Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / execute / RowChangerImpl.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java
new file mode 100644 (file)
index 0000000..db23cd5
--- /dev/null
@@ -0,0 +1,596 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.RowChangerImpl\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.sql.execute;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.StatementContext;\r
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.ExecutionContext;\r
+import org.apache.derby.iapi.sql.execute.RowChanger;\r
+import org.apache.derby.iapi.sql.execute.ExecutionFactory;\r
+import org.apache.derby.iapi.sql.execute.TemporaryRowHolder;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+\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.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import java.util.Vector;\r
+\r
+/**\r
+  Perform row at a time DML operations of tables and maintain indexes.\r
+  */\r
+class RowChangerImpl   implements      RowChanger\r
+{\r
+       boolean isOpen = false;\r
+\r
+       //\r
+       //Stuff provided to the constructor\r
+       boolean[] fixOnUpdate = null;\r
+       long heapConglom;\r
+       DynamicCompiledOpenConglomInfo heapDCOCI;\r
+       StaticCompiledOpenConglomInfo heapSCOCI;\r
+       long[] indexCIDS = null;\r
+       DynamicCompiledOpenConglomInfo[] indexDCOCIs;\r
+       StaticCompiledOpenConglomInfo[] indexSCOCIs;\r
+       IndexRowGenerator[] irgs = null;\r
+       Activation              activation;\r
+       TransactionController   tc;\r
+       FormatableBitSet        changedColumnBitSet;    \r
+       FormatableBitSet        baseRowReadList;        \r
+       private int[]           baseRowReadMap; //index=heap column, value=input row column.\r
+       int[]           changedColumnIds;\r
+       TemporaryRowHolderImpl  rowHolder;\r
+       \r
+       // for error reporting.\r
+       String[]        indexNames;\r
+\r
+       //\r
+       //Stuff filled in by open\r
+       private ConglomerateController baseCC;\r
+       private RowLocation     baseRowLocation;\r
+       private IndexSetChanger isc;\r
+\r
+       // a row array with all non-updated columns compacted out\r
+       private DataValueDescriptor[] sparseRowArray;\r
+       private int[] partialChangedColumnIds;\r
+       \r
+       /**\r
+         Create a new RowChanger for performing update and delete operations\r
+         based on partial before and after rows.\r
+\r
+         @param heapConglom Conglomerate # for the heap\r
+         @param heapSCOCI      SCOCI for heap.\r
+         @param heapDCOCI      DCOCI for heap\r
+         @param irgs the IndexRowGenerators for the table's indexes. We use\r
+           positions in this array as local id's for indexes. To support updates,\r
+           only indexes that change need be included.\r
+         @param indexCIDS the conglomerateids for the table's idexes. \r
+               indexCIDS[ix] corresponds to the same index as irgs[ix].\r
+         @param indexSCOCIs the SCOCIs for the table's idexes. \r
+               indexSCOCIs[ix] corresponds to the same index as irgs[ix].\r
+         @param indexDCOCIs the DCOCIs for the table's idexes. \r
+               indexDCOCIs[ix] corresponds to the same index as irgs[ix].\r
+         @param numberOfColumns        Number of columns in partial write row.\r
+         @param changedColumnIdsInput array of 1 based ints indicating the columns\r
+               to be updated.  Only used for updates\r
+         @param tc the transaction controller\r
+         @param baseRowReadList bit set of columns read from base row. 1 based.\r
+         @param baseRowReadMap BaseRowReadMap[heapColId]->ReadRowColumnId. (0 based)\r
+         @exception StandardException          Thrown on error\r
+         */\r
+       public RowChangerImpl(\r
+                          long heapConglom,\r
+                          StaticCompiledOpenConglomInfo heapSCOCI,\r
+                          DynamicCompiledOpenConglomInfo heapDCOCI,\r
+                          IndexRowGenerator[] irgs,\r
+                          long[] indexCIDS,\r
+                          StaticCompiledOpenConglomInfo[] indexSCOCIs,\r
+                          DynamicCompiledOpenConglomInfo[] indexDCOCIs,\r
+                          int numberOfColumns,\r
+                          int[] changedColumnIdsInput,\r
+                          TransactionController tc,\r
+                          FormatableBitSet     baseRowReadList,\r
+                          int[] baseRowReadMap,\r
+                          Activation activation)\r
+                throws StandardException\r
+       {\r
+               this.heapConglom = heapConglom;\r
+               this.heapSCOCI = heapSCOCI;\r
+               this.heapDCOCI = heapDCOCI;\r
+               this.irgs = irgs;\r
+               this.indexCIDS = indexCIDS;\r
+               this.indexSCOCIs = indexSCOCIs;\r
+               this.indexDCOCIs = indexDCOCIs;\r
+               this.tc = tc;\r
+               this.baseRowReadList = baseRowReadList;\r
+               this.baseRowReadMap = baseRowReadMap;\r
+               this.activation = activation;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(indexCIDS != null, "indexCIDS is null");\r
+               }\r
+\r
+               /*\r
+               ** Construct the update column FormatableBitSet.\r
+               ** It is 0 based as opposed to the 1 based\r
+               ** changed column ids.\r
+               */\r
+               if (changedColumnIdsInput != null)\r
+               {\r
+                       /*\r
+                       ** Sometimes replication does not have columns\r
+                       ** in sorted order, and basically needs to\r
+                       ** have the changed columns in non-sorted order.\r
+                       ** So sort them first if needed.\r
+                       */\r
+                       changedColumnIds = RowUtil.inAscendingOrder(changedColumnIdsInput) ?\r
+                                                               changedColumnIdsInput : sortArray(changedColumnIdsInput);\r
+\r
+                       /*\r
+                       ** Allocate the row array we are going to use during\r
+                       ** update here, to avoid extra work.  setup\r
+                       ** the FormatableBitSet of columns being updated.  See updateRow\r
+                       ** for the use.\r
+                       **\r
+                       ** changedColumnIds is guaranteed to be in order, so just take\r
+                       ** the last column number in the array to be the highest\r
+                       ** column number.\r
+                       */\r
+                       sparseRowArray =\r
+                               new DataValueDescriptor[changedColumnIds[changedColumnIds.length - 1] + 1];\r
+                       changedColumnBitSet = new FormatableBitSet(numberOfColumns);\r
+                       for (int i = 0; i < changedColumnIds.length; i++)\r
+                       {\r
+                               // make sure changedColumnBitSet can accomodate bit \r
+                               // changedColumnIds[i] - 1 \r
+                               changedColumnBitSet.grow(changedColumnIds[i]);\r
+                               changedColumnBitSet.set(changedColumnIds[i] - 1);\r
+                       }\r
+\r
+                       /*\r
+                       ** If we have a read map and a write map, we\r
+                       ** need to have a way to map the changed column\r
+                       ** ids to be relative to the read map.\r
+                       */\r
+                       if (baseRowReadList != null)\r
+                       {\r
+                               partialChangedColumnIds = new int[changedColumnIds.length];\r
+                               int partialColumnNumber = 1;\r
+                               int currentColumn = 0;\r
+                               for (int i = 0; i < changedColumnIds.length; i++)\r
+                               {\r
+                                       for (; currentColumn < changedColumnIds[i]; currentColumn++)\r
+                                       {\r
+                                               if (baseRowReadList.get(currentColumn))\r
+                                               {\r
+                                                       partialColumnNumber++;\r
+                                               }\r
+                                       }\r
+                                       partialChangedColumnIds[i] = partialColumnNumber;\r
+                               }\r
+                       }       \r
+               }\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(indexCIDS != null, "indexCIDS is null");\r
+               }\r
+               \r
+       }\r
+\r
+       /**\r
+        * Set the row holder for this changer to use.\r
+        * If the row holder is set, it wont bother \r
+        * saving copies of rows needed for deferred\r
+        * processing.  Also, it will never close the\r
+        * passed in rowHolder.\r
+        *\r
+        * @param rowHolder     the TemporaryRowHolder\r
+        */\r
+       public void setRowHolder(TemporaryRowHolder rowHolder)\r
+       {\r
+               this.rowHolder = (TemporaryRowHolderImpl)rowHolder;\r
+       }\r
+\r
+       /**\r
+        * @see RowChanger#setIndexNames\r
+        */\r
+       public void setIndexNames(String[] indexNames)\r
+       {\r
+               this.indexNames = indexNames;\r
+       }\r
+\r
+       /**\r
+         Open this RowChanger.\r
+\r
+         <P>Note to avoid the cost of fixing indexes that do not\r
+         change during update operations use openForUpdate().\r
+         @param lockMode       The lock mode to use\r
+                                                       (row or table, see TransactionController)\r
+\r
+         @exception StandardException thrown on failure to convert\r
+         */\r
+       public void open(int lockMode)\r
+                throws StandardException\r
+       {\r
+               open(lockMode, true);\r
+       }\r
+\r
+       /**\r
+        * @inheritDoc\r
+        */\r
+       public void open(int lockMode, boolean wait)\r
+                throws StandardException\r
+       {\r
+               //\r
+               //We open for update but say to fix every index on\r
+               //updates.\r
+               if (fixOnUpdate == null)\r
+               {\r
+                       fixOnUpdate = new boolean[irgs.length];\r
+                       for (int ix = 0; ix < irgs.length; ix++)\r
+                               fixOnUpdate[ix] = true;\r
+               }\r
+               openForUpdate(fixOnUpdate, lockMode, wait);\r
+       }\r
+\r
+       /**\r
+         Open this RowChanger to avoid fixing indexes that do not change\r
+         during update operations. \r
+\r
+         @param fixOnUpdate fixOnUpdat[ix] == true ==> fix index 'ix' on\r
+         an update operation.\r
+         @param lockMode       The lock mode to use\r
+                                                       (row or table, see TransactionController)\r
+         @param wait           If true, then the caller wants to wait for locks. False will be\r
+                                                       when we using a nested user xaction - we want to timeout right away\r
+                                                       if the parent holds the lock.  (bug 4821)\r
+\r
+         @exception StandardException thrown on failure to convert\r
+         */\r
+       public void openForUpdate(\r
+                                 boolean[] fixOnUpdate, int lockMode, boolean wait\r
+                         )\r
+                throws StandardException\r
+       {\r
+               LanguageConnectionContext lcc = null;\r
+\r
+               if (SanityManager.DEBUG)\r
+                   SanityManager.ASSERT( ! isOpen, "RowChanger already open");\r
+               \r
+               if (activation != null)\r
+               {\r
+                       lcc = activation.getLanguageConnectionContext();\r
+               }\r
+\r
+               /* Isolation level - translate from language to store */\r
+               int isolationLevel;\r
+               if (lcc == null)\r
+               {\r
+                       isolationLevel = ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL;\r
+               }\r
+               else\r
+               {\r
+                       isolationLevel = lcc.getCurrentIsolationLevel();\r
+               }\r
+\r
+\r
+               switch (isolationLevel)\r
+               {\r
+                       // Even though we preserve the isolation level at READ UNCOMMITTED,\r
+                       // Store will overwrite it to READ COMMITTED for update.\r
+                       case ExecutionContext.READ_UNCOMMITTED_ISOLATION_LEVEL:\r
+                               isolationLevel = \r
+                    TransactionController.ISOLATION_READ_UNCOMMITTED;\r
+                               break;\r
+\r
+                       case ExecutionContext.READ_COMMITTED_ISOLATION_LEVEL:\r
+                               isolationLevel = \r
+                    TransactionController.ISOLATION_READ_COMMITTED;\r
+                               break;\r
+\r
+                       case ExecutionContext.REPEATABLE_READ_ISOLATION_LEVEL:\r
+                               isolationLevel = \r
+                    TransactionController.ISOLATION_REPEATABLE_READ;\r
+                               break;\r
+\r
+                       case ExecutionContext.SERIALIZABLE_ISOLATION_LEVEL:\r
+                               isolationLevel = \r
+                    TransactionController.ISOLATION_SERIALIZABLE;\r
+                               break;\r
+\r
+                       default:\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       SanityManager.THROWASSERT(\r
+                                               "Invalid isolation level - " + isolationLevel);\r
+                               }\r
+               }\r
+\r
+               try {\r
+\r
+               /* We can get called by either an activation or \r
+                * the DataDictionary.  The DD cannot use the\r
+                * CompiledInfo while the activation can.\r
+                */\r
+               if (heapSCOCI != null)\r
+               {\r
+               baseCC =\r
+                               tc.openCompiledConglomerate(\r
+                                       false,\r
+                    (TransactionController.OPENMODE_FORUPDATE |\r
+                    ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),\r
+                                       lockMode,\r
+                                       isolationLevel,\r
+                                       heapSCOCI,\r
+                                       heapDCOCI);\r
+               }\r
+               else\r
+               {\r
+               baseCC =\r
+                               tc.openConglomerate(\r
+                                       heapConglom,\r
+                                       false,\r
+                    (TransactionController.OPENMODE_FORUPDATE |\r
+                    ((wait) ? 0 : TransactionController.OPENMODE_LOCK_NOWAIT)),\r
+                                       lockMode,\r
+                                       isolationLevel);\r
+               }\r
+\r
+               } catch (StandardException se) {\r
+                       if (activation != null)\r
+                               activation.checkStatementValidity();\r
+                       throw se;\r
+               }\r
+\r
+               /* Save the ConglomerateController off in the activation\r
+                * to eliminate the need to open it a 2nd time if we are doing\r
+                * and index to base row for the search as part of an update or\r
+                * delete below us.\r
+                * NOTE: activation can be null.  (We don't have it in\r
+                * the DataDictionary.)\r
+                */\r
+               if (activation != null)\r
+               {\r
+                       activation.checkStatementValidity();\r
+                       activation.setHeapConglomerateController(baseCC);\r
+               }\r
+\r
+               /* Only worry about indexes if there are indexes to worry about */\r
+               if (indexCIDS.length != 0)\r
+               {\r
+                       /* IndexSetChanger re-used across executions. */\r
+                       if (isc == null)\r
+                       {\r
+                               isc = new IndexSetChanger(irgs,\r
+                                                                                 indexCIDS,\r
+                                                                                 indexSCOCIs,\r
+                                                                                 indexDCOCIs,\r
+                                                                                 indexNames,\r
+                                                                                 baseCC,\r
+                                                                                 tc,\r
+                                                                                 lockMode,\r
+                                                                                 baseRowReadList,\r
+                                                                                 isolationLevel,\r
+                                                                                 activation\r
+                                                                                 );\r
+                               isc.setRowHolder(rowHolder);\r
+                       }\r
+                       else\r
+                       {\r
+\r
+                               /* Propagate the heap's ConglomerateController to\r
+                                * all of the underlying index changers.\r
+                                */\r
+                               isc.setBaseCC(baseCC);\r
+                       }\r
+\r
+                       isc.open(fixOnUpdate);\r
+\r
+                       if (baseRowLocation == null)\r
+                               baseRowLocation = baseCC.newRowLocationTemplate();\r
+               }\r
+\r
+               isOpen = true;\r
+       }\r
+          \r
+       /**\r
+         Insert a row into the table and perform associated index maintenance.\r
+\r
+         @param baseRow the row.\r
+         @exception StandardException          Thrown on error\r
+         */\r
+       public void insertRow(ExecRow baseRow)\r
+                throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(! baseCC.isKeyed(),\r
+                                                                "Keyed inserts not yet supported");\r
+\r
+               if (baseCC.isKeyed())\r
+               {\r
+                       //kcc.insert(row.key(), row());\r
+               }\r
+               else\r
+               {\r
+                       if (isc != null)\r
+                       {\r
+                               baseCC.insertAndFetchLocation(baseRow.getRowArray(), baseRowLocation);\r
+                               isc.insert(baseRow, baseRowLocation);\r
+                       }\r
+                       else\r
+                       {\r
+                               baseCC.insert(baseRow.getRowArray());\r
+                       }\r
+               }\r
+       }\r
+\r
+               \r
+       /**\r
+         Delete a row from the table and perform associated index maintenance.\r
+\r
+         @param baseRow the row.\r
+         @param baseRowLocation the row's base conglomerate\r
+            location\r
+         @exception StandardException          Thrown on error\r
+         */\r
+       public void deleteRow(ExecRow baseRow, RowLocation baseRowLocation)\r
+                throws StandardException\r
+       {\r
+               if (isc != null)\r
+               {\r
+                       isc.delete(baseRow, baseRowLocation);\r
+               }\r
+               baseCC.delete(baseRowLocation);\r
+       }\r
+\r
+       /**\r
+         Update a row in the table and perform associated index maintenance.\r
+\r
+         @param oldBaseRow the old image of the row.\r
+         @param newBaseRow the new image of the row.\r
+         @param baseRowLocation the row's base conglomerate\r
+            location\r
+         @exception StandardException          Thrown on error\r
+         */\r
+       public void updateRow(ExecRow oldBaseRow,\r
+                                                 ExecRow newBaseRow,\r
+                                                 RowLocation baseRowLocation)\r
+                throws StandardException\r
+       {\r
+               if (isc != null)\r
+               {\r
+                       isc.update(oldBaseRow, newBaseRow, baseRowLocation);\r
+               }\r
+\r
+               if (changedColumnBitSet != null)\r
+               {\r
+                       DataValueDescriptor[] baseRowArray = newBaseRow.getRowArray();\r
+                       int[] changedColumnArray = (partialChangedColumnIds == null) ?\r
+                                       changedColumnIds : partialChangedColumnIds;\r
+                       int nextColumnToUpdate = -1;\r
+                       for (int i = 0; i < changedColumnArray.length; i++)\r
+                       {\r
+                               int copyFrom = changedColumnArray[i] - 1;\r
+                               nextColumnToUpdate =\r
+                                                       changedColumnBitSet.anySetBit(nextColumnToUpdate);\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       SanityManager.ASSERT(nextColumnToUpdate >= 0,\r
+                                               "More columns in changedColumnArray than in changedColumnBitSet");\r
+                               }\r
+                               sparseRowArray[nextColumnToUpdate] = baseRowArray[copyFrom];\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       sparseRowArray = newBaseRow.getRowArray();\r
+               }\r
+               baseCC.replace(baseRowLocation, \r
+                                       sparseRowArray, \r
+                                       changedColumnBitSet);\r
+       }\r
+\r
+       /**\r
+         Finish processing the changes.  This means applying the deferred\r
+         inserts for updates to unique indexes.\r
+\r
+         @exception StandardException          Thrown on error\r
+        */\r
+       public void finish()\r
+               throws StandardException\r
+       {\r
+               if (isc != null)\r
+               {\r
+                       isc.finish();\r
+               }\r
+       }\r
+\r
+       /**\r
+         Close this RowChanger.\r
+\r
+         @exception StandardException          Thrown on error\r
+         */\r
+       public void close()\r
+               throws StandardException\r
+       {\r
+               //\r
+               //NOTE: isc uses baseCC. Since we close baseCC we free isc for now.\r
+               //We could consider making isc open its own baseCC or even leaving\r
+               //baseCC open to promote re-use. We must keep in mind that baseCC\r
+               //is associated with the opener's TransactionController.\r
+               if (isc != null)\r
+               {\r
+                       isc.close(); \r
+               }\r
+\r
+               if (baseCC != null)\r
+               {\r
+                       if (activation == null || activation.getForUpdateIndexScan() == null)\r
+                               baseCC.close();         //beetle 3865, don't close if borrowed to cursor\r
+                       baseCC = null;\r
+               }\r
+               \r
+               isOpen = false;\r
+\r
+               // rowHolder is reused across executions and closed by caller\r
+               // since caller creates it\r
+\r
+               if (activation != null)\r
+               {\r
+                       activation.clearHeapConglomerateController();\r
+               }\r
+       }\r
+\r
+       /** @see RowChanger#getHeapConglomerateController */\r
+       public ConglomerateController getHeapConglomerateController()\r
+       {\r
+               return baseCC;\r
+       }\r
+\r
+       private int[] sortArray(int[] input)\r
+       {\r
+               /*\r
+               ** Sotring.sort() will change the underlying array, so we\r
+               ** 'clone' it first\r
+               */\r
+               int[] output = new int[input.length];\r
+               System.arraycopy(input, 0, output, 0, input.length);\r
+               java.util.Arrays.sort(output);\r
+               return output;\r
+       }\r
+}\r