Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / store / access / btree / BTreeController.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
new file mode 100644 (file)
index 0000000..8326f78
--- /dev/null
@@ -0,0 +1,1391 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.btree.BTreeController\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.access.btree;\r
+\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.RowLocationRetRowSource;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.FetchDescriptor;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;\r
+import org.apache.derby.impl.store.access.conglomerate.TemplateRow;\r
+\r
+/**\r
+\r
+  A b-tree controller corresponds to an instance of an open b-tree conglomerate.\r
+  <P>\r
+  <B>Concurrency Notes<\B>\r
+  <P>\r
+  The concurrency rules are derived from OpenBTree.\r
+  <P>\r
+  @see OpenBTree\r
+\r
+**/\r
+\r
+public class BTreeController extends OpenBTree implements ConglomerateController\r
+{\r
+\r
+    transient DataValueDescriptor[] scratch_template = null;\r
+\r
+    /**\r
+     * Whether to get lock on the row being inserted, usually this lock\r
+     * has already been gotten when the row was inserted into the base table.\r
+     **/\r
+    boolean get_insert_row_lock;\r
+\r
+    /* Constructors: */\r
+\r
+       public BTreeController()\r
+       {\r
+       }\r
+\r
+       /*\r
+       ** private Methods of BTreeController\r
+       */\r
+\r
+    /**\r
+     * Attempt to reclaim committed deleted rows from the page.\r
+     * <p>\r
+     * Get exclusive latch on page, and then loop backward through\r
+     * page searching for deleted rows which are committed.  The routine\r
+     * assumes that it is called from a transaction which cannot have \r
+     * deleted any rows on the page.  For each deleted row on the page\r
+     * it attempts to get an exclusive lock on the deleted row, NOWAIT.\r
+     * If it succeeds, and since this row did not delete the row then the\r
+     * row must have been deleted by a transaction which has committed, so\r
+     * it is safe to purge the row.  It then purges the row from the page.\r
+     * <p>\r
+     * Note that this routine may remove all rows from the page, it will not\r
+     * attempt a merge in this situation.  This is because this routine is\r
+     * called from split which is attempting an insert on the given page, so\r
+     * it would be a waste to merge the page only to split it again to allow\r
+     * the insert of the row causing the split.\r
+     *\r
+        * @return true if at least one row was purged.\r
+     *\r
+     * @param open_btree The already open btree to use to get latch on page.\r
+     * @param pageno     The page number of the leaf to attempt the reclaim on.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    private boolean reclaim_deleted_rows(\r
+    OpenBTree   open_btree,\r
+    long        pageno)\r
+               throws StandardException\r
+    {\r
+        boolean     purged_at_least_one_row = false;\r
+        ControlRow  controlRow              = null; \r
+\r
+        try\r
+        {\r
+\r
+            if ((controlRow = ControlRow.get(open_btree, pageno)) == null)\r
+                return(false);\r
+\r
+            LeafControlRow leaf       = (LeafControlRow) controlRow;\r
+\r
+            BTreeLockingPolicy  btree_locking_policy = \r
+                open_btree.getLockingPolicy();\r
+\r
+\r
+            // The number records that can be reclaimed is:\r
+            // total recs - control row - recs_not_deleted\r
+            int num_possible_commit_delete = \r
+                leaf.page.recordCount() - 1 - leaf.page.nonDeletedRecordCount();\r
+\r
+            if ((num_possible_commit_delete > 0) &&\r
+                (btree_locking_policy.lockScanForReclaimSpace(leaf)))\r
+            {\r
+                // Need to get an exclusive scan lock on the page before we can\r
+                // do any sort of purges, otherwise other concurrent scans would\r
+                // not work.  If we can't get the lock NOWAIT, just give up on\r
+                // purging rows and do the split without reclaiming rows.\r
+\r
+                Page page   = leaf.page;\r
+\r
+\r
+                // RowLocation column is in last column of template.\r
+                FetchDescriptor lock_fetch_desc = \r
+                    RowUtil.getFetchDescriptorConstant(\r
+                        scratch_template.length - 1);\r
+\r
+                // loop backward so that purges which affect the slot table \r
+                // don't affect the loop (ie. they only move records we \r
+                // have already looked at).\r
+                for (int slot_no = page.recordCount() - 1; \r
+                     slot_no > 0; \r
+                     slot_no--) \r
+                {\r
+                    if (page.isDeletedAtSlot(slot_no))\r
+                    {\r
+                        // try to get an exclusive lock on the row, if we can \r
+                        // then the row is a committed deleted row and it is \r
+                        // safe to purge it.\r
+                        if (btree_locking_policy.lockScanCommittedDeletedRow(\r
+                                open_btree, leaf, scratch_template, \r
+                                lock_fetch_desc, slot_no))\r
+                        {\r
+                            // the row is a committed deleted row, purge it.\r
+                            page.purgeAtSlot(slot_no, 1, true);\r
+\r
+                            purged_at_least_one_row = true;\r
+                        }\r
+                    }\r
+                }\r
+\r
+            }\r
+        }\r
+        catch (java.lang.ClassCastException cce)\r
+        {\r
+            // because we give up the latch on the leaf before entering this\r
+            // routine, the page might change from a leaf to branch.  If that\r
+            // happens this routine will get a ClassCastException, and we\r
+            // just give up trying to reclaim space.\r
+        }\r
+        finally\r
+        {\r
+            if (controlRow != null)\r
+                controlRow.release();\r
+\r
+            return(purged_at_least_one_row);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Start an internal transaction and do the split.\r
+     * <p>\r
+     * This routine starts a new transaction, and handles any errors that\r
+     * may come during the transaction.  This transation must not obtain any\r
+     * locks as they are likely to conflict with the current user transaction.\r
+     * <p>\r
+     * If attempt_to_reclaim_deleted_rows is true this routine will \r
+     * attempt to reclaim space on the leaf page input, by purging \r
+     * committed deleted rows from the leaf.  If it succeeds in purging at\r
+     * least one row, then it will commit the internal transaction and return\r
+     * without actually performing a split.  \r
+     *\r
+     * @param scratch_template  A scratch template used to search a page.\r
+     * @param rowToInsert       The row to insert, make sure during split to\r
+     *                          make room for this row.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    private long \r
+    start_xact_and_dosplit(\r
+    boolean                 attempt_to_reclaim_deleted_rows,\r
+    long                    leaf_pageno,\r
+    DataValueDescriptor[]   scratch_template, \r
+    DataValueDescriptor[]   rowToInsert,\r
+    int                     flag)\r
+        throws StandardException\r
+    {\r
+        TransactionManager split_xact       = null;\r
+        OpenBTree          split_open_btree = null;\r
+        ControlRow         root             = null;\r
+\r
+        // Get an internal transaction to be used for the split.\r
+        split_xact = this.init_open_user_scans.getInternalTransaction();\r
+\r
+        // open the btree again so that actions on it take place in the\r
+        // split_xact, don't get any locks in this transaction.\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+            if (((getOpenMode() & ContainerHandle.MODE_FORUPDATE) !=\r
+                                                                  ContainerHandle.MODE_FORUPDATE))\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "Container not opened with update should not cause split");\r
+            }\r
+               }\r
+\r
+\r
+        boolean do_split = true;\r
+        if (attempt_to_reclaim_deleted_rows)\r
+        {\r
+            // Get lock on base table.\r
+\r
+            ConglomerateController base_cc = null;\r
+\r
+            try\r
+            {\r
+                base_cc = \r
+                    this.getConglomerate().lockTable(\r
+                        split_xact, \r
+                        (ContainerHandle.MODE_FORUPDATE |\r
+                         ContainerHandle.MODE_LOCK_NOWAIT), \r
+                        TransactionController.MODE_RECORD,\r
+                        TransactionController.ISOLATION_REPEATABLE_READ);\r
+            }\r
+            catch (StandardException se)\r
+            {\r
+                // any error just don't try to reclaim deleted rows.  The\r
+                // expected error is that we can't get the lock, which the\r
+                // current interface throws as a containerNotFound exception.\r
+            }\r
+\r
+            if (base_cc != null)\r
+            {\r
+                // we got IX lock on the base table, so can try reclaim space.\r
+\r
+\r
+                // We can only reclaim space by opening the btree in row lock \r
+                // mode.  Table level lock row recovery is hard as we can't \r
+                // determine if the deleted rows we encounter have been \r
+                // deleted by our parent caller and have been committed or \r
+                // not.  We will have to get those rows offline.\r
+                split_open_btree = new OpenBTree();\r
+                split_open_btree.init(\r
+                    this.init_open_user_scans, \r
+                    split_xact, \r
+                    null,                           // open the container.\r
+                    split_xact.getRawStoreXact(), \r
+                    false,\r
+                    (ContainerHandle.MODE_FORUPDATE | \r
+                     ContainerHandle.MODE_LOCK_NOWAIT),\r
+                    TransactionManager.MODE_RECORD,\r
+                    this.getConglomerate().getBtreeLockingPolicy(\r
+                        split_xact.getRawStoreXact(), \r
+                        TransactionController.MODE_RECORD,\r
+                        LockingPolicy.MODE_RECORD,\r
+                        TransactionController.ISOLATION_REPEATABLE_READ, \r
+                        (ConglomerateController) base_cc, \r
+                        split_open_btree),\r
+                    this.getConglomerate(), \r
+                    (LogicalUndo) null,\r
+                    (DynamicCompiledOpenConglomInfo) null);\r
+\r
+                // don't split if we reclaim any rows.\r
+                do_split = !reclaim_deleted_rows(split_open_btree, leaf_pageno);\r
+\r
+                split_open_btree.close();\r
+            }\r
+        }\r
+\r
+        long new_leaf_pageno = leaf_pageno; \r
+        if (do_split)\r
+        {\r
+            split_open_btree = new OpenBTree();\r
+            split_open_btree.init(\r
+                this.init_open_user_scans, \r
+                split_xact, \r
+                null,                           // open the container.\r
+                split_xact.getRawStoreXact(), \r
+                false,\r
+                getOpenMode(),                  // use same mode this controller\r
+                                                // was opened with\r
+                TransactionManager.MODE_NONE,\r
+                this.getConglomerate().getBtreeLockingPolicy(\r
+                    split_xact.getRawStoreXact(), \r
+                    this.init_lock_level,\r
+                    LockingPolicy.MODE_RECORD,\r
+                    TransactionController.ISOLATION_REPEATABLE_READ, \r
+                    (ConglomerateController) null, // no base row locks during split\r
+                    split_open_btree),\r
+                this.getConglomerate(), \r
+                (LogicalUndo) null,\r
+                (DynamicCompiledOpenConglomInfo) null);\r
+\r
+\r
+            // Get the root page back, and perform a split following the\r
+            // to-be-inserted key.  The split releases the root page latch.\r
+            root = ControlRow.get(split_open_btree, BTree.ROOTPAGEID);\r
+\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(root.page.isLatched());\r
+\r
+            new_leaf_pageno = \r
+                root.splitFor(\r
+                    split_open_btree, scratch_template, \r
+                    null, rowToInsert, flag);\r
+\r
+            split_open_btree.close();\r
+        }\r
+\r
+        split_xact.commit();\r
+\r
+        split_xact.destroy();\r
+\r
+        return(new_leaf_pageno);\r
+    }\r
+\r
+       /**\r
+    Insert a row into the conglomerate.\r
+\r
+    @param rowToInsert The row to insert into the conglomerate.  The stored\r
+       representations of the row's columns are copied into a new row\r
+       somewhere in the conglomerate.\r
+\r
+       @return Returns 0 if insert succeeded.  Returns \r
+    ConglomerateController.ROWISDUPLICATE if conglomerate supports uniqueness\r
+    checks and has been created to disallow duplicates, and the row inserted\r
+    had key columns which were duplicate of a row already in the table.  Other\r
+    insert failures will raise StandardException's.\r
+\r
+       @exception StandardException Standard exception policy.\r
+    **/\r
+       private int doIns(DataValueDescriptor[] rowToInsert)\r
+        throws StandardException\r
+       {\r
+               LeafControlRow  targetleaf                      = null;\r
+               LeafControlRow  save_targetleaf                 = null;\r
+        int             insert_slot                     = 0;\r
+        int             result_slot                     = 0;\r
+        int             ret_val                         = 0;\r
+        boolean         reclaim_deleted_rows_attempted  = false;\r
+\r
+        if (scratch_template == null)\r
+        {\r
+            scratch_template = runtime_mem.get_template(getRawTran());\r
+        }\r
+\r
+        if (SanityManager.DEBUG)\r
+            this.isIndexableRowConsistent(rowToInsert);\r
+\r
+        // Create the objects needed for the insert.\r
+        // RESOLVE (mikem) - should we cache this in the controller?\r
+        SearchParameters sp = \r
+            new SearchParameters(\r
+                rowToInsert,\r
+                SearchParameters.POSITION_LEFT_OF_PARTIAL_KEY_MATCH,\r
+                scratch_template, this, false);\r
+\r
+        // RowLocation column is in last column of template.\r
+        FetchDescriptor lock_fetch_desc = \r
+            RowUtil.getFetchDescriptorConstant(\r
+                scratch_template.length - 1);\r
+        RowLocation lock_row_loc = \r
+            (RowLocation) scratch_template[scratch_template.length - 1];\r
+\r
+        // Row locking - lock the row being inserted.\r
+\r
+        if (get_insert_row_lock)\r
+        {\r
+            // I don't hold any latch yet so I can wait on this lock, so I\r
+            // don't care about return value from this call.  This\r
+            // lock can only wait if the base table row was inserted in a\r
+            // separate transaction which never happens in sql tables, but\r
+            // does happen in the sparse indexes that synchronization builds.\r
+        \r
+            this.getLockingPolicy().lockNonScanRow(\r
+                this.getConglomerate(),\r
+                (LeafControlRow) null,\r
+                (LeafControlRow) null,\r
+                rowToInsert, \r
+                (ConglomerateController.LOCK_INS | \r
+                 ConglomerateController.LOCK_UPD));\r
+        }\r
+\r
+        while (true)\r
+        {\r
+            // Search the location at which the new row should be inserted.\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(this.container != null);\r
+\r
+            targetleaf = (LeafControlRow)\r
+                ControlRow.get(this, BTree.ROOTPAGEID).search(sp);\r
+\r
+\r
+            // Row locking - first lock row previous to row being inserted:\r
+            //     o if (sp.resultExact) then the row must be deleted and\r
+            //           we will be replacing it with the new row, lock\r
+            //           the row before the slot as the previous key.\r
+            //     o else \r
+            //           we will be inserting after the current slot so\r
+            //           lock the current slot as the previous key.\r
+            //\r
+            int slot_after_previous = \r
+                (sp.resultExact ? sp.resultSlot : sp.resultSlot + 1);\r
+\r
+            boolean latch_released = false;\r
+\r
+            latch_released = \r
+                !this.getLockingPolicy().lockNonScanPreviousRow(\r
+                    this.getConglomerate(),\r
+                    targetleaf, \r
+                    slot_after_previous, \r
+                    lock_fetch_desc,\r
+                    scratch_template,\r
+                    lock_row_loc,\r
+                    this, \r
+                    (ConglomerateController.LOCK_INS_PREVKEY |\r
+                     ConglomerateController.LOCK_UPD),\r
+                    TransactionManager.LOCK_INSTANT_DURATION);\r
+\r
+            // special test to see if latch release code works\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                latch_released = \r
+                    test_errors(\r
+                        this,\r
+                        "BTreeController_doIns", false,\r
+                        this.getLockingPolicy(), \r
+                        targetleaf, latch_released);\r
+            }\r
+\r
+            if (latch_released)\r
+            {\r
+                // Had to release latch in order to get the lock, probably \r
+                // because of a forward scanner, research tree, and try again.\r
+                targetleaf = null;\r
+                continue;\r
+            }\r
+\r
+            // If the row is there already, simply undelete it.\r
+            // The rationale for this is, since the index does\r
+            // not support duplicates, the only way we could\r
+            // find a duplicate is if we found a deleted row.\r
+            // If we could lock it, then no other transaction\r
+            // is deleting it; either this transaction deleted\r
+            // it earlier, or it's simply a row that the space\r
+            // reclaimer hasn't reclaimed yet.\r
+            // Since inserts are done directly (i.e., not to a\r
+            // location provided by a scan, we will see the \r
+            // deleted row).\r
+            if (sp.resultExact)\r
+            {\r
+                result_slot = insert_slot = sp.resultSlot;\r
+\r
+                if (this.getConglomerate().nKeyFields != \r
+                        this.getConglomerate().nUniqueColumns)\r
+                {\r
+                    // The key fields match, but not the row location.  We\r
+                    // must wait on the lock on the other row location before\r
+                    // preceding, so as to serialize behind any work being done\r
+                    // to the row as part of another transaction.\r
+\r
+                    latch_released = \r
+                        !this.getLockingPolicy().lockNonScanRowOnPage(\r
+                            this.getConglomerate(), targetleaf, insert_slot, \r
+                            lock_fetch_desc, scratch_template, lock_row_loc,\r
+                            ConglomerateController.LOCK_UPD);\r
+\r
+                    if (latch_released)\r
+                    {\r
+                        // Had to release latch in order to get the lock, \r
+                        // probably to wait for deleting xact to commit or \r
+                        // abort.  Research tree, and try again.\r
+                        targetleaf = null;\r
+                        continue;\r
+                    }\r
+                }\r
+\r
+                // The row better be deleted, or something is very wrong.\r
+\r
+                if (!(targetleaf.page.isDeletedAtSlot(insert_slot)))\r
+                {\r
+                    // attempt to insert a duplicate into the index.\r
+                    ret_val = ConglomerateController.ROWISDUPLICATE;\r
+                    break;\r
+                }\r
+                else\r
+                {\r
+                    if (this.getConglomerate().nKeyFields == \r
+                        this.getConglomerate().nUniqueColumns)\r
+                    {\r
+                        // The row that we found deleted is exactly the new row.\r
+                        targetleaf.page.deleteAtSlot(\r
+                            insert_slot, false, this.btree_undo);\r
+\r
+                        break;\r
+                    }\r
+                    else if (this.getConglomerate().nUniqueColumns == \r
+                             (this.getConglomerate().nKeyFields - 1))\r
+                    {\r
+                        // The row that we found deleted has matching keys\r
+                        // which form the unique key fields,\r
+                        // but the nonkey fields may differ (for now the\r
+                        // heap rowlocation is the only nonkey field \r
+                        // allowed).\r
+                        \r
+                        // RESOLVE BT39 (mikem) - when/if heap row location\r
+                        // is not fixed we must handle update failing for\r
+                        // out of space and split if it does.  For now\r
+                        // if the update fails because of lack of space\r
+                        // an exception is thrown and the statement is \r
+                        // backed out.  Should not happen very often.\r
+                        targetleaf.page.deleteAtSlot(\r
+                            insert_slot, false, this.btree_undo);\r
+\r
+                        boolean update_succeeded = true;\r
+\r
+                        try \r
+                        {\r
+                            int rowloc_index = \r
+                                this.getConglomerate().nKeyFields - 1;\r
+                            targetleaf.page.updateFieldAtSlot(\r
+                                insert_slot, rowloc_index, \r
+                                (DataValueDescriptor) RowUtil.getColumn(\r
+                                    rowToInsert, \r
+                                    (FormatableBitSet) null, rowloc_index),\r
+                                this.btree_undo);\r
+                        }\r
+                        catch (StandardException se)\r
+                        {\r
+                            // check if the exception is for out of space\r
+                            if (!se.getMessageId().equals(SQLState.DATA_NO_SPACE_FOR_RECORD))\r
+                            {\r
+                                throw se;\r
+                            }\r
+\r
+                            // The statement exception is\r
+                            // because the update failed for out of\r
+                            // space (ie. the field got longer and there\r
+                            // is no room on the page for the expanded\r
+                            // field).  Address this error by falling\r
+                            // through the code and doing a split.\r
+                            update_succeeded = false;                          // update failed.\r
+                            targetleaf.page.deleteAtSlot(\r
+                                insert_slot, true, this.btree_undo);\r
+                        }\r
+\r
+                        if (update_succeeded)\r
+                            break;\r
+                    }\r
+                    else\r
+                    {\r
+                        // Can only happen with non key fields in the btree.\r
+                        throw(\r
+                            StandardException.newException(\r
+                                SQLState.BTREE_UNIMPLEMENTED_FEATURE));\r
+                    }\r
+                }\r
+            }\r
+            else if (targetleaf.page.recordCount() - 1 < \r
+                    this.getConglomerate().maxRowsPerPage)\r
+            {\r
+                // The row wasn't there, so try to insert it\r
+                // on the page returned by the search.\r
+                insert_slot = sp.resultSlot + 1;\r
+                result_slot = insert_slot + 1;\r
+\r
+                // By default maxRowsPerPage is set to MAXINT, some tests\r
+                // set it small to cause splitting to happen quicker with\r
+                // less data.\r
+\r
+                if (targetleaf.page.insertAtSlot(\r
+                        insert_slot, \r
+                        rowToInsert, (FormatableBitSet) null,\r
+                        this.btree_undo,\r
+                        Page.INSERT_DEFAULT,\r
+                                               AccessFactoryGlobals.BTREE_OVERFLOW_THRESHOLD) != null)\r
+                {\r
+                    // Insert succeeded, so we're done.\r
+\r
+                    break;\r
+                }\r
+\r
+                // RESOLVE (mikem) - another long row issue.\r
+                // For now if a row does not fit on a page and there \r
+                // is only the control row on the page and at most one\r
+                // other row on the page, throw an exception\r
+\r
+                if (targetleaf.page.recordCount() <= 2)\r
+                {\r
+                    throw StandardException.newException(\r
+                            SQLState.BTREE_NO_SPACE_FOR_KEY);\r
+                }\r
+\r
+                // start splitting ...\r
+            }\r
+\r
+            \r
+            // Create some space by splitting pages.\r
+\r
+            // determine where in page/table row causing split would go\r
+            int flag = 0;\r
+            if (insert_slot == 1)\r
+            {\r
+                flag |= ControlRow.SPLIT_FLAG_FIRST_ON_PAGE;\r
+                if (targetleaf.isLeftmostLeaf())\r
+                    flag |= ControlRow.SPLIT_FLAG_FIRST_IN_TABLE;\r
+            }\r
+            else if (insert_slot == targetleaf.page.recordCount())\r
+            {\r
+                flag |= ControlRow.SPLIT_FLAG_LAST_ON_PAGE;\r
+                if (targetleaf.isRightmostLeaf())\r
+                    flag |= ControlRow.SPLIT_FLAG_LAST_IN_TABLE;\r
+            }\r
+\r
+            long targetleaf_pageno = targetleaf.page.getPageNumber();\r
+\r
+            if ((targetleaf.page.recordCount() - \r
+                 targetleaf.page.nonDeletedRecordCount()) <= 0)\r
+            {\r
+                // Don't do reclaim work if there are no deleted records.\r
+                reclaim_deleted_rows_attempted = true;\r
+            }\r
+\r
+            BranchRow branchrow = \r
+                BranchRow.createBranchRowFromOldLeafRow(\r
+                    rowToInsert, targetleaf_pageno);\r
+\r
+            // Release the target page because (a) it may change as a \r
+            // result of the split, (b) the latch ordering requires us \r
+            // to acquire latches from top to bottom, and (c) this \r
+            // loop should be done in a system transaction.\r
+            targetleaf.release();\r
+            targetleaf = null;\r
+\r
+            start_xact_and_dosplit(\r
+                !reclaim_deleted_rows_attempted, targetleaf_pageno, \r
+                scratch_template, branchrow.getRow(), flag);\r
+\r
+            // only attempt to reclaim deleted rows once, otherwise the\r
+            // split loop could loop forever, trying to reclaim a deleted\r
+            // row that was not committed.\r
+            reclaim_deleted_rows_attempted = true;\r
+\r
+            // RESOLVE (mikem) possible optimization could be to save\r
+            // split location and look there first, if this has \r
+            // already caused a split.  Or even return a latched page\r
+            // from splitFor().  For now just execute the loop again\r
+            // searching the tree for somewhere to put the row.\r
+        }\r
+\r
+        // set in-memory hint of where last row on page was inserted.\r
+        targetleaf.last_search_result = result_slot;\r
+\r
+        // Check that page just updated is consistent.\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (SanityManager.DEBUG_ON("enableBtreeConsistencyCheck"))\r
+            {\r
+                targetleaf.checkConsistency(this, null, true);\r
+            }\r
+        }\r
+\r
+        // Done with the target page.\r
+        targetleaf.release();\r
+        targetleaf = null;\r
+\r
+        // return the status about insert - 0 is ok, or duplicate status.\r
+        return(ret_val);\r
+       }\r
+\r
+    /**\r
+     * Just insert the row on the current page/slot if it fits.\r
+     * <p>\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       private boolean do_load_insert(\r
+    DataValueDescriptor[]   rowToInsert,\r
+    LeafControlRow          leaf,\r
+    int                     insert_slot)\r
+        throws StandardException\r
+       {\r
+               LeafControlRow old_leaf         = null;\r
+        boolean        row_inserted     = false;\r
+        int            num_rows_on_page = leaf.page.recordCount() - 1;\r
+\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(insert_slot == leaf.page.recordCount());\r
+            SanityManager.ASSERT(\r
+                leaf.getrightSiblingPageNumber() == \r
+                    ContainerHandle.INVALID_PAGE_NUMBER);\r
+            this.isIndexableRowConsistent(rowToInsert);\r
+        }\r
+\r
+        if (num_rows_on_page < this.getConglomerate().maxRowsPerPage)\r
+        {\r
+            // By default maxRowsPerPage is set to MAXINT, some tests\r
+            // set it small to cause splitting to happen quicker with\r
+            // less data.\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                // Caller should have sorted and done duplicate checking.\r
+\r
+                if (insert_slot > 1)\r
+                {\r
+                    // verify that the row inserted is >= than previous row.\r
+                    int compare_result =\r
+                        ControlRow.compareIndexRowFromPageToKey(\r
+                            leaf,\r
+                            insert_slot - 1,\r
+                            scratch_template,\r
+                            rowToInsert,\r
+                            this.getConglomerate().nUniqueColumns,\r
+                            0,\r
+                                                       this.getConglomerate().ascDescInfo);\r
+                    \r
+                    if (compare_result >= 0)\r
+                    {\r
+                        // Rows must be presented in order, so the row we are\r
+                        // inserting must always be greater than the previous \r
+                        // row on the page.\r
+                        SanityManager.THROWASSERT("result = " + compare_result);\r
+                    }\r
+                }\r
+            }\r
+\r
+\r
+            if (leaf.page.insertAtSlot(\r
+                    insert_slot, \r
+                    rowToInsert, \r
+                    (FormatableBitSet) null, \r
+                    this.btree_undo,\r
+                    Page.INSERT_DEFAULT,\r
+                                       AccessFactoryGlobals.BTREE_OVERFLOW_THRESHOLD) != null)\r
+            {\r
+                // Insert succeeded, so we're done.\r
+                row_inserted = true;\r
+            }\r
+            else\r
+            {\r
+                // RESOLVE (mikem) - another long row issue.\r
+                // For now if a row does not fit on a page and there \r
+                // is only the control row on the page and at most one\r
+                // other row on the page, throw an exception\r
+\r
+                if (leaf.page.recordCount() <= 2)\r
+                {\r
+                    throw StandardException.newException(\r
+                            SQLState.BTREE_NO_SPACE_FOR_KEY);\r
+                }\r
+            }\r
+        }\r
+\r
+        // Check that page just updated is consistent.\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (SanityManager.DEBUG_ON("enableBtreeConsistencyCheck"))\r
+            {\r
+                leaf.checkConsistency(this, null, true);\r
+            }\r
+        }\r
+\r
+        return(row_inserted);\r
+       }\r
+\r
+    /**\r
+     * Create room to insert a row to the right of the largest key in table.\r
+     * <p>\r
+     * Perform a split pass on the tree which will move the largest key in\r
+     * leaf right to a new leaf, splitting parent branch pages as necessary.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       private LeafControlRow do_load_split(\r
+    DataValueDescriptor[]   rowToInsert,\r
+    LeafControlRow          leaf)\r
+        throws StandardException\r
+       {\r
+               LeafControlRow new_leaf = null;\r
+\r
+        BranchRow branchrow = \r
+            BranchRow.createBranchRowFromOldLeafRow(\r
+                rowToInsert, leaf.page.getPageNumber());\r
+\r
+        // Release the target page because (a) it may change as a \r
+        // result of the split, (b) the latch ordering requires us \r
+        // to acquire latches from top to bottom, and (c) this \r
+        // loop should be done in a system transaction.\r
+        long old_leafpage = leaf.page.getPageNumber();\r
+\r
+        leaf.release();\r
+        leaf = null;\r
+        \r
+        long new_leaf_pageno = \r
+            start_xact_and_dosplit(\r
+                false /* don't try to reclaim deleted rows */,\r
+                old_leafpage,\r
+                scratch_template, \r
+                branchrow.getRow(), \r
+                (ControlRow.SPLIT_FLAG_LAST_ON_PAGE | \r
+                    ControlRow.SPLIT_FLAG_LAST_IN_TABLE));\r
+\r
+        new_leaf = (LeafControlRow) ControlRow.get(this, new_leaf_pageno);\r
+\r
+        // The leaf must be the rightmost leaf in the table, the first time\r
+        // the root grows from leaf to branch it will be a leaf with many\r
+        // rows which will probably have to be split soon, after that it will\r
+        // be a leaf with only one row.  The current algorithm requires that\r
+        // there be at least one row for duplicate checking (the duplicate\r
+        // checking code does not handle going left to the previous leaf) - \r
+        // this is the way the split at rightmost leaf row works currently.\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (new_leaf.getrightSiblingPageNumber() != \r
+                    ContainerHandle.INVALID_PAGE_NUMBER)\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "new_leaf.getrightSiblingPageNumber() = " + \r
+                        new_leaf.getrightSiblingPageNumber());\r
+            }\r
+            if (new_leaf.page.recordCount() <= 1)\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "new_leaf.page.recordCount() = " + \r
+                    new_leaf.page.recordCount());\r
+            }\r
+        }\r
+\r
+        return(new_leaf);\r
+       }\r
+\r
+\r
+\r
+       /*\r
+       ** public Methods of BTreeController\r
+       */\r
+\r
+       /**\r
+       Initialize the controller for use.\r
+       <p>\r
+       Any changes to this method will probably have to be reflected in close as \r
+    well.\r
+       <p>\r
+       Currently delegates to OpenBTree.  If the btree controller ends up not \r
+    having any state of its own, we can remove this method (the VM will \r
+    dispatch to OpenBTree), gaining some small efficiency.  For now, this \r
+    method remains for clarity.  \r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public void init(\r
+    TransactionManager              xact_manager,\r
+    boolean                         hold,\r
+    ContainerHandle                 container,\r
+    Transaction                     rawtran, \r
+       int                                                 open_mode,\r
+    int                             lock_level,\r
+    BTreeLockingPolicy              btree_locking_policy,\r
+    BTree                           conglomerate,\r
+    LogicalUndo                     undo,\r
+    StaticCompiledOpenConglomInfo   static_info,\r
+    DynamicCompiledOpenConglomInfo  dynamic_info)\r
+               throws StandardException\r
+       {\r
+        get_insert_row_lock = \r
+            ((open_mode & \r
+              TransactionController.OPENMODE_BASEROW_INSERT_LOCKED) == 0);\r
+\r
+               super.init(\r
+            xact_manager, xact_manager, \r
+            container, rawtran, hold, open_mode,\r
+            lock_level, btree_locking_policy,\r
+            conglomerate, undo, dynamic_info);\r
+       }\r
+\r
+       /*\r
+       ** Methods of ConglomerateController\r
+       */\r
+\r
+    /**\r
+    Close the conglomerate controller.\r
+       <p>\r
+       Any changes to this method will probably have to be reflected in close as \r
+    well.\r
+       <p>\r
+       Currently delegates to OpenBTree.  If the btree controller ends up not \r
+    having any state of its own, we can remove this method (the VM will \r
+    dispatch to OpenBTree), gaining some small efficiency.  For now, this \r
+    method remains for clarity.  \r
+\r
+       @see ConglomerateController#close\r
+    **/\r
+    public void close()\r
+        throws StandardException\r
+       {\r
+               super.close();\r
+\r
+               // If we are closed due to catching an error in the middle of init,\r
+               // xact_manager may not be set yet. \r
+               if (getXactMgr() != null)\r
+                       getXactMgr().closeMe(this);\r
+       }\r
+\r
+    /**\r
+     * Close conglomerate controller as part of terminating a transaction.\r
+     * <p>\r
+     * Use this call to close the conglomerate controller resources as part of\r
+     * committing or aborting a transaction.  The normal close() routine may \r
+     * do some cleanup that is either unnecessary, or not correct due to the \r
+     * unknown condition of the controller following a transaction ending error.\r
+     * Use this call when closing all controllers as part of an abort of a \r
+     * transaction.\r
+     * <p)\r
+     * This call is meant to only be used internally by the Storage system,\r
+     * clients of the storage system should use the simple close() interface.\r
+     * <p>\r
+     * RESOLVE (mikem) - move this call to ConglomerateManager so it is\r
+     * obvious that non-access clients should not call this.\r
+     *\r
+     * @param closeHeldScan     If true, means to close controller even if\r
+     *                          it has been opened to be kept opened \r
+     *                          across commit.  This is\r
+     *                          used to close these controllers on abort.\r
+     *\r
+        * @return boolean indicating that the close has resulted in a real close\r
+     *                 of the controller.  A held scan will return false if \r
+     *                 called by closeForEndTransaction(false), otherwise it \r
+     *                 will return true.  A non-held scan will always return \r
+     *                 true.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public boolean closeForEndTransaction(boolean closeHeldScan)\r
+               throws StandardException\r
+    {\r
+        super.close();\r
+\r
+        if ((!getHold()) || closeHeldScan) \r
+        {\r
+            // If we are closed due to catching an error in the middle of init,\r
+            // xact_manager may not be set yet. \r
+            if (getXactMgr() != null)\r
+                getXactMgr().closeMe(this);\r
+\r
+            return(true);\r
+        }\r
+        else\r
+        {\r
+            return(false);\r
+        }\r
+    }\r
+\r
+       /**\r
+    Insert a row into the conglomerate.\r
+       @see ConglomerateController#insert\r
+\r
+    @param row The row to insert into the conglomerate.  The stored\r
+       representations of the row's columns are copied into a new row\r
+       somewhere in the conglomerate.\r
+\r
+       @return Returns 0 if insert succeeded.  Returns \r
+    ConglomerateController.ROWISDUPLICATE if conglomerate supports uniqueness\r
+    checks and has been created to disallow duplicates, and the row inserted\r
+    had key columns which were duplicate of a row already in the table.  Other\r
+    insert failures will raise StandardException's.\r
+\r
+       @exception StandardException Standard exception policy.\r
+    **/\r
+       public int insert(DataValueDescriptor[] row) \r
+         throws StandardException\r
+    {\r
+\r
+               if (isClosed())\r
+        {\r
+            if (getHold())\r
+            {\r
+                reopen();\r
+            }\r
+            else\r
+            {\r
+                throw StandardException.newException(\r
+                            SQLState.BTREE_IS_CLOSED,\r
+                            new Long(err_containerid));\r
+            } \r
+        }\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(this.container != null);\r
+\r
+            TemplateRow.checkPartialColumnTypes(\r
+                this.getConglomerate().format_ids, \r
+                (FormatableBitSet) null, (int []) null, row);\r
+        }\r
+\r
+               return doIns(row);\r
+       }\r
+\r
+    /**\r
+       Return whether this is a keyed conglomerate.\r
+       <p>\r
+       All b-trees are keyed.\r
+       @see ConglomerateController#isKeyed\r
+       **/\r
+       public boolean isKeyed()\r
+       {\r
+               return(true);\r
+       }\r
+\r
+    /*\r
+     * Request the system properties associated with a table. \r
+     * <p>\r
+     * Request the value of properties that are associated with a table.  The\r
+     * following properties can be requested:\r
+     *     derby.storage.pageSize \r
+     *     derby.storage.pageReservedSpace\r
+     *     derby.storage.minimumRecordSize\r
+     *     derby.storage.initialPages\r
+     * <p>\r
+     * To get the value of a particular property add it to the property list,\r
+     * and on return the value of the property will be set to it's current \r
+     * value.  For example:\r
+     *\r
+     * get_prop(ConglomerateController cc)\r
+     * {\r
+     *     Properties prop = new Properties();\r
+     *     prop.put("derby.storage.pageSize", "");\r
+     *     cc.getTableProperties(prop);\r
+     *\r
+     *     System.out.println(\r
+     *         "table's page size = " + \r
+     *         prop.getProperty("derby.storage.pageSize");\r
+     * }\r
+     *\r
+     * @param prop   Property list to fill in.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public void getTableProperties(Properties prop)\r
+               throws StandardException\r
+    {\r
+               if (this.container == null)\r
+        {\r
+            throw StandardException.newException(\r
+                        SQLState.BTREE_IS_CLOSED,\r
+                        new Long(err_containerid));\r
+        }\r
+\r
+        container.getContainerProperties(prop);\r
+\r
+        return;\r
+    }\r
+\r
+    /**\r
+     * Request set of properties associated with a table. \r
+     * <p>\r
+     * Returns a property object containing all properties that the store\r
+     * knows about, which are stored persistently by the store.  This set\r
+     * of properties may vary from implementation to implementation of the\r
+     * store.\r
+     * <p>\r
+     * This call is meant to be used only for internal query of the properties\r
+     * by jbms, for instance by language during bulk insert so that it can\r
+     * create a new conglomerate which exactly matches the properties that\r
+     * the original container was created with.  This call should not be used\r
+     * by the user interface to present properties to users as it may contain\r
+     * properties that are meant to be internal to jbms.  Some properties are \r
+     * meant only to be specified by jbms code and not by users on the command\r
+     * line.\r
+     * <p>\r
+     * Note that not all properties passed into createConglomerate() are stored\r
+     * persistently, and that set may vary by store implementation.\r
+     *\r
+     * @param prop   Property list to add properties to.  If null, routine will\r
+     *               create a new Properties object, fill it in and return it.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public Properties getInternalTablePropertySet(Properties prop)\r
+               throws StandardException\r
+    {\r
+        Properties  ret_properties = \r
+            ConglomerateUtil.createRawStorePropertySet(prop);\r
+\r
+        getTableProperties(ret_properties);\r
+\r
+        return(ret_properties);\r
+    }\r
+\r
+    /**\r
+     * Load rows from rowSource into the opened btree.\r
+     * <p>\r
+     * Efficiently load rows into the already opened btree.  The btree must\r
+     * be table locked, as no row locks will be requested by this routine.  \r
+     * On exit from this routine the conglomerate will be closed (on both\r
+     * error or success).\r
+     * <p>\r
+     * This routine does an almost bottom up build of a btree.  It assumes\r
+     * all rows arrive in sorted order, and inserts them directly into the\r
+     * next (to the right) spot in the current leaf until there is no space.\r
+     * Then it calls the generic split code to add the next leaf (RESOLVE - \r
+     * in the future we could optimize this to split bottom up rather than\r
+     * top down for create index).\r
+     *\r
+     * @exception StandardException Standard exception policy.  If conglomerate\r
+        *                              supports uniqueness checks and has been \r
+     *                              created to disallow duplicates, and one of \r
+     *                              the rows being loaded had key columns which\r
+     *                              were duplicate of a row already in the \r
+     *                              conglomerate, then raise \r
+     *                              SQLState.STORE_CONGLOMERATE_DUPLICATE_KEY_EXCEPTION.\r
+     *\r
+        * @see org.apache.derby.iapi.store.access.conglomerate.Conglomerate#load\r
+     **/\r
+       public long load(\r
+    TransactionManager      xact_manager,\r
+    boolean                 createConglom,\r
+    RowLocationRetRowSource rowSource)\r
+                throws StandardException\r
+       {\r
+        long num_rows_loaded = 0;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(createConglom,\r
+                               "Cannot load a btree incrementally - it must either be entirely logged, or entirely not logged.  Doesn't make sense to log only the allocation when one cannot guarantee to not touch any pre-existing pages");\r
+               }\r
+\r
+        if (scratch_template == null)\r
+        {\r
+            scratch_template = runtime_mem.get_template(getRawTran());\r
+        }\r
+\r
+        LeafControlRow current_leaf = null;\r
+\r
+        try \r
+        {\r
+            // Btree must just have been created and empty, so there must\r
+            // be one root leaf page which is empty except for the control row.\r
+            current_leaf = \r
+                (LeafControlRow) ControlRow.get(this, BTree.ROOTPAGEID);\r
+            int current_insert_slot = 1;\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                // root must be empty except for the control row.\r
+                SanityManager.ASSERT(current_leaf.page.recordCount() == 1);\r
+            }\r
+           \r
+            // now loop thru the row source and insert into the btree\r
+            FormatableBitSet  validColumns = rowSource.getValidColumns();\r
+            \r
+                       // get the next row and its valid columns from the rowSource\r
+                       DataValueDescriptor[] row;\r
+            while ((row = rowSource.getNextRowFromRowSource()) != null)\r
+            {\r
+                num_rows_loaded++;\r
+\r
+                if (SanityManager.DEBUG)\r
+                {\r
+                    SanityManager.ASSERT(\r
+                        validColumns == null, "Does not support partial row");\r
+                }\r
+\r
+                while (true)\r
+                {\r
+                    if (do_load_insert(row, current_leaf, current_insert_slot))\r
+                    {\r
+                        // row inserted successfully.\r
+                        break;\r
+                    }\r
+                    else\r
+                    {\r
+                        // if insert fails, do a split pass. There is an edge\r
+                        // case where multiple split passes are necessary if\r
+                        // branch splits are necessary, thus the loop.  It is\r
+                        // most likely that only a single split pass will be\r
+                        // necessary.\r
+                        current_leaf = do_load_split(row, current_leaf);\r
+\r
+                        current_insert_slot = current_leaf.page.recordCount();\r
+                    }\r
+                }\r
+                current_insert_slot++;\r
+            }\r
+\r
+            current_leaf.release();\r
+            current_leaf = null;\r
+\r
+            // Loading done, must flush all pages to disk since it is unlogged.\r
+            if (!this.getConglomerate().isTemporary())\r
+                container.flushContainer();\r
+        }\r
+        finally\r
+        {\r
+            this.close();\r
+        }\r
+\r
+        return(num_rows_loaded);\r
+       }\r
+\r
+       /*\r
+       ** Methods of ConglomerateController which are not supported.\r
+       */\r
+\r
+    /**\r
+    Delete a row from the conglomerate.  \r
+       @see ConglomerateController#delete\r
+\r
+    @exception StandardException Standard exception policy.\r
+    **/\r
+    public boolean delete(RowLocation loc)\r
+               throws StandardException\r
+       {\r
+        throw(StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE));\r
+       }\r
+\r
+    /**\r
+    Fetch the row at the given location.\r
+       @see ConglomerateController#fetch\r
+\r
+    @exception StandardException Standard exception policy.\r
+    **/\r
+    public boolean fetch(\r
+    RowLocation loc, \r
+    DataValueDescriptor[]   row, \r
+    FormatableBitSet                 validColumns) \r
+               throws StandardException\r
+       {\r
+        throw(StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE));\r
+       }\r
+\r
+    /**\r
+    Fetch the row at the given location.\r
+       @see ConglomerateController#fetch\r
+\r
+    @exception StandardException Standard exception policy.\r
+    **/\r
+    public boolean fetch(\r
+    RowLocation             loc, \r
+    DataValueDescriptor[]   row, \r
+    FormatableBitSet                 validColumns,\r
+    boolean                 waitForLock) \r
+               throws StandardException\r
+       {\r
+        throw(StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE));\r
+       }\r
+\r
+       /**\r
+       Insert a row into the conglomerate, and store its location in the\r
+       provided template row location.\r
+\r
+    Unimplemented by btree.\r
+\r
+       @see ConglomerateController#insertAndFetchLocation\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public void insertAndFetchLocation(\r
+    DataValueDescriptor[]      row,\r
+    RowLocation             templateRowLocation)\r
+        throws StandardException\r
+       {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+       }\r
+\r
+       /**\r
+       Return a row location object of the correct type to be\r
+       used in calls to insertAndFetchLocation.\r
+\r
+       @see ConglomerateController#newRowLocationTemplate\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public RowLocation newRowLocationTemplate()\r
+               throws StandardException\r
+       {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+       }\r
+\r
+    /**\r
+     * Lock the given row location.\r
+     * <p>\r
+     * Should only be called by access.\r
+     * <p>\r
+     * This call can be made on a ConglomerateController that was opened\r
+     * for locking only.\r
+     * <p>\r
+     * RESOLVE (mikem) - move this call to ConglomerateManager so it is\r
+     * obvious that non-access clients should not call this.\r
+     *\r
+        * @return true if lock was granted, only can be false if wait was false.\r
+     *\r
+        * @param loc    The "RowLocation" which describes the exact row to lock.\r
+     * @param wait   Should the lock call wait to be granted?\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public boolean lockRow(\r
+    RowLocation loc,\r
+    int         lock_operation,\r
+    boolean     wait,\r
+    int         lock_duration)\r
+        throws StandardException\r
+    {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+    }\r
+\r
+    public boolean lockRow(\r
+    long        page_num,\r
+    int         record_id,\r
+    int         lock_operation,\r
+    boolean     wait,\r
+    int         lock_duration)\r
+        throws StandardException\r
+    {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+    }\r
+\r
+    public void unlockRowAfterRead(\r
+    RowLocation     loc,\r
+    boolean         forUpdate,\r
+    boolean         row_qualifies)\r
+        throws StandardException\r
+    {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+    }\r
+\r
+       /**\r
+    Replace the entire row at the given location.  \r
+       @see ConglomerateController#replace\r
+\r
+    @exception StandardException Standard exception policy.\r
+    **/\r
+    public boolean replace(\r
+    RowLocation             loc, \r
+    DataValueDescriptor[]   row, \r
+    FormatableBitSet                 validColumns)\r
+               throws StandardException\r
+       {\r
+        throw StandardException.newException(\r
+                SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+       }\r
+}\r