--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.RAMTransaction\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;\r
+\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.util.ReuseFactory;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+import org.apache.derby.iapi.services.io.Storable;\r
+\r
+import org.apache.derby.iapi.services.daemon.Serviceable;\r
+import org.apache.derby.iapi.services.locks.CompatibilitySpace;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;\r
+import org.apache.derby.iapi.store.access.conglomerate.ConglomerateFactory;\r
+import org.apache.derby.iapi.store.access.conglomerate.ScanManager;\r
+import org.apache.derby.iapi.store.access.conglomerate.MethodFactory;\r
+import org.apache.derby.iapi.store.access.conglomerate.ScanControllerRowSource;\r
+import org.apache.derby.iapi.store.access.conglomerate.Sort;\r
+import org.apache.derby.iapi.store.access.conglomerate.SortFactory;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+import org.apache.derby.iapi.store.access.AccessFactory;\r
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;\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.FileResource;\r
+import org.apache.derby.iapi.store.access.GroupFetchScanController;\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.ScanController;\r
+import org.apache.derby.iapi.store.access.SortController;\r
+import org.apache.derby.iapi.store.access.SortCostController;\r
+import org.apache.derby.iapi.store.access.SortObserver;\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
+import org.apache.derby.iapi.store.access.XATransactionController;\r
+\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+\r
+\r
+import org.apache.derby.iapi.store.raw.Loggable;\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.impl.store.access.conglomerate.ConglomerateUtil;\r
+\r
+import org.apache.derby.iapi.store.access.DatabaseInstant;\r
+\r
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import java.io.Serializable;\r
+\r
+// debugging\r
+import org.apache.derby.iapi.services.stream.HeaderPrintWriter;\r
+\r
+public class RAMTransaction \r
+ implements XATransactionController, TransactionManager\r
+{\r
+\r
+ /**\r
+ The corresponding raw store transaction.\r
+ **/\r
+ protected Transaction rawtran;\r
+\r
+ /**\r
+ The access manager this transaction is under.\r
+ **/\r
+ protected RAMAccessManager accessmanager;\r
+\r
+ /**\r
+ The context this transaction is being managed by.\r
+ **/\r
+ protected RAMTransactionContext context;\r
+\r
+ /**\r
+ The parent transaction if this is a nested user transaction.\r
+ **/\r
+ protected RAMTransaction parent_tran;\r
+\r
+ // XXX (nat) management of the controllers is still embryonic.\r
+ // XXX (nat) would be nice if sort controllers were like conglom controllers\r
+ private ArrayList scanControllers;\r
+ private ArrayList conglomerateControllers;\r
+ private ArrayList sorts;\r
+ private ArrayList sortControllers;\r
+\r
+ /** List of sort identifiers (represented as <code>Integer</code> objects)\r
+ * which can be reused. Since sort identifiers are used as array indexes,\r
+ * we need to reuse them to avoid leaking memory (DERBY-912). */\r
+ private ArrayList freeSortIds;\r
+\r
+ /**\r
+ Where to look for temporary conglomerates.\r
+ **/\r
+ protected HashMap tempCongloms;\r
+\r
+ /**\r
+ Next id to use for a temporary conglomerate.\r
+ **/\r
+ private long nextTempConglomId = -1;\r
+\r
+ /**\r
+ * Set by alter table to indicate that the conglomerate cache needs to\r
+ * be invalidated if a transaction aborting error is encountered, cleared\r
+ * after cleanup.\r
+ */\r
+ private boolean alterTableCallMade = false;\r
+\r
+ /**\r
+ * The lock level of the transaction.\r
+ * <p>\r
+ * Cannot lock a level lower than the getSystemLockLevel(). So if \r
+ * getSystemLockLevel() is table level locking, setting the transaction\r
+ * locking level to record has no effect.\r
+ **/\r
+ private int transaction_lock_level;\r
+\r
+ /**************************************************************************\r
+ * Constructors for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ private final void init(\r
+ RAMAccessManager myaccessmanager, \r
+ Transaction theRawTran,\r
+ RAMTransaction parent_tran)\r
+ {\r
+ this.rawtran = theRawTran;\r
+ this.parent_tran = parent_tran;\r
+ accessmanager = myaccessmanager;\r
+ scanControllers = new ArrayList();\r
+ conglomerateControllers = new ArrayList();\r
+\r
+ sorts = null; // allocated on demand.\r
+ freeSortIds = null; // allocated on demand.\r
+ sortControllers = null; // allocated on demand\r
+\r
+ if (parent_tran != null)\r
+ {\r
+ // allow nested transactions to see temporary conglomerates which\r
+ // were created in the parent transaction. This is necessary for\r
+ // language which compiling plans in nested transactions against \r
+ // user temporaries created in parent transactions.\r
+\r
+ tempCongloms = parent_tran.tempCongloms;\r
+ }\r
+ else\r
+ {\r
+ tempCongloms = null; // allocated on demand\r
+ }\r
+ }\r
+\r
+ protected RAMTransaction(\r
+ RAMAccessManager myaccessmanager, \r
+ Transaction theRawTran,\r
+ RAMTransaction parent_transaction)\r
+ throws StandardException\r
+ {\r
+ init(myaccessmanager, theRawTran, parent_transaction);\r
+ }\r
+\r
+ RAMTransaction(\r
+ RAMAccessManager myaccessmanager, \r
+ RAMTransaction tc,\r
+ int format_id,\r
+ byte[] global_id,\r
+ byte[] branch_id)\r
+ throws StandardException\r
+ {\r
+ init(myaccessmanager, tc.getRawStoreXact(), null);\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(tc.getRawStoreXact().isIdle());\r
+\r
+ this.context = tc.context;\r
+\r
+ // switch the transaction pointer in the context to point to this xact\r
+ this.context.setTransaction(this);\r
+\r
+ this.rawtran.createXATransactionFromLocalTransaction(\r
+ format_id, global_id, branch_id);\r
+\r
+ // invalidate old tc, so caller does not use it. Can't just call\r
+ // destroy as that screws up the contexts which we want to just leave\r
+ // alone.\r
+ tc.rawtran = null;\r
+ }\r
+\r
+\r
+ RAMTransaction()\r
+ {\r
+ }\r
+\r
+\r
+ /**************************************************************************\r
+ * Private/Protected methods of This class:\r
+ **************************************************************************\r
+ */\r
+\r
+\r
+ // XXX (nat) currently closes all controllers.\r
+ protected void closeControllers(boolean closeHeldControllers)\r
+ throws StandardException\r
+ {\r
+\r
+ if (!scanControllers.isEmpty())\r
+ {\r
+ // loop from end to beginning, removing scans which are not held.\r
+ for (int i = scanControllers.size() - 1; i >= 0; i--)\r
+ {\r
+ ScanManager sc = (ScanManager) scanControllers.get(i);\r
+\r
+ if (sc.closeForEndTransaction(closeHeldControllers))\r
+ {\r
+ // TODO - now counting on scan's removing themselves by \r
+ // calling the closeMe() method.\r
+ /* scanControllers.removeElementAt(i); */\r
+ }\r
+ }\r
+\r
+ if (closeHeldControllers)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(scanControllers.isEmpty());\r
+ }\r
+ // just to make sure everything has been closed and removed.\r
+ scanControllers.clear();\r
+ }\r
+ }\r
+\r
+ if (!conglomerateControllers.isEmpty())\r
+ {\r
+ // loop from end to beginning, removing scans which are not held.\r
+ for (int i = conglomerateControllers.size() - 1; i >= 0; i--)\r
+ {\r
+ ConglomerateController cc = \r
+ (ConglomerateController) \r
+ conglomerateControllers.get(i);\r
+\r
+ if (cc.closeForEndTransaction(closeHeldControllers))\r
+ {\r
+ // TODO - now counting on cc's removing themselves by \r
+ // calling the closeMe() method.\r
+ /* conglomerateControllers.removeElementAt(i); */\r
+ }\r
+ }\r
+\r
+ if (closeHeldControllers)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(scanControllers.isEmpty());\r
+ }\r
+ // just to make sure everything has been closed and removed.\r
+ conglomerateControllers.clear();\r
+ }\r
+ }\r
+\r
+ if ((sortControllers != null) && !sortControllers.isEmpty())\r
+ {\r
+ if (closeHeldControllers)\r
+ {\r
+ // Loop from the end since the call to close() will remove the\r
+ // element from the list.\r
+ for (int i = sortControllers.size() - 1; i >= 0; i--)\r
+ {\r
+ SortController sc = (SortController) sortControllers.get(i);\r
+ sc.completedInserts();\r
+ }\r
+ sortControllers.clear();\r
+ }\r
+ }\r
+\r
+ if ((sorts != null) && (!sorts.isEmpty()))\r
+ {\r
+ if (closeHeldControllers)\r
+ {\r
+ // Loop from the end since the call to drop() will remove the\r
+ // element from the list.\r
+ for (int i = sorts.size() - 1; i >= 0; i--)\r
+ {\r
+ Sort sort = (Sort) sorts.get(i);\r
+ if (sort != null)\r
+ sort.drop(this);\r
+ }\r
+ sorts.clear();\r
+ freeSortIds.clear();\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * Determine correct locking policy for a conglomerate open.\r
+ * <p>\r
+ * Determine from the following table whether to table or record lock\r
+ * the conglomerate we are opening.\r
+ * <p>\r
+ *\r
+ *\r
+ * System level override\r
+ * -------------------------------\r
+ * user requests table locking record locking\r
+ * ------------- ------------- --------------\r
+ * TransactionController.MODE_TABLE TABLE TABLE\r
+ * TransactionController.MODE_RECORD TABLE RECORD\r
+ **/\r
+ private LockingPolicy determine_locking_policy(\r
+ int requested_lock_level,\r
+ int isolation_level)\r
+ {\r
+ LockingPolicy ret_locking_policy;\r
+\r
+ if ((accessmanager.getSystemLockLevel() == \r
+ TransactionController.MODE_TABLE) ||\r
+ (requested_lock_level == TransactionController.MODE_TABLE))\r
+ {\r
+ ret_locking_policy = \r
+ accessmanager.table_level_policy[isolation_level];\r
+ }\r
+ else \r
+ {\r
+ ret_locking_policy = \r
+ accessmanager.record_level_policy[isolation_level];\r
+ \r
+ }\r
+ return(ret_locking_policy);\r
+ }\r
+\r
+ private int determine_lock_level(\r
+ int requested_lock_level)\r
+ {\r
+ int ret_lock_level;\r
+\r
+ if ((accessmanager.getSystemLockLevel() == \r
+ TransactionController.MODE_TABLE) ||\r
+ (requested_lock_level == TransactionController.MODE_TABLE))\r
+ {\r
+ ret_lock_level = TransactionController.MODE_TABLE;\r
+ }\r
+ else \r
+ {\r
+ ret_lock_level = TransactionController.MODE_RECORD;\r
+ \r
+ }\r
+ return(ret_lock_level);\r
+ }\r
+\r
+ private Conglomerate findExistingConglomerate(long conglomId)\r
+ throws StandardException\r
+ {\r
+ Conglomerate conglom = null;\r
+\r
+ if (conglomId < 0)\r
+ {\r
+ if (tempCongloms != null)\r
+ conglom = (Conglomerate) tempCongloms.get(new Long(conglomId));\r
+ }\r
+ else\r
+ {\r
+ conglom = accessmanager.conglomCacheFind(this, conglomId);\r
+ }\r
+\r
+ if (conglom == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.STORE_CONGLOMERATE_DOES_NOT_EXIST, \r
+ new Long(conglomId));\r
+ }\r
+ else\r
+ {\r
+ return(conglom);\r
+ }\r
+ }\r
+\r
+ private Conglomerate findConglomerate(long conglomId)\r
+ throws StandardException\r
+ {\r
+ Conglomerate conglom = null;\r
+\r
+ if (conglomId >= 0)\r
+ {\r
+ conglom = accessmanager.conglomCacheFind(this, conglomId);\r
+ }\r
+ else\r
+ {\r
+ if (tempCongloms != null)\r
+ conglom = (Conglomerate) tempCongloms.get(new Long(conglomId));\r
+ }\r
+\r
+ return(conglom);\r
+ }\r
+\r
+ void setContext(RAMTransactionContext rtc)\r
+ {\r
+ context = rtc;\r
+ }\r
+\r
+ /**\r
+ Get cache statistics for the specified cache\r
+ */\r
+ public long[] getCacheStats(String cacheName) {\r
+ return getRawStoreXact().getCacheStats(cacheName);\r
+ }\r
+\r
+ private ConglomerateController openConglomerate(\r
+ Conglomerate conglom,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if ((open_mode & \r
+ ~(ContainerHandle.MODE_UNLOGGED |\r
+ ContainerHandle.MODE_CREATE_UNLOGGED |\r
+ ContainerHandle.MODE_FORUPDATE |\r
+ ContainerHandle.MODE_READONLY |\r
+ ContainerHandle.MODE_TRUNCATE_ON_COMMIT |\r
+ ContainerHandle.MODE_DROP_ON_COMMIT |\r
+ ContainerHandle.MODE_OPEN_FOR_LOCK_ONLY |\r
+ ContainerHandle.MODE_LOCK_NOWAIT |\r
+ ContainerHandle.MODE_TRUNCATE_ON_ROLLBACK |\r
+ ContainerHandle.MODE_FLUSH_ON_COMMIT |\r
+ ContainerHandle.MODE_NO_ACTIONS_ON_COMMIT |\r
+ ContainerHandle.MODE_TEMP_IS_KEPT |\r
+ ContainerHandle.MODE_USE_UPDATE_LOCKS |\r
+ ContainerHandle.MODE_SECONDARY_LOCKED |\r
+ ContainerHandle.MODE_BASEROW_INSERT_LOCKED)) != 0) \r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Bad open mode to openConglomerate:" + \r
+ Integer.toHexString(open_mode));\r
+ }\r
+\r
+ SanityManager.ASSERT(conglom != null);\r
+ \r
+ if (lock_level != MODE_RECORD && lock_level != MODE_TABLE)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Bad lock level to openConglomerate:" + lock_level);\r
+ }\r
+ }\r
+\r
+ // Get a conglomerate controller.\r
+ ConglomerateController cc = \r
+ conglom.open(\r
+ this, rawtran, hold, open_mode, \r
+ determine_lock_level(lock_level), \r
+ determine_locking_policy(lock_level, isolation_level),\r
+ static_info,\r
+ dynamic_info);\r
+\r
+ // Keep track of it so we can release on close.\r
+ conglomerateControllers.add(cc);\r
+\r
+ return cc;\r
+ }\r
+\r
+ private ScanController openScan(\r
+ Conglomerate conglom,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\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
+ if (SanityManager.DEBUG)\r
+ {\r
+ if ((open_mode & \r
+ ~(TransactionController.OPENMODE_FORUPDATE |\r
+ TransactionController.OPENMODE_USE_UPDATE_LOCKS |\r
+ TransactionController.OPENMODE_FOR_LOCK_ONLY |\r
+ TransactionController.OPENMODE_LOCK_NOWAIT |\r
+ TransactionController.OPENMODE_SECONDARY_LOCKED)) != 0)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Bad open mode to openScan:" +\r
+ Integer.toHexString(open_mode));\r
+ }\r
+\r
+ if (!((lock_level == MODE_RECORD | lock_level == MODE_TABLE)))\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Bad lock level to openScan:" + lock_level);\r
+ }\r
+ }\r
+\r
+ // Get a scan controller.\r
+ ScanManager sm =\r
+ conglom.openScan(\r
+ this, rawtran, hold, open_mode,\r
+ determine_lock_level(lock_level),\r
+ determine_locking_policy(lock_level, isolation_level),\r
+ isolation_level,\r
+ scanColumnList,\r
+ startKeyValue, startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue, stopSearchOperator,\r
+ static_info,\r
+ dynamic_info);\r
+\r
+ // Keep track of it so we can release on close.\r
+ scanControllers.add(sm);\r
+\r
+ return(sm);\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ Reset the cache statistics for the specified cache\r
+ */\r
+ public void resetCacheStats(String cacheName) {\r
+ getRawStoreXact().resetCacheStats(cacheName);\r
+ }\r
+\r
+ /**\r
+ * Invalidate the conglomerate cache, if necessary. If an alter table\r
+ * call has been made then invalidate the cache.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ protected void invalidateConglomerateCache()\r
+ throws StandardException\r
+ {\r
+ if (alterTableCallMade)\r
+ {\r
+ accessmanager.conglomCacheInvalidate();\r
+ alterTableCallMade = false;\r
+ }\r
+ }\r
+\r
+\r
+ /**************************************************************************\r
+ * Public Methods of TransactionController interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ Add a column to a conglomerate. The conglomerate must not be open in\r
+ the current transaction. This also means that there must not be any\r
+ active scans on it.\r
+\r
+ The column can only be added at the spot just after the current set of\r
+ columns.\r
+\r
+ The template_column must be nullable.\r
+\r
+ After this call has been made, all fetches of this column from rows that\r
+ existed in the table prior to this call will return "null".\r
+\r
+ @param conglomId The identifier of the conglomerate to drop.\r
+ @param column_id The column number to add this column at.\r
+ @param template_column An instance of the column to be added to table.\r
+ @param collation_id collation id of the added column.\r
+\r
+ @exception StandardException Only some types of conglomerates can support\r
+ adding a column, for instance "heap" conglomerates support adding a\r
+ column while "btree" conglomerates do not. If the column can not be\r
+ added an exception will be thrown.\r
+ **/\r
+ public void addColumnToConglomerate(\r
+ long conglomId,\r
+ int column_id,\r
+ Storable template_column,\r
+ int collation_id)\r
+ throws StandardException\r
+ {\r
+ boolean is_temporary = (conglomId < 0);\r
+\r
+ Conglomerate conglom = findConglomerate(conglomId);\r
+ if (conglom == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_CONGLOMERATE_DROP, new Long(conglomId));\r
+ }\r
+\r
+ // Get exclusive lock on the table being altered.\r
+ ConglomerateController cc =\r
+ conglom.open(\r
+ this, rawtran, false, OPENMODE_FORUPDATE,\r
+ MODE_TABLE,\r
+ accessmanager.table_level_policy[\r
+ TransactionController.ISOLATION_SERIALIZABLE],\r
+ (StaticCompiledOpenConglomInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null);\r
+\r
+ conglom.addColumn(this, column_id, template_column, collation_id);\r
+\r
+ // remove the old entry in the Conglomerate directory, and add the\r
+ // new one.\r
+ if (is_temporary)\r
+ {\r
+ // remove old entry in the Conglomerate directory, and add new one\r
+ if (tempCongloms != null)\r
+ tempCongloms.remove(new Long(conglomId));\r
+ tempCongloms.put(new Long(conglomId), conglom);\r
+ }\r
+ else\r
+ {\r
+ alterTableCallMade = true;\r
+\r
+ // have access manager update the conglom to this new one.\r
+ accessmanager.conglomCacheUpdateEntry(conglomId, conglom);\r
+ }\r
+\r
+ cc.close();\r
+\r
+ return;\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
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ findExistingConglomerate(\r
+ conglomId).getStaticCompiledConglomInfo(this, conglomId));\r
+ }\r
+\r
+ /**\r
+ * Return dynamic information about the conglomerate to be dynamically\r
+ * reused in repeated execution of a statement.\r
+ * <p>\r
+ * The dynamic info is a set of variables to be used in a given\r
+ * ScanController or ConglomerateController. It can only be used in one\r
+ * controller at a time. It is up to the caller to insure the correct\r
+ * thread access to this info. The type of info in this is a scratch\r
+ * template for btree traversal, other scratch variables for qualifier\r
+ * evaluation, ...\r
+ * <p>\r
+ *\r
+ * @return The dynamic information.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate to open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public DynamicCompiledOpenConglomInfo getDynamicCompiledConglomInfo(\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ findExistingConglomerate(\r
+ conglomId).getDynamicCompiledConglomInfo(conglomId));\r
+ }\r
+\r
+\r
+ private final int countCreatedSorts()\r
+ {\r
+ int ret_val = 0;\r
+ if (sorts != null)\r
+ {\r
+ for (int i = 0; i < sorts.size(); i++)\r
+ {\r
+ if (sorts.get(i) != null)\r
+ ret_val++;\r
+ }\r
+ }\r
+\r
+ return(ret_val);\r
+ }\r
+\r
+ /**\r
+ * Report on the number of open conglomerates in the transaction.\r
+ * <p>\r
+ * There are 4 types of open "conglomerates" that can be tracked, those\r
+ * opened by each of the following: openConglomerate(), openScan(), \r
+ * openSort(), and openSortScan(). This routine can be used to either\r
+ * report on the number of all opens, or may be used to track one \r
+ * particular type of open.\r
+ *\r
+ * This routine is expected to be used for debugging only. An \r
+ * implementation may only track this info under SanityManager.DEBUG mode.\r
+ * If the implementation does not track the info it will return -1 (so\r
+ * code using this call to verify that no congloms are open should check\r
+ * for return <= 0 rather than == 0).\r
+ *\r
+ * The return value depends on the "which_to_count" parameter as follows:\r
+ * OPEN_CONGLOMERATE - return # of openConglomerate() calls not close()'d.\r
+ * OPEN_SCAN - return # of openScan() calls not close()'d.\r
+ * OPEN_CREATED_SORTS - return # of sorts created (createSort()) in \r
+ * current xact. There is currently no way to get\r
+ * rid of these sorts before end of transaction.\r
+ * OPEN_SORT - return # of openSort() calls not close()'d.\r
+ * OPEN_TOTAL - return total # of all above calls not close()'d.\r
+ * - note an implementation may return -1 if it does not track the\r
+ * above information.\r
+ *\r
+ * @return The nunber of open's of a type indicated by "which_to_count"\r
+ * parameter.\r
+ *\r
+ * @param which_to_count Which kind of open to report on.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public int countOpens(int which_to_count)\r
+ throws StandardException\r
+ {\r
+ int ret_val = -1;\r
+\r
+ switch (which_to_count)\r
+ {\r
+ case OPEN_CONGLOMERATE:\r
+ ret_val = conglomerateControllers.size();\r
+ break;\r
+ case OPEN_SCAN:\r
+ ret_val = scanControllers.size();\r
+ break;\r
+ case OPEN_CREATED_SORTS:\r
+ ret_val = countCreatedSorts();\r
+ break;\r
+ case OPEN_SORT:\r
+ ret_val = \r
+ ((sortControllers != null) ? sortControllers.size() : 0);\r
+ break;\r
+ case OPEN_TOTAL:\r
+ ret_val = \r
+ conglomerateControllers.size() + scanControllers.size() +\r
+ ((sortControllers != null) ? sortControllers.size() : 0) +\r
+ countCreatedSorts();\r
+ break;\r
+ }\r
+\r
+ return(ret_val);\r
+ }\r
+\r
+ /**\r
+ * Create a new conglomerate.\r
+ * <p>\r
+ * @see TransactionController#createConglomerate\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public long createConglomerate(\r
+ String implementation,\r
+ DataValueDescriptor[] template,\r
+ ColumnOrdering[] columnOrder,\r
+ int[] collationIds,\r
+ Properties properties,\r
+ int temporaryFlag)\r
+ throws StandardException\r
+ {\r
+ // Find the appropriate factory for the desired implementation.\r
+ MethodFactory mfactory;\r
+ mfactory = accessmanager.findMethodFactoryByImpl(implementation);\r
+ if (mfactory == null || !(mfactory instanceof ConglomerateFactory))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_CONGLOMERATE_TYPE, implementation);\r
+ }\r
+ ConglomerateFactory cfactory = (ConglomerateFactory) mfactory;\r
+\r
+ // Create the conglomerate\r
+ // RESOLVE (mikem) - eventually segmentid's will be passed into here\r
+ // in the properties. For now just use 0.]\r
+ int segment;\r
+ long conglomid;\r
+ if ((temporaryFlag & TransactionController.IS_TEMPORARY)\r
+ == TransactionController.IS_TEMPORARY)\r
+ {\r
+ segment = ContainerHandle.TEMPORARY_SEGMENT;\r
+ conglomid = ContainerHandle.DEFAULT_ASSIGN_ID;\r
+ }\r
+ else\r
+ {\r
+ segment = 0; // RESOLVE - only using segment 0\r
+ conglomid = \r
+ accessmanager.getNextConglomId(\r
+ cfactory.getConglomerateFactoryId());\r
+ }\r
+\r
+ // call the factory to actually create the conglomerate.\r
+ Conglomerate conglom =\r
+ cfactory.createConglomerate(\r
+ this, segment, conglomid, template, \r
+ columnOrder, collationIds, properties, temporaryFlag);\r
+\r
+ long conglomId;\r
+ if ((temporaryFlag & TransactionController.IS_TEMPORARY)\r
+ == TransactionController.IS_TEMPORARY)\r
+ {\r
+ conglomId = nextTempConglomId--;\r
+ if (tempCongloms == null)\r
+ tempCongloms = new HashMap();\r
+ tempCongloms.put(new Long(conglomId), conglom);\r
+ }\r
+ else\r
+ {\r
+ conglomId = conglom.getContainerid();\r
+\r
+ accessmanager.conglomCacheAddEntry(conglomId, conglom);\r
+ }\r
+\r
+ return conglomId;\r
+ }\r
+\r
+ /**\r
+ Create a conglomerate and populate it with rows from rowSource.\r
+\r
+ @see TransactionController#createAndLoadConglomerate\r
+ @exception StandardException Standard Derby Error Policy\r
+ */\r
+ public long createAndLoadConglomerate(\r
+ String implementation,\r
+ DataValueDescriptor[] template,\r
+ ColumnOrdering[] columnOrder,\r
+ int[] collationIds,\r
+ Properties properties,\r
+ int temporaryFlag,\r
+ RowLocationRetRowSource rowSource,\r
+ long[] rowCount)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ recreateAndLoadConglomerate(\r
+ implementation,\r
+ true,\r
+ template,\r
+ columnOrder,\r
+ collationIds,\r
+ properties,\r
+ temporaryFlag,\r
+ 0 /* unused if recreate_ifempty is true */,\r
+ rowSource,\r
+ rowCount));\r
+ }\r
+\r
+ /**\r
+ recreate a conglomerate and populate it with rows from rowSource.\r
+\r
+ @see TransactionController#createAndLoadConglomerate\r
+ @exception StandardException Standard Derby Error Policy\r
+ */\r
+ public long recreateAndLoadConglomerate(\r
+ String implementation,\r
+ boolean recreate_ifempty,\r
+ DataValueDescriptor[] template,\r
+ ColumnOrdering[] columnOrder,\r
+ int[] collationIds,\r
+ Properties properties,\r
+ int temporaryFlag,\r
+ long orig_conglomId,\r
+ RowLocationRetRowSource rowSource,\r
+ long[] rowCount)\r
+ throws StandardException\r
+\r
+ {\r
+ // RESOLVE: this create the conglom LOGGED, this is slower than\r
+ // necessary although still correct.\r
+ long conglomId = \r
+ createConglomerate(\r
+ implementation, template, columnOrder, collationIds, \r
+ properties, temporaryFlag);\r
+\r
+ long rows_loaded = \r
+ loadConglomerate(\r
+ conglomId, \r
+ true, // conglom is being created\r
+ rowSource);\r
+\r
+ if (rowCount != null)\r
+ rowCount[0] = rows_loaded;\r
+\r
+ if (!recreate_ifempty && (rows_loaded == 0))\r
+ {\r
+ dropConglomerate(conglomId);\r
+\r
+ conglomId = orig_conglomId;\r
+ }\r
+\r
+ return conglomId;\r
+ }\r
+\r
+ /**\r
+ * Return a string with debug information about opened congloms/scans/sorts.\r
+ * <p>\r
+ * Return a string with debugging information about current opened\r
+ * congloms/scans/sorts which have not been close()'d.\r
+ * Calls to this routine are only valid under code which is conditional\r
+ * on SanityManager.DEBUG.\r
+ * <p>\r
+ *\r
+ * @return String with debugging information.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public String debugOpened() throws StandardException\r
+ {\r
+ String str = null;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+\r
+ str = new String();\r
+\r
+ for (Iterator it = scanControllers.iterator(); it.hasNext(); )\r
+ {\r
+ ScanController sc = (ScanController) it.next();\r
+ str += "open scan controller: " + sc + "\n";\r
+ }\r
+\r
+ for (Iterator it = conglomerateControllers.iterator();\r
+ it.hasNext(); )\r
+ {\r
+ ConglomerateController cc = \r
+ (ConglomerateController) it.next();\r
+ str += "open conglomerate controller: " + cc + "\n";\r
+ }\r
+\r
+ if (sortControllers != null)\r
+ {\r
+ for (Iterator it = sortControllers.iterator(); it.hasNext(); )\r
+ {\r
+ SortController sc = (SortController) it.next();\r
+ str += "open sort controller: " + sc + "\n";\r
+ }\r
+ }\r
+\r
+ if (sorts != null)\r
+ {\r
+ for (int i = 0; i < sorts.size(); i++)\r
+ {\r
+ Sort sort = (Sort) sorts.get(i);\r
+\r
+ if (sort != null)\r
+ {\r
+ str += \r
+ "sorts created by createSort() in current xact:" + \r
+ sort + "\n";\r
+ }\r
+ }\r
+ }\r
+\r
+ if (tempCongloms != null)\r
+ {\r
+ for (Iterator it = tempCongloms.keySet().iterator();\r
+ it.hasNext(); )\r
+ {\r
+ Long conglomId = (Long) it.next();\r
+ Conglomerate c = (Conglomerate) tempCongloms.get(conglomId);\r
+ str += "temp conglomerate id = " + conglomId + ": " + c;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ return(str);\r
+ }\r
+\r
+ public boolean conglomerateExists(long conglomId)\r
+ throws StandardException\r
+ {\r
+ Conglomerate conglom = findConglomerate(conglomId);\r
+ if (conglom == null)\r
+ return false;\r
+ return true;\r
+ }\r
+\r
+ public void dropConglomerate(long conglomId)\r
+ throws StandardException\r
+ {\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ conglom.drop(this);\r
+\r
+ if (conglomId < 0)\r
+ {\r
+ if (tempCongloms != null)\r
+ tempCongloms.remove(new Long(conglomId));\r
+ }\r
+ else\r
+ {\r
+ accessmanager.conglomCacheRemoveEntry(conglomId);\r
+ }\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 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
+ long conglomId,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] fetchRow)\r
+ throws StandardException\r
+ {\r
+ // Find the conglomerate.\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ // Get a scan controller.\r
+ return(\r
+ conglom.fetchMaxOnBTree(\r
+ this, \r
+ rawtran,\r
+ conglomId,\r
+ open_mode,\r
+ lock_level,\r
+ determine_locking_policy(lock_level, isolation_level),\r
+ isolation_level,\r
+ scanColumnList,\r
+ fetchRow));\r
+ }\r
+\r
+\r
+ /**\r
+ * A superset of properties that "users" can specify.\r
+ * <p>\r
+ * A superset of properties that "users" (ie. from sql) can specify. Store\r
+ * may implement other properties which should not be specified by users.\r
+ * Layers above access may implement properties which are not known at\r
+ * all to Access.\r
+ * <p>\r
+ * This list is a superset, as some properties may not be implemented by\r
+ * certain types of conglomerates. For instant an in-memory store may not\r
+ * implement a pageSize property. Or some conglomerates may not support\r
+ * pre-allocation.\r
+ * <p>\r
+ * This interface is meant to be used by the SQL parser to do validation\r
+ * of properties passsed to the create table statement, and also by the\r
+ * various user interfaces which present table information back to the \r
+ * user.\r
+ * <p>\r
+ * Currently this routine returns the following list:\r
+ * derby.storage.initialPages\r
+ * derby.storage.minimumRecordSize\r
+ * derby.storage.pageReservedSpace\r
+ * derby.storage.pageSize\r
+ *\r
+ * @return The superset of properties that "users" can specify.\r
+ *\r
+ **/\r
+ public Properties getUserCreateConglomPropList()\r
+ {\r
+ Properties ret_properties = \r
+ ConglomerateUtil.createUserRawStorePropertySet((Properties) null);\r
+\r
+ return(ret_properties);\r
+ }\r
+\r
+ /**\r
+ * Reveals whether the transaction has ever read or written data.\r
+ *\r
+ * @return true If the transaction has never read or written data.\r
+ *\r
+ **/\r
+ public boolean isIdle()\r
+ {\r
+ return rawtran.isIdle();\r
+ }\r
+\r
+ /**\r
+ * Reveals whether the transaction is a global or local transaction.\r
+ *\r
+ * @return true If the transaction was either started by \r
+ * AccessFactory.startXATransaction() or was morphed to a global\r
+ * transaction by calling \r
+ * AccessFactory.createXATransactionFromLocalTransaction().\r
+ * \r
+ * @see AccessFactory#startXATransaction\r
+ * @see TransactionController#createXATransactionFromLocalTransaction\r
+ *\r
+ **/\r
+ public boolean isGlobal()\r
+ {\r
+ return(rawtran.getGlobalId() != null);\r
+ }\r
+\r
+ /**\r
+ * Reveals whether the transaction is currently pristine.\r
+ *\r
+ * @return true If the transaction is Pristine.\r
+ *\r
+ * @see TransactionController#isPristine\r
+ **/\r
+ public boolean isPristine()\r
+ {\r
+ return rawtran.isPristine();\r
+ }\r
+\r
+ /**\r
+ * Convert a local transaction to a global transaction.\r
+ * <p>\r
+ * Get a transaction controller with which to manipulate data within\r
+ * the access manager. Tbis controller allows one to manipulate a \r
+ * global XA conforming transaction.\r
+ * <p>\r
+ * Must only be called a previous local transaction was created and exists\r
+ * in the context. Can only be called if the current transaction is in\r
+ * the idle state. Upon return from this call the old tc will be unusable,\r
+ * and all references to it should be dropped (it will have been implicitly\r
+ * destroy()'d by this call.\r
+ * <p>\r
+ * The (format_id, global_id, branch_id) triplet is meant to come exactly\r
+ * from a javax.transaction.xa.Xid. We don't use Xid so that the system\r
+ * can be delivered on a non-1.2 vm system and not require the javax classes\r
+ * in the path. \r
+ *\r
+ * @param format_id the format id part of the Xid - ie. Xid.getFormatId().\r
+ * @param global_id the global transaction identifier part of XID - ie.\r
+ * Xid.getGlobalTransactionId().\r
+ * @param branch_id The branch qualifier of the Xid - ie. \r
+ * Xid.getBranchQaulifier()\r
+ * \r
+ * @exception StandardException Standard exception policy.\r
+ * @see TransactionController\r
+ **/\r
+ public /* XATransactionController */ Object \r
+ createXATransactionFromLocalTransaction(\r
+ int format_id,\r
+ byte[] global_id,\r
+ byte[] branch_id)\r
+ throws StandardException\r
+ {\r
+\r
+ getRawStoreXact().createXATransactionFromLocalTransaction(\r
+ format_id, global_id, branch_id);\r
+\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ Bulk load into the conglomerate. Rows being loaded into the\r
+ conglomerate are not logged.\r
+\r
+ @param conglomId The conglomerate Id.\r
+\r
+ @param createConglom If true, the conglomerate is being created in the\r
+ same operation as the loadConglomerate. The enables further\r
+ optimization as recovery does not require page allocation to be\r
+ logged. \r
+\r
+ @param rowSource Where the rows come from.\r
+\r
+ @return true The number of rows loaded.\r
+\r
+ @exception StandardException Standard Derby Error Policy\r
+ */\r
+ public long loadConglomerate(\r
+ long conglomId,\r
+ boolean createConglom,\r
+ RowLocationRetRowSource rowSource)\r
+ throws StandardException\r
+ {\r
+ // Find the conglomerate.\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ // Load up the conglomerate with rows from the rowSource.\r
+ // Don't need to keep track of the conglomerate controller because load\r
+ // automatically closes it when it finished.\r
+ return(conglom.load(this, createConglom, rowSource));\r
+ }\r
+\r
+ /**\r
+ Use this for incremental load in the future. \r
+\r
+ @param conglomId the conglomerate Id\r
+ @param rowSource where the rows to be loaded comes from \r
+\r
+ @exception StandardException Standard Derby Error Policy\r
+ */\r
+ public void loadConglomerate(\r
+ long conglomId,\r
+ RowLocationRetRowSource rowSource)\r
+ throws StandardException\r
+ {\r
+ loadConglomerate(\r
+ conglomId, \r
+ false, // conglomerate is not being created \r
+ rowSource);\r
+ } \r
+\r
+ /**\r
+ * Log an operation and then action it in the context of this transaction.\r
+ * <p>\r
+ * This simply passes the operation to the RawStore which logs and does it.\r
+ * <p>\r
+ *\r
+ * @param operation the operation that is to be applied\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void logAndDo(Loggable operation)\r
+ throws StandardException\r
+ {\r
+ rawtran.logAndDo(operation);\r
+ }\r
+\r
+ public ConglomerateController openCompiledConglomerate(\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(static_info != null);\r
+ SanityManager.ASSERT(dynamic_info != null);\r
+ }\r
+ \r
+ // in the current implementation, only Conglomerate's are passed around\r
+ // as StaticCompiledOpenConglomInfo.\r
+\r
+ return(\r
+ openConglomerate(\r
+ (Conglomerate) static_info.getConglom(),\r
+ hold, open_mode, lock_level, isolation_level, \r
+ static_info, dynamic_info));\r
+ }\r
+\r
+ public ConglomerateController openConglomerate(\r
+ long conglomId, \r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ openConglomerate(\r
+ findExistingConglomerate(conglomId),\r
+ hold, open_mode, lock_level, isolation_level, \r
+ (StaticCompiledOpenConglomInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null));\r
+ }\r
+\r
+ public long findConglomid(long container_id)\r
+ throws StandardException\r
+ {\r
+ return(container_id);\r
+ }\r
+\r
+ public long findContainerid(long conglom_id)\r
+ throws StandardException\r
+ {\r
+ return(conglom_id);\r
+ }\r
+\r
+ /**\r
+ * Create a BackingStoreHashtable which contains all rows that qualify for\r
+ * the described scan.\r
+ **/\r
+ public BackingStoreHashtable createBackingStoreHashtableFromScan(\r
+ long conglomId,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] startKeyValue,\r
+ int startSearchOperator,\r
+ Qualifier qualifier[][],\r
+ DataValueDescriptor[] stopKeyValue,\r
+ int stopSearchOperator,\r
+ long max_rowcnt,\r
+ int[] key_column_numbers,\r
+ boolean remove_duplicates,\r
+ long estimated_rowcnt,\r
+ long max_inmemory_rowcnt,\r
+ int initialCapacity,\r
+ float loadFactor,\r
+ boolean collect_runtimestats,\r
+ boolean skipNullKeyColumns,\r
+ boolean keepAfterCommit)\r
+ throws StandardException\r
+ {\r
+ return (\r
+ new BackingStoreHashTableFromScan(\r
+ this,\r
+ conglomId,\r
+ open_mode,\r
+ lock_level,\r
+ isolation_level,\r
+ scanColumnList,\r
+ startKeyValue,\r
+ startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue,\r
+ stopSearchOperator,\r
+ max_rowcnt,\r
+ key_column_numbers,\r
+ remove_duplicates,\r
+ estimated_rowcnt,\r
+ max_inmemory_rowcnt,\r
+ initialCapacity,\r
+ loadFactor,\r
+ collect_runtimestats,\r
+ skipNullKeyColumns,\r
+ keepAfterCommit));\r
+ }\r
+\r
+\r
+ public GroupFetchScanController openGroupFetchScan(\r
+ long conglomId,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] startKeyValue,\r
+ int startSearchOperator,\r
+ Qualifier qualifier[][],\r
+ DataValueDescriptor[] stopKeyValue,\r
+ int stopSearchOperator)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if ((open_mode & \r
+ ~(TransactionController.OPENMODE_FORUPDATE | \r
+ TransactionController.OPENMODE_FOR_LOCK_ONLY |\r
+ TransactionController.OPENMODE_SECONDARY_LOCKED)) != 0)\r
+ SanityManager.THROWASSERT(\r
+ "Bad open mode to openScan:" + \r
+ Integer.toHexString(open_mode));\r
+\r
+ if (!(lock_level == MODE_RECORD |\r
+ lock_level == MODE_TABLE))\r
+ SanityManager.THROWASSERT(\r
+ "Bad lock level to openScan:" + lock_level);\r
+ }\r
+\r
+ // Find the conglomerate.\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ // Get a scan controller.\r
+ ScanManager sm = \r
+ conglom.openScan(\r
+ this, rawtran, hold, open_mode, \r
+ determine_lock_level(lock_level),\r
+ determine_locking_policy(lock_level, isolation_level),\r
+ isolation_level,\r
+ scanColumnList,\r
+ startKeyValue, startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue, stopSearchOperator,\r
+ (StaticCompiledOpenConglomInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null);\r
+\r
+ // Keep track of it so we can release on close.\r
+ scanControllers.add(sm);\r
+\r
+ return(sm);\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ * Purge all committed deleted rows from the conglomerate.\r
+ * <p>\r
+ * This call will purge committed deleted rows from the conglomerate,\r
+ * that space will be available for future inserts into the conglomerate.\r
+ * <p>\r
+ *\r
+ * @param conglomId Id of the conglomerate to purge.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void purgeConglomerate(\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ findExistingConglomerate(conglomId).purgeConglomerate(\r
+ this, \r
+ rawtran);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Return free space from the conglomerate back to the OS.\r
+ * <p>\r
+ * Returns free space from the conglomerate back to the OS. Currently\r
+ * only the sequential free pages at the "end" of the conglomerate can\r
+ * be returned to the OS.\r
+ * <p>\r
+ *\r
+ * @param conglomId Id of the conglomerate to purge.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void compressConglomerate(\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ findExistingConglomerate(conglomId).compressConglomerate(\r
+ this, \r
+ rawtran); \r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Compress table in place.\r
+ * <p>\r
+ * Returns a GroupFetchScanController which can be used to move rows\r
+ * around in a table, creating a block of free pages at the end of the\r
+ * table. The process will move rows from the end of the table toward\r
+ * the beginning. The GroupFetchScanController will return the \r
+ * old row location, the new row location, and the actual data of any\r
+ * row moved. Note that this scan only returns moved rows, not an\r
+ * entire set of rows, the scan is designed specifically to be\r
+ * used by either explicit user call of the SYSCS_ONLINE_COMPRESS_TABLE()\r
+ * procedure, or internal background calls to compress the table.\r
+ *\r
+ * The old and new row locations are returned so that the caller can\r
+ * update any indexes necessary.\r
+ *\r
+ * This scan always returns all collumns of the row.\r
+ * \r
+ * All inputs work exactly as in openScan(). The return is \r
+ * a GroupFetchScanController, which only allows fetches of groups\r
+ * of rows from the conglomerate.\r
+ * <p>\r
+ *\r
+ * @return The GroupFetchScanController to be used to fetch the rows.\r
+ *\r
+ * @param conglomId see openScan()\r
+ * @param hold see openScan()\r
+ * @param open_mode see openScan()\r
+ * @param lock_level see openScan()\r
+ * @param isolation_level see openScan()\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ *\r
+ * @see ScanController\r
+ * @see GroupFetchScanController\r
+ **/\r
+ public GroupFetchScanController defragmentConglomerate(\r
+ long conglomId,\r
+ boolean online,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if ((open_mode & \r
+ ~(TransactionController.OPENMODE_FORUPDATE | \r
+ TransactionController.OPENMODE_FOR_LOCK_ONLY |\r
+ TransactionController.OPENMODE_SECONDARY_LOCKED)) != 0)\r
+ SanityManager.THROWASSERT(\r
+ "Bad open mode to openScan:" + \r
+ Integer.toHexString(open_mode));\r
+\r
+ if (!(lock_level == MODE_RECORD |\r
+ lock_level == MODE_TABLE))\r
+ SanityManager.THROWASSERT(\r
+ "Bad lock level to openScan:" + lock_level);\r
+ }\r
+\r
+ // Find the conglomerate.\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ // Get a scan controller.\r
+ ScanManager sm = \r
+ conglom.defragmentConglomerate(\r
+ this, \r
+ rawtran, \r
+ hold, \r
+ open_mode, \r
+ determine_lock_level(lock_level),\r
+ determine_locking_policy(lock_level, isolation_level),\r
+ isolation_level);\r
+\r
+ // Keep track of it so we can release on close.\r
+ scanControllers.add(sm);\r
+\r
+ return(sm);\r
+ }\r
+\r
+\r
+ public ScanController openScan(\r
+ long conglomId,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] startKeyValue,\r
+ int startSearchOperator,\r
+ Qualifier qualifier[][],\r
+ DataValueDescriptor[] stopKeyValue,\r
+ int stopSearchOperator)\r
+ throws StandardException\r
+ {\r
+ return(\r
+ openScan(\r
+ findExistingConglomerate(conglomId),\r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ isolation_level,\r
+ scanColumnList,\r
+ startKeyValue,\r
+ startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue,\r
+ stopSearchOperator,\r
+ (StaticCompiledOpenConglomInfo) null,\r
+ (DynamicCompiledOpenConglomInfo) null));\r
+ }\r
+\r
+ public ScanController openCompiledScan(\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\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
+ // in the current implementation, only Conglomerate's are passed around\r
+ // as StaticCompiledOpenConglomInfo.\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(static_info != null);\r
+ SanityManager.ASSERT(dynamic_info != null);\r
+ SanityManager.ASSERT(\r
+ static_info instanceof StaticCompiledOpenConglomInfo);\r
+ SanityManager.ASSERT(\r
+ dynamic_info instanceof DynamicCompiledOpenConglomInfo);\r
+ }\r
+\r
+ return(\r
+ openScan(\r
+ ((Conglomerate) static_info.getConglom()),\r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ isolation_level,\r
+ scanColumnList,\r
+ startKeyValue,\r
+ startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue,\r
+ stopSearchOperator,\r
+ static_info,\r
+ dynamic_info));\r
+ }\r
+\r
+\r
+ /**\r
+ * Return an open StoreCostController for the given conglomid.\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
+ *\r
+ * @return The open StoreCostController.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate to open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ *\r
+ * @see StoreCostController\r
+ **/\r
+ public StoreCostController openStoreCost(\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ // Find the conglomerate.\r
+ Conglomerate conglom = findExistingConglomerate(conglomId);\r
+\r
+ // Get a scan controller.\r
+ StoreCostController scc = conglom.openStoreCost(this, rawtran);\r
+\r
+ return(scc);\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#createSort\r
+ @exception StandardException Standard error policy.\r
+ **/\r
+ public long createSort(\r
+ Properties implParameters,\r
+ DataValueDescriptor[] template,\r
+ ColumnOrdering columnOrdering[],\r
+ SortObserver sortObserver,\r
+ boolean alreadyInOrder,\r
+ long estimatedRows,\r
+ int estimatedRowSize)\r
+ throws StandardException\r
+ {\r
+ // Get the implementation type from the parameters.\r
+ // XXX (nat) need to figure out how to select sort implementation.\r
+ String implementation = null;\r
+ if (implParameters != null)\r
+ implementation = \r
+ implParameters.getProperty(AccessFactoryGlobals.IMPL_TYPE);\r
+\r
+ if (implementation == null)\r
+ implementation = AccessFactoryGlobals.SORT_EXTERNAL;\r
+\r
+ // Find the appropriate factory for the desired implementation.\r
+ MethodFactory mfactory;\r
+ mfactory = accessmanager.findMethodFactoryByImpl(implementation);\r
+ if (mfactory == null || !(mfactory instanceof SortFactory))\r
+ {\r
+ throw(\r
+ StandardException.newException(\r
+ SQLState.AM_NO_FACTORY_FOR_IMPLEMENTATION, implementation));\r
+ }\r
+ SortFactory sfactory = (SortFactory) mfactory;\r
+\r
+ // Decide what segment the sort should use.\r
+ int segment = 0; // XXX (nat) sorts always in segment 0\r
+\r
+ // Create the sort.\r
+ Sort sort = sfactory.createSort(this, segment,\r
+ implParameters, template, columnOrdering,\r
+ sortObserver, alreadyInOrder, estimatedRows, \r
+ estimatedRowSize);\r
+\r
+ // Add the sort to the sorts vector\r
+ if (sorts == null) {\r
+ sorts = new ArrayList();\r
+ freeSortIds = new ArrayList();\r
+ }\r
+\r
+ int sortid;\r
+ if (freeSortIds.isEmpty()) {\r
+ // no free identifiers, add sort at the end\r
+ sortid = sorts.size();\r
+ sorts.add(sort);\r
+ } else {\r
+ // reuse a sort identifier\r
+ sortid = ((Integer) freeSortIds.remove(freeSortIds.size() - 1))\r
+ .intValue();\r
+ sorts.set(sortid, sort);\r
+ }\r
+\r
+ return sortid;\r
+ }\r
+\r
+ /**\r
+ Drop a sort. \r
+ <p>\r
+ Drop a sort created by a call to createSort() within the current \r
+ transaction (sorts are automatically "dropped" at the end of a \r
+ transaction. This call should only be made after all openSortScan()'s\r
+ and openSort()'s have been closed.\r
+ <p>\r
+\r
+ @param sortid The identifier of the sort to drop, as returned from \r
+ createSort.\r
+ @exception StandardException From a lower-level exception.\r
+ **/\r
+ public void dropSort(long sortid) \r
+ throws StandardException\r
+ {\r
+ // should call close on the sort.\r
+ Sort sort = (Sort) sorts.get((int) sortid);\r
+\r
+ if (sort != null)\r
+ {\r
+ sort.drop(this);\r
+ sorts.set((int) sortid, null);\r
+ freeSortIds.add(ReuseFactory.getInteger((int) sortid));\r
+ }\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#getProperty\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public Serializable getProperty(\r
+ String key) \r
+ throws StandardException\r
+ {\r
+ return \r
+ (accessmanager.getTransactionalProperties().getProperty(this, key));\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#getPropertyDefault\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public Serializable getPropertyDefault(\r
+ String key) \r
+ throws StandardException\r
+ {\r
+ return \r
+ (accessmanager.getTransactionalProperties().getPropertyDefault(this, key));\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#setProperty\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void setProperty(\r
+ String key, \r
+ Serializable value,\r
+ boolean dbOnlyProperty) \r
+ throws StandardException\r
+ {\r
+ accessmanager.getTransactionalProperties().setProperty(\r
+ this, key, value, dbOnlyProperty);\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#setProperty\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void setPropertyDefault(\r
+ String key, \r
+ Serializable value) \r
+ throws StandardException\r
+ {\r
+ accessmanager.getTransactionalProperties().setPropertyDefault(\r
+ this, key, value);\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#propertyDefaultIsVisible\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean propertyDefaultIsVisible(String key) throws StandardException\r
+ {\r
+ return accessmanager.getTransactionalProperties().propertyDefaultIsVisible(this,key);\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#getProperties\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public Properties getProperties() \r
+ throws StandardException\r
+ {\r
+ return accessmanager.getTransactionalProperties().getProperties(this);\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#openSort\r
+ @exception StandardException Standard error policy.\r
+ **/\r
+ public SortController openSort(long id)\r
+ throws StandardException\r
+ {\r
+ Sort sort;\r
+\r
+ // Find the sort in the sorts list, throw an error\r
+ // if it doesn't exist.\r
+ if (sorts == null || id >= sorts.size()\r
+ || (sort = ((Sort) sorts.get((int) id))) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_SORT, new Long(id));\r
+ }\r
+\r
+ // Open it.\r
+ SortController sc = sort.open(this);\r
+\r
+ // Keep track of it so we can release on close.\r
+ if (sortControllers == null)\r
+ sortControllers = new ArrayList();\r
+ sortControllers.add(sc);\r
+\r
+ return sc;\r
+ }\r
+\r
+ /**\r
+ * Return an open SortCostController.\r
+ * <p>\r
+ * Return an open SortCostController which can be used to ask about \r
+ * the estimated costs of SortController() operations.\r
+ * <p>\r
+ *\r
+ * @return The open StoreCostController.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ *\r
+ * @see StoreCostController\r
+ **/\r
+ public SortCostController openSortCostController(\r
+ Properties implParameters)\r
+ throws StandardException\r
+ {\r
+ // Get the implementation type from the parameters.\r
+ // RESOLVE (mikem) need to figure out how to select sort implementation.\r
+ String implementation = null;\r
+\r
+ if (implementation == null)\r
+ implementation = AccessFactoryGlobals.SORT_EXTERNAL;\r
+\r
+ // Find the appropriate factory for the desired implementation.\r
+ MethodFactory mfactory;\r
+ mfactory = accessmanager.findMethodFactoryByImpl(implementation);\r
+ if (mfactory == null || !(mfactory instanceof SortFactory))\r
+ {\r
+ throw(\r
+ StandardException.newException(\r
+ SQLState.AM_NO_FACTORY_FOR_IMPLEMENTATION, implementation));\r
+ }\r
+ SortFactory sfactory = (SortFactory) mfactory;\r
+\r
+ // open sort cost controller\r
+ return(sfactory.openSortCostController());\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#openSortScan\r
+ @exception StandardException Standard error policy.\r
+ **/\r
+ public ScanController openSortScan(\r
+ long id,\r
+ boolean hold)\r
+ throws StandardException\r
+ {\r
+ Sort sort;\r
+\r
+ // Find the sort in the sorts list, throw an error\r
+ // if it doesn't exist.\r
+ if (sorts == null || id >= sorts.size()\r
+ || (sort = ((Sort) sorts.get((int) id))) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_SORT, new Long(id));\r
+ }\r
+\r
+ // Open a scan on it.\r
+ ScanController sc = sort.openSortScan(this, hold);\r
+\r
+ // Keep track of it so we can release on close.\r
+ scanControllers.add(sc);\r
+\r
+ return sc;\r
+ }\r
+\r
+ /**\r
+ @see TransactionController#openSortRowSource\r
+ @exception StandardException Standard error policy.\r
+ **/\r
+ public RowLocationRetRowSource openSortRowSource(long id) \r
+ throws StandardException\r
+ {\r
+ Sort sort;\r
+\r
+ // Find the sort in the sorts list, throw an error\r
+ // if it doesn't exist.\r
+ if (sorts == null || id >= sorts.size()\r
+ || (sort = ((Sort) sorts.get((int) id))) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.AM_NO_SUCH_SORT, new Long(id));\r
+ }\r
+\r
+ // Open a scan row source on it.\r
+ ScanControllerRowSource sc = sort.openSortRowSource(this);\r
+\r
+ // Keep track of it so we can release on close.\r
+ scanControllers.add(sc);\r
+\r
+ return sc;\r
+ }\r
+\r
+\r
+ public void commit()\r
+ throws StandardException\r
+ {\r
+ this.closeControllers(false /* don't close held controllers */ );\r
+\r
+ rawtran.commit();\r
+\r
+ alterTableCallMade = false;\r
+\r
+ return;\r
+ }\r
+\r
+ public DatabaseInstant commitNoSync(int commitflag)\r
+ throws StandardException\r
+ {\r
+ this.closeControllers(false /* don't close held controllers */ );\r
+ return rawtran.commitNoSync(commitflag);\r
+ }\r
+\r
+ public void abort()\r
+ throws StandardException\r
+ {\r
+ \r
+ if (alterTableCallMade)\r
+ {\r
+ accessmanager.conglomCacheInvalidate();\r
+ alterTableCallMade = false;\r
+ }\r
+ this.closeControllers(true /* close all controllers */ );\r
+ rawtran.abort();\r
+\r
+ if (parent_tran != null)\r
+ parent_tran.abort();\r
+ }\r
+\r
+ /**\r
+ * Get the context manager that the transaction was created with.\r
+ * <p>\r
+ *\r
+ * @return The context manager that the transaction was created with.\r
+ * **/\r
+ public ContextManager getContextManager()\r
+ {\r
+ return(context.getContextManager());\r
+ }\r
+\r
+ public int setSavePoint(String name, Object kindOfSavepoint)\r
+ throws StandardException\r
+ {\r
+ return rawtran.setSavePoint(name, kindOfSavepoint);\r
+ }\r
+\r
+ public int releaseSavePoint(String name, Object kindOfSavepoint)\r
+ throws StandardException\r
+ {\r
+ return rawtran.releaseSavePoint(name, kindOfSavepoint);\r
+ }\r
+\r
+ public int rollbackToSavePoint(String name, boolean close_controllers, Object kindOfSavepoint)\r
+ throws StandardException\r
+ {\r
+ if (close_controllers)\r
+ this.closeControllers(true /* close all controllers */ );\r
+ return rawtran.rollbackToSavePoint(name, kindOfSavepoint);\r
+ }\r
+\r
+ public void destroy()\r
+ {\r
+ try\r
+ {\r
+ this.closeControllers(true /* close all controllers */);\r
+ \r
+ // If there's a transaction, abort it.\r
+ if (rawtran != null) {\r
+ rawtran.destroy();\r
+ rawtran = null;\r
+ }\r
+ \r
+\r
+ // If there's a context, pop it.\r
+ if (context != null)\r
+ context.popMe();\r
+ context = null;\r
+\r
+ accessmanager = null;\r
+ tempCongloms = null;\r
+ }\r
+ catch (StandardException e)\r
+ {\r
+ // XXX (nat) really need to figure out what to do\r
+ // if there's an exception while aborting.\r
+ rawtran = null;\r
+ context = null;\r
+ accessmanager = null;\r
+ tempCongloms = null;\r
+ }\r
+ }\r
+\r
+ public boolean anyoneBlocked()\r
+ {\r
+ return rawtran.anyoneBlocked();\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing the XATransactionController interface.\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * This method is called to commit the current XA global transaction.\r
+ * <p>\r
+ * RESOLVE - how do we map to the "right" XAExceptions.\r
+ * <p>\r
+ *\r
+ * @param onePhase If true, the resource manager should use a one-phase\r
+ * commit protocol to commit the work done on behalf of \r
+ * current xid.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void xa_commit(\r
+ boolean onePhase)\r
+ throws StandardException\r
+ {\r
+ rawtran.xa_commit(onePhase);\r
+ }\r
+\r
+ /**\r
+ * This method is called to ask the resource manager to prepare for\r
+ * a transaction commit of the transaction specified in xid.\r
+ * <p>\r
+ *\r
+ * @return A value indicating the resource manager's vote on the\r
+ * the outcome of the transaction. The possible values\r
+ * are: XA_RDONLY or XA_OK. If the resource manager wants\r
+ * to roll back the transaction, it should do so by \r
+ * throwing an appropriate XAException in the prepare\r
+ * method.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public int xa_prepare()\r
+ throws StandardException\r
+ {\r
+ return(rawtran.xa_prepare());\r
+ }\r
+\r
+ /**\r
+ * rollback the current global transaction.\r
+ * <p>\r
+ * The given transaction is roll'ed back and it's history is not\r
+ * maintained in the transaction table or long term log.\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void xa_rollback()\r
+ throws StandardException\r
+ {\r
+ rawtran.xa_rollback();\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods of TransactionManager interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Add to the list of post commit work.\r
+ * <p>\r
+ * Add to the list of post commit work that may be processed after this\r
+ * transaction commits. If this transaction aborts, then the post commit\r
+ * work list will be thrown away. No post commit work will be taken out\r
+ * on a rollback to save point.\r
+ * <p>\r
+ * This routine simply delegates the work to the Rawstore transaction.\r
+ *\r
+ * @param work The post commit work to do.\r
+ *\r
+ **/\r
+ public void addPostCommitWork(Serviceable work)\r
+ {\r
+ rawtran.addPostCommitWork(work);\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Check to see if a database has been upgraded to the required\r
+ * level in order to use a store feature.\r
+ *\r
+ * @param requiredMajorVersion required database Engine major version\r
+ * @param requiredMinorVersion required database Engine minor version\r
+ * @param feature Non-null to throw an exception, null to \r
+ * return the state of the version match.\r
+ *\r
+ * @return <code> true </code> if the database has been upgraded to \r
+ * the required level, <code> false </code> otherwise.\r
+ *\r
+ * @exception StandardException \r
+ * if the database is not at the require version \r
+ * when <code>feature</code> feature is \r
+ * not <code> null </code>. \r
+ */\r
+ public boolean checkVersion(\r
+ int requiredMajorVersion, \r
+ int requiredMinorVersion, \r
+ String feature) \r
+ throws StandardException\r
+ {\r
+ return(\r
+ accessmanager.getRawStore().checkVersion(\r
+ requiredMajorVersion, requiredMinorVersion, feature));\r
+ }\r
+\r
+ /**\r
+ * The ConglomerateController.close() method has been called on \r
+ * "conglom_control".\r
+ * <p>\r
+ * Take whatever cleanup action is appropriate to a closed \r
+ * conglomerateController. It is likely this routine will remove\r
+ * references to the ConglomerateController object that it was maintaining\r
+ * for cleanup purposes.\r
+ *\r
+ **/\r
+ public void closeMe(ConglomerateController conglom_control)\r
+ {\r
+ conglomerateControllers.remove(conglom_control);\r
+ }\r
+\r
+ /**\r
+ * The SortController.close() method has been called on "sort_control".\r
+ * <p>\r
+ * Take whatever cleanup action is appropriate to a closed \r
+ * sortController. It is likely this routine will remove\r
+ * references to the SortController object that it was maintaining\r
+ * for cleanup purposes.\r
+ **/\r
+ public void closeMe(SortController sort_control)\r
+ {\r
+ sortControllers.remove(sort_control);\r
+ }\r
+\r
+ /**\r
+ * The ScanManager.close() method has been called on "scan".\r
+ * <p>\r
+ * Take whatever cleanup action is appropriate to a closed scan. It is\r
+ * likely this routine will remove references to the scan object that it\r
+ * was maintaining for cleanup purposes.\r
+ *\r
+ **/\r
+ public void closeMe(ScanManager scan)\r
+ {\r
+ scanControllers.remove(scan);\r
+ }\r
+\r
+ /**\r
+ * Get reference to access factory which started this transaction.\r
+ * <p>\r
+ *\r
+ * @return The AccessFactory which started this transaction.\r
+ *\r
+ **/\r
+ public AccessFactory getAccessManager()\r
+ {\r
+ return(accessmanager);\r
+ }\r
+\r
+ /**\r
+ * Get an Internal transaction.\r
+ * <p>\r
+ * Start an internal transaction. An internal transaction is a completely\r
+ * separate transaction from the current user transaction. All work done\r
+ * in the internal transaction must be physical (ie. it can be undone \r
+ * physically by the rawstore at the page level, rather than logically \r
+ * undone like btree insert/delete operations). The rawstore guarantee's\r
+ * that in the case of a system failure all open Internal transactions are\r
+ * first undone in reverse order, and then other transactions are undone\r
+ * in reverse order.\r
+ * <p>\r
+ * Internal transactions are meant to implement operations which, if \r
+ * interupted before completion will cause logical operations like tree\r
+ * searches to fail. This special undo order insures that the state of\r
+ * the tree is restored to a consistent state before any logical undo \r
+ * operation which may need to search the tree is performed.\r
+ * <p>\r
+ *\r
+ * @return The new internal transaction.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public TransactionManager getInternalTransaction()\r
+ throws StandardException\r
+ {\r
+ // Get the context manager.\r
+ ContextManager cm = getContextManager();\r
+\r
+ // Allocate a new transaction no matter what.\r
+ \r
+ // Create a transaction, make a context for it, and push the context.\r
+ // Note this puts the raw store transaction context\r
+ // above the access context, which is required for\r
+ // error handling assumptions to be correct.\r
+ \r
+ Transaction rawtran = \r
+ accessmanager.getRawStore().startInternalTransaction(cm);\r
+ RAMTransaction rt = new RAMTransaction(accessmanager, rawtran, null);\r
+ RAMTransactionContext rtc = \r
+ new RAMTransactionContext(\r
+ cm, AccessFactoryGlobals.RAMXACT_INTERNAL_CONTEXT_ID, \r
+ rt, true /*abortAll */);\r
+\r
+ rawtran.setDefaultLockingPolicy(\r
+ accessmanager.getDefaultLockingPolicy());\r
+\r
+ return(rt);\r
+ }\r
+\r
+ /**\r
+ * Get an nested user transaction.\r
+ * <p>\r
+ * A nested user can be used exactly as any other TransactionController,\r
+ * except as follows. For this discussion let the parent transaction \r
+ * be the transaction used to make the getNestedUserTransaction(), and\r
+ * let the child transaction be the transaction returned by the \r
+ * getNestedUserTransaction() call.\r
+ * <p>\r
+ * The nesting is limited to one level deep. An exception will be thrown\r
+ * if a subsequent getNestedUserTransaction() is called on the child\r
+ * transaction.\r
+ * <p>\r
+ * The locks in the child transaction will be compatible with the locks\r
+ * of the parent transaction.\r
+ * <p>\r
+ * A commit in the child transaction will release locks associated with\r
+ * the child transaction only, work can continue in the parent transaction\r
+ * at this point. \r
+ * <p>\r
+ * Any abort of the child transaction will result in an abort of both\r
+ * the child transaction and parent transaction.\r
+ * <p>\r
+ * A TransactionController.destroy() call should be made on the child\r
+ * transaction once all child work is done, and the caller wishes to \r
+ * continue work in the parent transaction.\r
+ * <p>\r
+ * Nested internal transactions are meant to be used to implement \r
+ * system work necessary to commit as part of implementing a user's\r
+ * request, but where holding the lock for the duration of the user\r
+ * transaction is not acceptable. 2 examples of this are system catalog\r
+ * read locks accumulated while compiling a plan, and auto-increment.\r
+ * <p>\r
+ *\r
+ * @return The new nested user transaction.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public TransactionController startNestedUserTransaction(boolean readOnly)\r
+ throws StandardException\r
+ {\r
+ // Get the context manager.\r
+ ContextManager cm = getContextManager();\r
+\r
+ // Allocate a new transaction no matter what.\r
+ \r
+ // Create a transaction, make a context for it, and push the context.\r
+ // Note this puts the raw store transaction context\r
+ // above the access context, which is required for\r
+ // error handling assumptions to be correct.\r
+ //\r
+ // Note that the nested transaction inherits the compatibility space\r
+ // from "this", thus the new transaction shares the compatibility space\r
+ // of the current transaction.\r
+ \r
+\r
+ Transaction child_rawtran = \r
+ ((readOnly) ?\r
+ accessmanager.getRawStore().startNestedReadOnlyUserTransaction(\r
+ getLockSpace(), cm,\r
+ AccessFactoryGlobals.NESTED_READONLY_USER_TRANS) :\r
+ accessmanager.getRawStore().startNestedUpdateUserTransaction(\r
+ cm, AccessFactoryGlobals.NESTED_UPDATE_USER_TRANS));\r
+\r
+ RAMTransaction rt = \r
+ new RAMTransaction(accessmanager, child_rawtran, this);\r
+\r
+ RAMTransactionContext rtc = \r
+ new RAMTransactionContext(\r
+ cm, \r
+ AccessFactoryGlobals.RAMXACT_CHILD_CONTEXT_ID,\r
+ rt, true /*abortAll */);\r
+\r
+ child_rawtran.setDefaultLockingPolicy(\r
+ accessmanager.getDefaultLockingPolicy());\r
+\r
+ /*\r
+ System.out.println("returning nested xact: " + rt + \r
+ "child_rawtran = " + child_rawtran); \r
+ */\r
+\r
+ return(rt);\r
+ }\r
+\r
+ /**\r
+ * Get the Transaction from the Transaction manager.\r
+ * <p>\r
+ * Access methods often need direct access to the "Transaction" - ie. the\r
+ * raw store transaction, so give access to it.\r
+ *\r
+ * @return The raw store transaction.\r
+ *\r
+ **/\r
+ public Transaction getRawStoreXact()\r
+ {\r
+ return(rawtran);\r
+ }\r
+\r
+\r
+ /**\r
+ * Do work necessary to maintain the current position in all the scans.\r
+ * <p>\r
+ * The latched page in the conglomerate "congomid" is changing, do\r
+ * whatever is necessary to maintain the current position of all the\r
+ * scans open in this transaction.\r
+ * <p>\r
+ * For some conglomerates this may be a no-op.\r
+ * <p>\r
+ *\r
+ * @param conglom Conglomerate being changed.\r
+ * @param page Page in the conglomerate being changed.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void saveScanPositions(Conglomerate conglom, Page page)\r
+ throws StandardException\r
+ {\r
+ for (Iterator it = scanControllers.iterator(); it.hasNext(); )\r
+ {\r
+ Object o = it.next();\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // The following debugging code is here because the following \r
+ // (ScanManager) cast is occasionally causing a \r
+ // java.lang.ClassCastException.\r
+\r
+ if (!(o instanceof ScanManager))\r
+ {\r
+ HeaderPrintWriter istream = Monitor.getStream();\r
+ \r
+ if (o == null)\r
+ istream.println("next element was null\n");\r
+ else\r
+ istream.println("non ScanManager on list: " + o);\r
+\r
+ istream.println(\r
+ "Current list of open scans: " + debugOpened());\r
+ }\r
+ }\r
+ ScanManager sm = (ScanManager) o;\r
+ sm.savePosition(conglom, page);\r
+ }\r
+ }\r
+\r
+ public FileResource getFileHandler() {\r
+ return rawtran.getFileHandler();\r
+ }\r
+\r
+ /**\r
+ * Return an object that when used as the compatibility space,\r
+ * <strong>and</strong> the object returned when calling\r
+ * <code>getOwner()</code> on that object is used as group for a lock\r
+ * request, guarantees that the lock will be removed on a commit or an\r
+ * abort.\r
+ */\r
+ public CompatibilitySpace getLockSpace()\r
+ {\r
+ return rawtran.getCompatibilitySpace();\r
+ }\r
+\r
+ /**\r
+ * Get string id of the transaction.\r
+ * <p>\r
+ * This transaction "name" will be the same id which is returned in\r
+ * the TransactionInfo information, used by the lock and transaction\r
+ * vti's to identify transactions.\r
+ * <p>\r
+ * Although implementation specific, the transaction id is usually a number\r
+ * which is bumped every time a commit or abort is issued.\r
+ * <p>\r
+ * For now return the toString() method, which does what we want. Later\r
+ * if that is not good enough we can add public raw tran interfaces to\r
+ * get exactly what we want.\r
+ *\r
+ * @return The a string which identifies the transaction. \r
+ **/\r
+ public String getTransactionIdString()\r
+ {\r
+ return(rawtran.toString());\r
+ }\r
+\r
+\r
+ /**\r
+ * Get string id of the transaction that would be when the Transaction\r
+ * is IN active state.\r
+ **/\r
+ public String getActiveStateTxIdString()\r
+ {\r
+ return(rawtran.getActiveStateTxIdString());\r
+ }\r
+\r
+\r
+ public String toString()\r
+ {\r
+ String str = null;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ str = "rawtran = " + rawtran;\r
+ }\r
+ return(str);\r
+ }\r
+}\r