--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.btree.index.B2I\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.index;\r
+\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+import java.io.IOException;\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.io.ArrayInputStream;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;\r
+import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;\r
+import org.apache.derby.iapi.store.access.conglomerate.ScanManager;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+\r
+import org.apache.derby.iapi.store.access.ColumnOrdering;\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.Qualifier;\r
+import org.apache.derby.iapi.store.access.RowLocationRetRowSource;\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.StoreCostController;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+\r
+import org.apache.derby.impl.store.access.btree.BTree;\r
+import org.apache.derby.impl.store.access.btree.BTreeLockingPolicy;\r
+import org.apache.derby.impl.store.access.btree.LeafControlRow;\r
+import org.apache.derby.impl.store.access.btree.OpenBTree;\r
+\r
+import org.apache.derby.iapi.services.cache.ClassSize;\r
+\r
+import org.apache.derby.iapi.services.io.CompressedNumber;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+\r
+\r
+// For JavaDoc references (i.e. @see)\r
+import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;\r
+\r
+\r
+/*\r
+ * @format_id ACCESS_B2I_V3_ID\r
+ *\r
+ * @purpose The tag that describes the on disk representation of the B2I\r
+ * conglomerate object. Access contains no "directory" of \r
+ * conglomerate information. In order to bootstrap opening a file\r
+ * it encodes the factory that can open the conglomerate in the \r
+ * conglomerate id itself. There exists a single B2IFactory which\r
+ * must be able to read all btree format id's. \r
+ *\r
+ * This format was used for all Derby database B2I's in version\r
+ * 10.2 and previous versions.\r
+ *\r
+ * @upgrade The format id of this object is currently always read from disk\r
+ * as the first field of the conglomerate itself. A bootstrap\r
+ * problem exists as we don't know the format id of the B2I \r
+ * until we are in the "middle" of reading the B2I. Thus the\r
+ * base B2I implementation must be able to read and write \r
+ * all formats based on the reading the \r
+ * "format_of_this_conglomerate". \r
+ *\r
+ * soft upgrade to ACCESS_B2I_V4_ID:\r
+ * read:\r
+ * old format is readable by current B2I implementation,\r
+ * with automatic in memory creation of default collation\r
+ * id needed by new format. No code other than\r
+ * readExternal and writeExternal need know about old format.\r
+ * write:\r
+ * will never write out new format id in soft upgrade mode.\r
+ * Code in readExternal and writeExternal handles writing\r
+ * correct version. Code in the factory handles making\r
+ * sure new conglomerates use the B2I_v10_2 class to \r
+ * that will write out old format info.\r
+ *\r
+ * hard upgrade to ACCESS_B2I_V4_ID:\r
+ * read:\r
+ * old format is readable by current B2I implementation,\r
+ * with automatic in memory creation of default collation\r
+ * id needed by new format.\r
+ * write:\r
+ * Only "lazy" upgrade will happen. New format will only\r
+ * get written for new conglomerate created after the \r
+ * upgrade. Old conglomerates continue to be handled the\r
+ * same as soft upgrade.\r
+ *\r
+ * @disk_layout \r
+ * format_of_this_conlgomerate(byte[])\r
+ * containerid(long)\r
+ * segmentid(int)\r
+ * number_of_key_fields(int)\r
+ * number_of_unique_columns(int)\r
+ * allow_duplicates(boolean)\r
+ * maintain_parent_links(boolean)\r
+ * array_of_format_ids(byte[][])\r
+ * baseConglomerateId(long)\r
+ * rowLocationColumn(int)\r
+ * ascend_column_info(FormatableBitSet)\r
+ *\r
+ */\r
+\r
+/*\r
+ * @format_id ACCESS_B2I_V4_ID\r
+ *\r
+ * @purpose The tag that describes the on disk representation of the B2I\r
+ * conglomerate object. Access contains no "directory" of \r
+ * conglomerate information. In order to bootstrap opening a file\r
+ * it encodes the factory that can open the conglomerate in the \r
+ * conglomerate id itself. There exists a single B2IFactory which\r
+ * must be able to read all btree format id's. \r
+ *\r
+ * This format is the current version id of B2I and has been used \r
+ * in versions of Derby after the 10.2 release.\r
+ *\r
+ * @upgrade This is the current version, no upgrade necessary.\r
+ *\r
+ * @disk_layout \r
+ * format_of_this_conlgomerate(byte[])\r
+ * containerid(long)\r
+ * segmentid(int)\r
+ * number_of_key_fields(int)\r
+ * number_of_unique_columns(int)\r
+ * allow_duplicates(boolean)\r
+ * maintain_parent_links(boolean)\r
+ * array_of_format_ids(byte[][])\r
+ * baseConglomerateId(long)\r
+ * rowLocationColumn(int)\r
+ * ascend_column_info(FormatableBitSet)\r
+ * collation_ids(compressed array of ints)\r
+ *\r
+ */\r
+\r
+/**\r
+ * Implements an instance of a B-Tree secondary index conglomerate.\r
+ * A B2I object has two roles.\r
+ * <ol>\r
+ * <li>\r
+ * The B2I object is stored on disk, and holds the store specific\r
+ * information needed to access/describe the conglomerate. This\r
+ * includes information such as the format ids of the columns, \r
+ * the conglomerate id of the base table, the location of \r
+ * row location column.\r
+ * </li>\r
+ * <li>\r
+ * Access to all the interfaces start by making a call off the\r
+ * Conglomerate interface. So for instance to get a scan on the\r
+ * conglomerate method {@link #openScan openScan} should be called.\r
+ * </li>\r
+ * </ol>\r
+ */\r
+public class B2I extends BTree\r
+{\r
+ private static final String PROPERTY_BASECONGLOMID = "baseConglomerateId";\r
+ private static final String PROPERTY_ROWLOCCOLUMN = "rowLocationColumn";\r
+\r
+ static final int FORMAT_NUMBER = StoredFormatIds.ACCESS_B2I_V4_ID;\r
+\r
+ /*\r
+ ** Fields of B2I.\r
+ */\r
+\r
+ /**\r
+ The id of the conglomerate which contains the base table.\r
+ Row locations inserted into this secondary index are assumed\r
+ to refer to that conglomerate. Used to obtain table/row locks on the\r
+ base table rows which the index rows point at.\r
+ **/\r
+ long baseConglomerateId;\r
+\r
+ /**\r
+ The column id (zero-based integer index) of the column which holds the row \r
+ location to the base conglomerate.\r
+ The default value of RowLocationColumn is the last key column.\r
+ Used to obtain table/row locks on the base table rows with the index rows\r
+ point at.\r
+ Currently, RowLocationColumn must be the last key column.\r
+ **/\r
+ int rowLocationColumn;\r
+\r
+ private static final int BASE_MEMORY_USAGE = \r
+ ClassSize.estimateBaseFromCatalog( B2I.class);\r
+\r
+ public int estimateMemoryUsage()\r
+ {\r
+ return BASE_MEMORY_USAGE;\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Constructors for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**************************************************************************\r
+ * Protected locking implmentations of abtract BTree routines:\r
+ * getBtreeLockingPolicy\r
+ * lockTable\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Create a new btree locking policy from scratch.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ protected BTreeLockingPolicy getBtreeLockingPolicy(\r
+ Transaction rawtran,\r
+ int lock_level,\r
+ int mode,\r
+ int isolation_level,\r
+ ConglomerateController base_cc,\r
+ OpenBTree open_btree)\r
+ throws StandardException\r
+ {\r
+ BTreeLockingPolicy ret_locking_policy = null;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_SERIALIZABLE) ||\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_REPEATABLE_READ) ||\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK) ||\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_READ_COMMITTED) ||\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_READ_UNCOMMITTED),\r
+ "bad isolation_level = " + isolation_level);\r
+ }\r
+\r
+ if (lock_level == TransactionController.MODE_TABLE)\r
+ {\r
+ ret_locking_policy = \r
+ new B2ITableLocking3(\r
+ rawtran,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER, \r
+ isolation_level,\r
+ true), \r
+ base_cc,\r
+ open_btree);\r
+ }\r
+ else if (lock_level == TransactionController.MODE_RECORD)\r
+ {\r
+ if (isolation_level == TransactionController.ISOLATION_SERIALIZABLE)\r
+ {\r
+ ret_locking_policy = \r
+ new B2IRowLocking3(\r
+ rawtran,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD, \r
+ isolation_level,\r
+ true), \r
+ base_cc,\r
+ open_btree);\r
+ }\r
+ else if ((isolation_level == \r
+ TransactionController.ISOLATION_REPEATABLE_READ))\r
+ {\r
+ ret_locking_policy = \r
+ new B2IRowLockingRR(\r
+ rawtran,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD, \r
+ isolation_level,\r
+ true), \r
+ base_cc,\r
+ open_btree);\r
+ }\r
+ else if ((isolation_level == \r
+ TransactionController.ISOLATION_READ_COMMITTED) ||\r
+ (isolation_level == \r
+ TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK))\r
+ {\r
+ ret_locking_policy = \r
+ new B2IRowLocking2(\r
+ rawtran,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD, \r
+ isolation_level,\r
+ true), \r
+ base_cc,\r
+ open_btree);\r
+ }\r
+ else if (isolation_level == \r
+ TransactionController.ISOLATION_READ_UNCOMMITTED)\r
+ {\r
+ ret_locking_policy = \r
+ new B2IRowLocking1(\r
+ rawtran,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD, \r
+ isolation_level,\r
+ true), \r
+ base_cc,\r
+ open_btree);\r
+ }\r
+ }\r
+\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(\r
+ ret_locking_policy != null, "ret_locking_policy == null");\r
+ }\r
+\r
+ return(ret_locking_policy);\r
+ }\r
+\r
+ /**\r
+ * Lock the base table.\r
+ * <p>\r
+ * Assumes that segment of the base container is the same as the segment\r
+ * of the btree segment.\r
+ * <p>\r
+ * RESOLVE - we really want to get the lock without opening the container.\r
+ * raw store will be providing this.\r
+ *\r
+ * @param xact_manager Transaction to associate the lock with.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public final ConglomerateController lockTable(\r
+ TransactionManager xact_manager,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level)\r
+ throws StandardException\r
+ {\r
+ open_mode |= TransactionController.OPENMODE_FOR_LOCK_ONLY;\r
+\r
+ // open the base conglomerate - just to get the table lock.\r
+ ConglomerateController cc = \r
+ xact_manager.openConglomerate(\r
+ this.baseConglomerateId, false, open_mode, lock_level, \r
+ isolation_level);\r
+\r
+ return(cc);\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Private methods of B2I, arranged alphabetically.\r
+ **************************************************************************\r
+ */\r
+\r
+\r
+ private void traverseRight()\r
+ {\r
+ // RESOLVE - Do I have to do this???????????????\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT("not implemented.");\r
+ }\r
+\r
+\r
+ /*\r
+ ** Methods of B2I.\r
+ */\r
+\r
+ /**\r
+ Create an empty secondary index b-tree, using the generic b-tree to do the\r
+ generic part of the creation process.\r
+\r
+ This routine opens the newly created container, adds a single page, and\r
+ makes this page the root by inserting a LeafControlRow onto this page\r
+ at slot 0 and marking in that control row that the page is a root page.\r
+\r
+ The following properties are specific to the b-tree secondary index:\r
+ <UL>\r
+ <LI> "baseConglomerateId" (integer). The conglomerate id of the base\r
+ conglomerate is never actually accessed by the b-tree secondary\r
+ index implementation, it only serves as a namespace for row locks.\r
+ This property is required.\r
+ <LI> "rowLocationColumn" (integer). The zero-based index into the row which\r
+ the b-tree secondary index will assume holds a @see RowLocation of\r
+ the base row in the base conglomerate. This value will be used\r
+ for acquiring locks. In this implementation RowLocationColumn must be \r
+ the last key column.\r
+ This property is required.\r
+ </UL>\r
+\r
+ A secondary index i (a, b) on table t (a, b, c) would have rows\r
+ which looked like (a, b, row_location). baseConglomerateId is set to the\r
+ conglomerate id of t. rowLocationColumns is set to 2. allowsDuplicates\r
+ would be set to false, @see BTree#create. To create a unique\r
+ secondary index set uniquenessColumns to 2, this means that the btree\r
+ code will compare the key values but not the row id when determing\r
+ uniqueness. To create a nonunique secondary index set uniquenessColumns\r
+ to 3, this would mean that the uniqueness test would include the row\r
+ location and since all row locations will be unique all rows inserted \r
+ into the index will be differentiated (at least) by row location. \r
+\r
+ @see BTree#create\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void create(\r
+ TransactionManager xact_manager,\r
+ int segmentId, \r
+ long input_conglomid, \r
+ DataValueDescriptor[] template, \r
+ ColumnOrdering[] columnOrder,\r
+ int[] collationIds,\r
+ Properties properties,\r
+ int temporaryFlag)\r
+ throws StandardException\r
+ {\r
+ String property_value = null;\r
+ Transaction rawtran = xact_manager.getRawStoreXact();\r
+\r
+ if (properties == null)\r
+ {\r
+ throw(StandardException.newException(\r
+ SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID));\r
+ }\r
+\r
+ // Get baseConglomerateId //\r
+ property_value = properties.getProperty(PROPERTY_BASECONGLOMID);\r
+ if (property_value == null)\r
+ {\r
+ throw(StandardException.newException(\r
+ SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID));\r
+ }\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (property_value == null)\r
+ SanityManager.THROWASSERT(\r
+ PROPERTY_BASECONGLOMID +\r
+ "property not passed to B2I.create()");\r
+ }\r
+\r
+ baseConglomerateId = Long.parseLong(property_value);\r
+\r
+ // Get rowLocationColumn //\r
+ property_value = properties.getProperty(PROPERTY_ROWLOCCOLUMN);\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (property_value == null)\r
+ SanityManager.THROWASSERT(\r
+ PROPERTY_ROWLOCCOLUMN +\r
+ "property not passed to B2I.create()");\r
+ }\r
+\r
+ if (property_value == null)\r
+ {\r
+ throw(StandardException.newException(\r
+ SQLState.BTREE_PROPERTY_NOT_FOUND, PROPERTY_BASECONGLOMID));\r
+ }\r
+\r
+ rowLocationColumn = Integer.parseInt(property_value);\r
+\r
+ // Currently the row location column must be the last column (makes)\r
+ // comparing the columns in the index easier.\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(rowLocationColumn == template.length - 1, \r
+ "rowLocationColumn is not the last column in the index");\r
+ SanityManager.ASSERT(\r
+ template[rowLocationColumn] instanceof \r
+ RowLocation);\r
+\r
+ // There must be at least one key column\r
+ if (rowLocationColumn < 1)\r
+ SanityManager.THROWASSERT(\r
+ "rowLocationColumn (" + rowLocationColumn +\r
+ ") expected to be >= 1");\r
+ }\r
+\r
+\r
+ /* convert the sorting order information into a boolean array map.\r
+ * If the sorting order for the columns is not provided, we\r
+ * assign the default as Ascending Order.\r
+ * array length is equal to template length, because column order\r
+ * length changes whether it is unique or is non unique. store assumes\r
+ * template length arrays. So, we make template length array and make\r
+ * the last column as ascending instead of having lot of execeptions \r
+ * code.\r
+ */\r
+ \r
+ ascDescInfo = new boolean[template.length];\r
+ for (int i=0 ; i < ascDescInfo.length; i++)\r
+ {\r
+ if (columnOrder != null && i < columnOrder.length)\r
+ ascDescInfo[i] = columnOrder[i].getIsAscending();\r
+ else\r
+ ascDescInfo[i] = true; // default values - ascending order\r
+ }\r
+\r
+ // get collation ids from input collation ids, store it in the \r
+ // conglom state.\r
+ collation_ids = \r
+ ConglomerateUtil.createCollationIds(template.length, collationIds);\r
+\r
+ // Do the generic part of creating the b-tree.\r
+ super.create(\r
+ rawtran, segmentId, input_conglomid, template, \r
+ properties, getTypeFormatId(), temporaryFlag);\r
+\r
+ // open the base conglomerate - to get the lock\r
+ ConglomerateController base_cc = \r
+ xact_manager.openConglomerate(\r
+ baseConglomerateId,\r
+ false,\r
+ TransactionController.OPENMODE_FOR_LOCK_ONLY, \r
+ TransactionController.MODE_TABLE,\r
+ TransactionController.ISOLATION_SERIALIZABLE);\r
+ \r
+ OpenBTree open_btree = new OpenBTree();\r
+\r
+ BTreeLockingPolicy b2i_locking_policy = \r
+ new B2ITableLocking3(\r
+ rawtran,\r
+ TransactionController.MODE_TABLE,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true), \r
+ base_cc, open_btree);\r
+\r
+\r
+ // The following call will "open" the new btree. Create is\r
+ // an interesting case. What we really want is read only table lock\r
+ // on the base conglomerate and update locks on the index. For now\r
+ // just get the update lock on the base table, this is done by the\r
+ // lockTable() call made by base class.\r
+\r
+ open_btree.init(\r
+ (TransactionManager) xact_manager, // current user xact\r
+ (TransactionManager) xact_manager, // current xact\r
+ (ContainerHandle) null, // have init open the container.\r
+ rawtran, \r
+ false,\r
+ (ContainerHandle.MODE_FORUPDATE),\r
+ TransactionController.MODE_TABLE,\r
+ b2i_locking_policy, // get table level lock.\r
+ this, \r
+ (LogicalUndo) null, // no logical undo necessary, as \r
+ // initEmptyBtree()\r
+ // work will be done single user and\r
+ // rows will not move.\r
+ (DynamicCompiledOpenConglomInfo) null);\r
+ \r
+ // Open the newly created container, and insert the first control row.\r
+ LeafControlRow.initEmptyBtree(open_btree);\r
+\r
+ open_btree.close();\r
+\r
+ base_cc.close();\r
+ }\r
+\r
+\r
+\r
+ /*\r
+ ** Methods of Conglomerate\r
+ */\r
+\r
+ /**\r
+ * Retrieve the maximum value row in an ordered conglomerate.\r
+ * <p>\r
+ * Returns true and fetches the rightmost row of an ordered conglomerate \r
+ * into "fetchRow" if there is at least one row in the conglomerate. If\r
+ * there are no rows in the conglomerate it returns false.\r
+ * <p>\r
+ * Non-ordered conglomerates will not implement this interface, calls\r
+ * will generate a StandardException.\r
+ * <p>\r
+ * RESOLVE - this interface is temporary, long term equivalent (and more) \r
+ * functionality will be provided by the openBackwardScan() interface. \r
+ *\r
+ * @param xact_manager The TransactionController under which this \r
+ * operation takes place.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate\r
+ * to open the scan for.\r
+ *\r
+ * @param open_mode Specifiy flags to control opening of table. \r
+ * OPENMODE_FORUPDATE - if set open the table for\r
+ * update otherwise open table shared.\r
+ * @param lock_level One of (MODE_TABLE, MODE_RECORD, or MODE_NONE).\r
+ *\r
+ * @param isolation_level The isolation level to lock the conglomerate at.\r
+ * One of (ISOLATION_READ_COMMITTED or \r
+ * ISOLATION_SERIALIZABLE).\r
+ *\r
+ * @param scanColumnList A description of which columns to return from \r
+ * every fetch in the scan. template, \r
+ * and scanColumnList work together\r
+ * to describe the row to be returned by the scan - \r
+ * see RowUtil for description of how these three \r
+ * parameters work together to describe a "row".\r
+ *\r
+ * @param fetchRow The row to retrieve the maximum value into.\r
+ *\r
+ * @return boolean indicating if a row was found and retrieved or not.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean fetchMaxOnBTree(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ long conglomId,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] fetchRow)\r
+ throws StandardException\r
+ {\r
+ boolean row_exists;\r
+\r
+ // row level locking implementation.\r
+\r
+ // RESOLVE (revisit implementation after all the Xena rowlocking\r
+ // changes have been made). Can probably come up with single\r
+ // path implementation.\r
+ \r
+ // Create a new b-tree secondary index scan.\r
+ B2IMaxScan b2is = new B2IMaxScan();\r
+\r
+ // Initialize it.\r
+ b2is.init(\r
+ xact_manager, \r
+ rawtran, \r
+ open_mode,\r
+ lock_level,\r
+ locking_policy,\r
+ isolation_level,\r
+ true /* get locks on base table as part of open */,\r
+ scanColumnList,\r
+ this, \r
+ new B2IUndo());\r
+\r
+ row_exists = b2is.fetchMax(fetchRow);\r
+\r
+ b2is.close();\r
+\r
+ return(row_exists);\r
+ }\r
+\r
+\r
+ /**\r
+ Bulk Load a B-tree secondary index.\r
+\r
+ @see Conglomerate#load\r
+ @exception StandardException Standard Derby Error policy.\r
+ raise SQLState.STORE_CONGLOMERATE_DUPLICATE_KEY_EXCEPTION if a duplicate \r
+ key is detected in the load.\r
+ **/\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
+ B2IController b2ic = new B2IController();\r
+\r
+ try\r
+ {\r
+ int open_mode = TransactionController.OPENMODE_FORUPDATE;\r
+\r
+ if (createConglom)\r
+ {\r
+ open_mode |=\r
+ (ContainerHandle.MODE_UNLOGGED |\r
+ ContainerHandle.MODE_CREATE_UNLOGGED);\r
+ }\r
+\r
+ // Do the actual open of the container in the super class.\r
+ b2ic.init(\r
+ xact_manager, // current transaction \r
+ xact_manager.getRawStoreXact(), // current raw store xact\r
+ false, // Not holdable\r
+ open_mode,\r
+ TransactionController.MODE_TABLE,\r
+ xact_manager.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true),\r
+ true,\r
+ this, \r
+ new B2IUndo(),\r
+ (B2IStaticCompiledInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null);\r
+\r
+ num_rows_loaded = b2ic.load(xact_manager, createConglom, rowSource);\r
+\r
+ }\r
+ finally\r
+ {\r
+ b2ic.close();\r
+ }\r
+\r
+ return(num_rows_loaded);\r
+ }\r
+\r
+ /**\r
+ Open a b-tree controller.\r
+ @see Conglomerate#open\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public ConglomerateController open(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran, \r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ // Create a new b-tree secondary index controller.\r
+ B2IController b2ic = new B2IController();\r
+\r
+ // Do the actual open of the container in the super class.\r
+ b2ic.init(\r
+ xact_manager, // current transaction \r
+ rawtran, // current raw store transaction\r
+ hold, // holdability\r
+ open_mode,\r
+ lock_level,\r
+ locking_policy,\r
+ true,\r
+ this, \r
+ new B2IUndo(),\r
+ (B2IStaticCompiledInfo) static_info,\r
+ dynamic_info);\r
+\r
+ // Return it to the caller.\r
+ return b2ic;\r
+ }\r
+\r
+ /**\r
+ Open a b-tree secondary index scan controller.\r
+ @see Conglomerate#openScan\r
+ @see BTree#openScan\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public ScanManager openScan(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] startKeyValue,\r
+ int startSearchOperator,\r
+ Qualifier qualifier[][],\r
+ DataValueDescriptor[] stopKeyValue,\r
+ int stopSearchOperator,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ // Create a new b-tree secondary index scan.\r
+ B2IForwardScan b2is = new B2IForwardScan();\r
+\r
+ // Initialize it.\r
+ b2is.init(xact_manager, rawtran, \r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ locking_policy,\r
+ isolation_level,\r
+ true /* get locks on base table as part of open */,\r
+ scanColumnList,\r
+ startKeyValue, startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue, stopSearchOperator, this, new B2IUndo(),\r
+ (B2IStaticCompiledInfo) static_info,\r
+ dynamic_info);\r
+\r
+ // Return it to the caller.\r
+ return b2is;\r
+ }\r
+\r
+ /**\r
+ * Open a b-tree compress scan.\r
+ * <p>\r
+ * B2I does not support a compress scan.\r
+ * <p>\r
+ * @see Conglomerate#defragmentConglomerate\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ScanManager defragmentConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level)\r
+ throws StandardException\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.BTREE_UNIMPLEMENTED_FEATURE);\r
+ }\r
+\r
+ public void purgeConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ // currently on work to do in btree's for purge rows, purging\r
+ // happens best when split is about to happen.\r
+ return;\r
+ }\r
+\r
+ public void compressConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ B2IController b2ic = new B2IController();\r
+\r
+ try\r
+ {\r
+ int open_mode = TransactionController.OPENMODE_FORUPDATE;\r
+\r
+ // Do the actual open of the container in the super class.\r
+ b2ic.init(\r
+ xact_manager, // current transaction \r
+ xact_manager.getRawStoreXact(), // current raw store xact\r
+ false, // Not holdable\r
+ open_mode,\r
+ TransactionController.MODE_TABLE,\r
+ xact_manager.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true),\r
+ true,\r
+ this, \r
+ new B2IUndo(),\r
+ (B2IStaticCompiledInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null);\r
+\r
+ b2ic.getContainer().compressContainer();\r
+\r
+ }\r
+ finally\r
+ {\r
+ b2ic.close();\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Return an open StoreCostController for the conglomerate.\r
+ * <p>\r
+ * Return an open StoreCostController which can be used to ask about \r
+ * the estimated row counts and costs of ScanController and \r
+ * ConglomerateController operations, on the given conglomerate.\r
+ * <p>\r
+ * @param xact_manager The TransactionController under which this \r
+ * operation takes place.\r
+ * @param rawtran raw transaction context in which scan is managed.\r
+ *\r
+ * @return The open StoreCostController.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ *\r
+ * @see StoreCostController\r
+ **/\r
+ public StoreCostController openStoreCost(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ B2ICostController b2icost = new B2ICostController();\r
+\r
+ b2icost.init(xact_manager, this, rawtran);\r
+\r
+ return(b2icost);\r
+ }\r
+\r
+ /**\r
+ Drop this b-tree secondary index.\r
+ @see Conglomerate#drop\r
+ @see BTree#drop\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void drop(TransactionManager xact_manager)\r
+ throws StandardException\r
+ {\r
+ // HACK to get around problem where index is dropped after the base\r
+ // table.\r
+ ConglomerateController base_cc = null;\r
+\r
+\r
+ /* Get X table lock to make sure no thread is accessing index */\r
+ base_cc = \r
+ lockTable(\r
+ xact_manager, \r
+ TransactionController.OPENMODE_FORUPDATE, \r
+ TransactionController.MODE_TABLE,\r
+ TransactionController.ISOLATION_REPEATABLE_READ);\r
+\r
+ xact_manager.getRawStoreXact().dropContainer(id);\r
+\r
+ if (base_cc != null)\r
+ base_cc.close();\r
+ }\r
+\r
+ /**\r
+ * Return static information about the conglomerate to be included in a\r
+ * a compiled plan.\r
+ * <p>\r
+ * The static info would be valid until any ddl was executed on the \r
+ * conglomid, and would be up to the caller to throw away when that \r
+ * happened. This ties in with what language already does for other \r
+ * invalidation of static info. The type of info in this would be \r
+ * containerid and array of format id's from which templates can be created.\r
+ * The info in this object is read only and can be shared among as many \r
+ * threads as necessary.\r
+ * <p>\r
+ *\r
+ * @return The static compiled information.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate to open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public StaticCompiledOpenConglomInfo getStaticCompiledConglomInfo(\r
+ TransactionController xact_manager,\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ return(new B2IStaticCompiledInfo(xact_manager, this));\r
+ }\r
+\r
+ /*\r
+ ** Methods of Storable (via Conglomerate via BTree).\r
+ ** This class is responsible for re/storing its\r
+ ** own state and calling its superclass to store its'.\r
+ */\r
+\r
+\r
+ /*\r
+ * Storable interface, implies Externalizable, TypedFormat\r
+ */\r
+\r
+\r
+ /**\r
+ Return my format identifier.\r
+\r
+ @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId\r
+ */\r
+ public int getTypeFormatId() \r
+ {\r
+ return StoredFormatIds.ACCESS_B2I_V4_ID;\r
+ }\r
+\r
+\r
+ /**\r
+ * Store the stored representation of the column value in the\r
+ * stream.\r
+ * <p>\r
+ * For more detailed description of the ACCESS_B2I_V3_ID format see \r
+ * documentation at top of file.\r
+ *\r
+ * @see java.io.Externalizable#writeExternal\r
+ **/\r
+ public void writeExternal_v10_2(ObjectOutput out) \r
+ throws IOException \r
+ {\r
+ super.writeExternal(out);\r
+ out.writeLong(baseConglomerateId);\r
+ out.writeInt(rowLocationColumn);\r
+\r
+ //write the columns ascend/descend information as bits\r
+ FormatableBitSet ascDescBits = \r
+ new FormatableBitSet(ascDescInfo.length);\r
+\r
+ for (int i = 0; i < ascDescInfo.length; i++)\r
+ { \r
+ if (ascDescInfo[i])\r
+ ascDescBits.set(i);\r
+ }\r
+ ascDescBits.writeExternal(out);\r
+ }\r
+\r
+ /**\r
+ * Store the stored representation of the column value in the\r
+ * stream.\r
+ * <p>\r
+ * For more detailed description of the ACCESS_B2I_V3_ID and \r
+ * ACCESS_B2I_V4_ID formats see documentation at top of file.\r
+ *\r
+ * @see java.io.Externalizable#writeExternal\r
+ **/\r
+ public void writeExternal(ObjectOutput out) \r
+ throws IOException \r
+ {\r
+ // First part of ACCESS_B2I_V4_ID format is the ACCESS_B2I_V3_ID format.\r
+ writeExternal_v10_2(out);\r
+\r
+ if (conglom_format_id == StoredFormatIds.ACCESS_B2I_V4_ID)\r
+ {\r
+ // Now append sparse array of collation ids\r
+ ConglomerateUtil.writeCollationIdArray(collation_ids, out);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Restore the in-memory representation from the stream.\r
+ * <p>\r
+ *\r
+ * @exception ClassNotFoundException Thrown if the stored representation \r
+ * is serialized and a class named in \r
+ * the stream could not be found.\r
+ *\r
+ * @see java.io.Externalizable#readExternal\r
+ **/\r
+ private final void localReadExternal(ObjectInput in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ super.readExternal(in);\r
+ \r
+ baseConglomerateId = in.readLong();\r
+ rowLocationColumn = in.readInt();\r
+\r
+ // read the column sort order info\r
+ FormatableBitSet ascDescBits = new FormatableBitSet();\r
+ ascDescBits.readExternal(in);\r
+ ascDescInfo = new boolean[ascDescBits.getLength()];\r
+ for(int i =0 ; i < ascDescBits.getLength(); i++)\r
+ ascDescInfo[i] = ascDescBits.isSet(i);\r
+\r
+ // In memory maintain a collation id per column in the template.\r
+ collation_ids = new int[format_ids.length];\r
+\r
+ // initialize all the entries to COLLATION_TYPE_UCS_BASIC, \r
+ // and then reset as necessary. For version ACCESS_B2I_V3_ID,\r
+ // this is the default and no resetting is necessary.\r
+ for (int i = 0; i < format_ids.length; i++)\r
+ collation_ids[i] = StringDataValue.COLLATION_TYPE_UCS_BASIC;\r
+\r
+ if (conglom_format_id == StoredFormatIds.ACCESS_B2I_V4_ID)\r
+ {\r
+ // current format id, read collation info from disk\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // length must include row location column and at least\r
+ // one other field.\r
+ SanityManager.ASSERT(\r
+ collation_ids.length >= 2, \r
+ "length = " + collation_ids.length);\r
+ }\r
+\r
+ ConglomerateUtil.readCollationIdArray(collation_ids, in);\r
+ }\r
+ else if (conglom_format_id != StoredFormatIds.ACCESS_B2I_V3_ID)\r
+ {\r
+ // Currently only V3 and V4 should be possible in a Derby DB.\r
+ // Actual work for V3 is handled by default code above, so no\r
+ // special work is necessary.\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected format id: " + conglom_format_id);\r
+ }\r
+ }\r
+ }\r
+\r
+ public void readExternal(ObjectInput in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ localReadExternal(in);\r
+ }\r
+ public void readExternalFromArray(ArrayInputStream in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ localReadExternal(in);\r
+ }\r
+}\r