Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / execute / IndexRowToBaseRowResultSet.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/IndexRowToBaseRowResultSet.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/IndexRowToBaseRowResultSet.java
new file mode 100644 (file)
index 0000000..79a6fde
--- /dev/null
@@ -0,0 +1,642 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.IndexRowToBaseRowResultSet\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.monitor.Monitor;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.stream.HeaderPrintWriter;\r
+import org.apache.derby.iapi.services.stream.InfoStreams;\r
+\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.impl.sql.GenericPreparedStatement;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.conn.StatementContext;\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.services.loader.GeneratedMethod;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.catalog.types.ReferencedColumnsDescriptorImpl;\r
+\r
+/**\r
+ * Takes a result set with a RowLocation as the last column, and uses the\r
+ * RowLocation to get and return a row from the given base conglomerate.\r
+ * Normally, the input result set will be a TableScanResultSet scanning an\r
+ * index conglomerate.\r
+ *\r
+ */\r
+class IndexRowToBaseRowResultSet extends NoPutResultSetImpl\r
+       implements CursorResultSet {\r
+\r
+    // set in constructor and not altered during\r
+    // life of object.\r
+       private long conglomId;\r
+    public NoPutResultSet source;\r
+       private GeneratedMethod resultRowAllocator;\r
+       private GeneratedMethod restriction;\r
+    private long baseConglomId;\r
+       public FormatableBitSet accessedHeapCols;\r
+       //caching accessed columns (heap+index) beetle 3865\r
+       private FormatableBitSet accessedAllCols;\r
+       public String indexName;\r
+       private int[] indexCols;\r
+       private DynamicCompiledOpenConglomInfo dcoci;\r
+       private StaticCompiledOpenConglomInfo scoci;\r
+\r
+       // set in open() and not changed after that\r
+       private ConglomerateController  baseCC;\r
+       private boolean                 closeBaseCCHere;\r
+       private ExecRow                                 resultRow;\r
+       private boolean                                 forUpdate;\r
+       private DataValueDescriptor[]   rowArray;\r
+\r
+       // changed a whole bunch\r
+       RowLocation     baseRowLocation;\r
+\r
+       /* Remember whether or not we have copied any\r
+        * columns from the source row to our row yet.\r
+        */\r
+       boolean copiedFromSource;\r
+\r
+       /* Run time statistics variables */\r
+       public long restrictionTime;\r
+\r
+       protected boolean currentRowPrescanned;\r
+       private boolean sourceIsForUpdateIndexScan;\r
+\r
+    //\r
+    // class interface\r
+    //\r
+    IndexRowToBaseRowResultSet(\r
+                                       long conglomId,\r
+                                       int scociItem,\r
+                                       Activation a,\r
+                                       NoPutResultSet source,\r
+                                       GeneratedMethod resultRowAllocator,\r
+                                       int resultSetNumber,\r
+                                       String indexName,\r
+                                       int heapColRefItem,\r
+                                       int allColRefItem,\r
+                                       int heapOnlyColRefItem,\r
+                                       int indexColMapItem,\r
+                                       GeneratedMethod restriction,\r
+                                       boolean forUpdate,\r
+                                       double optimizerEstimatedRowCount,\r
+                                       double optimizerEstimatedCost) \r
+               throws StandardException\r
+       {\r
+               super(a, resultSetNumber, optimizerEstimatedRowCount, optimizerEstimatedCost);\r
+               final GenericPreparedStatement gp =\r
+                       (GenericPreparedStatement)a.getPreparedStatement();\r
+               final Object[] saved = gp.getSavedObjects();\r
+\r
+               scoci = (StaticCompiledOpenConglomInfo)saved[scociItem];\r
+               TransactionController tc = activation.getTransactionController();\r
+               dcoci = tc.getDynamicCompiledConglomInfo(conglomId);\r
+        this.source = source;\r
+               this.resultRowAllocator = resultRowAllocator;\r
+               this.indexName = indexName;\r
+               this.forUpdate = forUpdate;\r
+               this.restriction = restriction;\r
+\r
+               /* RESOLVE - once we push Qualifiers into the store we\r
+                * need to clear their Orderable cache on each open/reopen.\r
+                */\r
+\r
+               // retrieve the valid column list from\r
+               // the saved objects, if it exists\r
+               if (heapColRefItem != -1) {\r
+                       this.accessedHeapCols = (FormatableBitSet)saved[heapColRefItem];\r
+               }\r
+               if (allColRefItem != -1) {\r
+                       this.accessedAllCols = (FormatableBitSet)saved[allColRefItem];\r
+               }\r
+\r
+               // retrieve the array of columns coming from the index\r
+               indexCols = \r
+                       ((ReferencedColumnsDescriptorImpl)\r
+                        saved[indexColMapItem]).getReferencedColumnPositions();\r
+\r
+               /* Get the result row template */\r
+               resultRow = (ExecRow) resultRowAllocator.invoke(activation);\r
+\r
+               // Note that getCompactRow will assign its return value to the\r
+               // variable compactRow which can be accessed through\r
+               // inheritance. Hence we need not collect the return value\r
+               // of the method.\r
+               getCompactRow(resultRow, accessedAllCols, \r
+                                         (FormatableBitSet)null, false);\r
+\r
+               /* If there's no partial row bit map, then we want the entire\r
+                * row, otherwise we need to diddle with the row array so that\r
+                * we only get the columns coming from the heap on the fetch.\r
+                */\r
+               if (accessedHeapCols == null) {\r
+                       rowArray = resultRow.getRowArray();\r
+               }\r
+               else {\r
+                       // Figure out how many columns are coming from the heap\r
+\r
+                       final DataValueDescriptor[] resultRowArray =\r
+                               resultRow.getRowArray();\r
+                       final FormatableBitSet heapOnly =\r
+                               (FormatableBitSet)saved[heapOnlyColRefItem];\r
+                       final int heapOnlyLen = heapOnly.getLength();\r
+\r
+                       // Need a separate DataValueDescriptor array in this case\r
+                       rowArray =\r
+                               new DataValueDescriptor[heapOnlyLen];\r
+                       final int minLen = Math.min(resultRowArray.length, heapOnlyLen);\r
+\r
+                       // Make a copy of the relevant part of rowArray\r
+                       for (int i = 0; i < minLen; ++i) {\r
+                               if (resultRowArray[i] != null && heapOnly.isSet(i)) {\r
+                                       rowArray[i] = resultRowArray[i];\r
+                               }\r
+                       }\r
+               }\r
+               constructorTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       //\r
+       // ResultSet interface (leftover from NoPutResultSet)\r
+       //\r
+\r
+       /**\r
+     * open this ResultSet.\r
+        *\r
+        * @exception StandardException thrown if cursor finished.\r
+     */\r
+       public void     openCore() throws StandardException \r
+       {\r
+               boolean                                         lockingRequired = false;\r
+               TransactionController           tc;\r
+\r
+               // REVISIT: through the direct DB API, this needs to be an\r
+               // error, not an ASSERT; users can open twice. Only through JDBC\r
+               // is access to open controlled and ensured valid.\r
+               if (SanityManager.DEBUG)\r
+               {\r
+               SanityManager.ASSERT( ! isOpen,\r
+                                                               "IndexRowToBaseRowResultSet already open");\r
+               }\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+\r
+               source.openCore();\r
+               if ((source instanceof TableScanResultSet) && \r
+                       ((TableScanResultSet) source).indexCols != null)\r
+                       sourceIsForUpdateIndexScan = true;\r
+\r
+               /* Get a ConglomerateController for the base conglomerate \r
+                * NOTE: We only need to acquire locks on the data pages when\r
+                * going through the index when we are at READ COMMITTED and\r
+                * the source is a BulkTableScan or HashScan.  (The underlying\r
+                * row will not be guaranteed to be locked.)\r
+                */\r
+               if (source.requiresRelocking())\r
+               {\r
+                       lockingRequired = true;\r
+               }\r
+\r
+               tc = activation.getTransactionController();\r
+\r
+               int openMode;\r
+               int isolationLevel;\r
+               \r
+               if (forUpdate)\r
+               {\r
+                       openMode = TransactionController.OPENMODE_FORUPDATE;\r
+               }\r
+               else\r
+               {\r
+                       openMode = 0;\r
+               }\r
+               isolationLevel = source.getScanIsolationLevel();\r
+\r
+               if (!lockingRequired)\r
+               {\r
+            // flag indicates that lock has already been acquired by access to\r
+            // the secondary index, and need not be gotten again in the base\r
+            // table.\r
+                       openMode |= TransactionController.OPENMODE_SECONDARY_LOCKED;\r
+               }\r
+               \r
+               /* Try to get the ConglomerateController from the activation\r
+                * first, for the case that we are part of an update or delete.\r
+                * If so, then the RowChangerImpl did the correct locking.\r
+                * If not there, then we go off and open it ourself.\r
+                */\r
+               if (forUpdate)\r
+               {\r
+                       baseCC = activation.getHeapConglomerateController();\r
+               }\r
+\r
+               if (baseCC == null)\r
+               {\r
+                       baseCC = \r
+                       tc.openCompiledConglomerate(\r
+                    activation.getResultSetHoldability(),\r
+                                   openMode,\r
+                                       // consistent with FromBaseTable's updateTargetLockMode\r
+                                       TransactionController.MODE_RECORD,\r
+                       isolationLevel,\r
+                                       scoci,\r
+                                       dcoci);\r
+                       closeBaseCCHere = true;\r
+               }\r
+\r
+               isOpen = true;\r
+               numOpens++;\r
+               openTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       /**\r
+        * reopen this ResultSet.\r
+        *\r
+        * @exception StandardException thrown if cursor finished.\r
+        */\r
+       public void     reopenCore() throws StandardException {\r
+               TransactionController           tc;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(isOpen,\r
+                                       "IndexRowToBaseRowResultSet already open");\r
+               }\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+\r
+               source.reopenCore();\r
+\r
+               numOpens++;\r
+               openTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       /**\r
+     * Return the requested values computed\r
+     * from the next row (if any) for which\r
+     * the restriction evaluates to true.\r
+     * <p>\r
+     * restriction and projection parameters\r
+     * are evaluated for each row.\r
+        *\r
+        * @exception StandardException thrown on failure.\r
+        * @exception StandardException ResultSetNotOpen thrown if not yet open.\r
+        *\r
+        * @return the next row in the result\r
+        */\r
+       public ExecRow  getNextRowCore() throws StandardException {\r
+\r
+           ExecRow sourceRow = null;\r
+               ExecRow retval = null;\r
+           boolean restrict = false;\r
+           DataValueDescriptor restrictBoolean;\r
+               long    beginRT = 0;\r
+\r
+               beginTime = getCurrentTimeMillis();\r
+           if ( ! isOpen ) {\r
+                       throw StandardException.newException(SQLState.LANG_RESULT_SET_NOT_OPEN, "next");\r
+               }\r
+\r
+               /* beetle 3865, updateable cursor using index.  When in-memory hash table was full, we\r
+                * read forward and saved future row id's in a virtual-memory-like temp table.  So if\r
+                * we have rid's saved, and we are here, it must be non-covering index.  Intercept it\r
+                * here, so that we don't have to go to underlying index scan.  We get both heap cols\r
+                * and index cols together here for better performance.\r
+                */\r
+               if (sourceIsForUpdateIndexScan && ((TableScanResultSet) source).futureForUpdateRows != null)\r
+               {\r
+                       currentRowPrescanned = false;\r
+                       TableScanResultSet src = (TableScanResultSet) source;\r
+\r
+                       if (src.futureRowResultSet == null)\r
+                       {\r
+                               src.futureRowResultSet = (TemporaryRowHolderResultSet) src.futureForUpdateRows.getResultSet();\r
+                               src.futureRowResultSet.openCore();\r
+                       }\r
+\r
+                       ExecRow ridRow = src.futureRowResultSet.getNextRowCore();\r
+\r
+                       currentRow = null;\r
+\r
+                       if (ridRow != null)\r
+                       {\r
+                               /* To maximize performance, we only use virtual memory style heap, no\r
+                                * position index is ever created.  And we save and retrieve rows from the\r
+                                * in-memory part of the heap as much as possible.  We can also insert after\r
+                                * we start retrieving, the assumption is that we delete the current row right\r
+                                * after we retrieve it.\r
+                                */\r
+                               src.futureRowResultSet.deleteCurrentRow();\r
+                               baseRowLocation = (RowLocation) ridRow.getColumn(1);\r
+                       baseCC.fetch(\r
+                             baseRowLocation, compactRow.getRowArray(), accessedAllCols);\r
+\r
+                               currentRow = compactRow;\r
+                               currentRowPrescanned = true;\r
+                       }\r
+                       else if (src.sourceDrained)\r
+                               currentRowPrescanned = true;\r
+\r
+                       if (currentRowPrescanned)\r
+                       {\r
+                               setCurrentRow(currentRow);\r
+\r
+                               nextTime += getElapsedMillis(beginTime);\r
+                               return currentRow;\r
+                       }\r
+               }\r
+\r
+               /* Loop until we get a row from the base page that qualifies or\r
+                * there's no more rows from the index that qualify. (If the RID\r
+                * returned by the index does not qualify, then we have to go back\r
+                * to the index to see if there is another RID to consider.)\r
+                */\r
+               do \r
+               {\r
+                       sourceRow = source.getNextRowCore();\r
+\r
+                       if (sourceRow != null) {\r
+\r
+                               if (SanityManager.DEBUG) {\r
+                                       SanityManager.ASSERT(\r
+                                               sourceRow.getColumn(sourceRow.nColumns())\r
+                                                                                                               instanceof RowLocation,\r
+                                               "Last column of source row is not a RowLocation"\r
+                                                       );\r
+                               }\r
+\r
+                               baseRowLocation = (RowLocation)\r
+                                               sourceRow.getColumn(sourceRow.nColumns());\r
+\r
+                               // Fetch the columns coming from the heap\r
+                               boolean row_exists = \r
+                    baseCC.fetch(\r
+                        baseRowLocation, rowArray, accessedHeapCols);\r
+\r
+                if (row_exists)\r
+                {\r
+                                       /* We only need to copy columns from the index row \r
+                                        * to our result row once as we will be reusing the\r
+                                        * wrappers in that case.\r
+                                        * NOTE: When the underlying ResultSet got an \r
+                                        * instantaneous lock (BulkTableScan or HashScan)\r
+                                        * then we will be getting all of the columns anew\r
+                                        * from the index (indexCols == null).\r
+                                        */\r
+                                       if (! copiedFromSource)\r
+                                       {\r
+                                               copiedFromSource = true;\r
+\r
+                                               // Copy the columns coming from the index into resultRow\r
+                                               for (int index = 0; index < indexCols.length; index++)\r
+                                               {\r
+                                                       if (indexCols[index] != -1)\r
+                                                       {\r
+                                                               compactRow.setColumn(\r
+                                                                                       index + 1,\r
+                                                                                       sourceRow.getColumn(indexCols[index] + 1));\r
+                                                       }\r
+                                               }\r
+                                       }\r
+\r
+                    setCurrentRow(compactRow);\r
+\r
+                    restrictBoolean = (DataValueDescriptor) \r
+                        ((restriction == null) ? \r
+                             null : restriction.invoke(activation));\r
+\r
+                    restrictionTime += getElapsedMillis(beginRT);\r
+\r
+                    // if the result is null, we make it false --\r
+                    // so the row won't be returned.\r
+                    restrict = (restrictBoolean == null) ||\r
+                                ((! restrictBoolean.isNull()) &&\r
+                                    restrictBoolean.getBoolean());\r
+                }\r
+\r
+                               if (! restrict || ! row_exists)\r
+                               {\r
+                                       rowsFiltered++;\r
+                                       clearCurrentRow();\r
+                                       baseRowLocation = null;\r
+\r
+                               }\r
+                               else\r
+                               {\r
+                                       currentRow = compactRow;\r
+                               }\r
+\r
+                               /* Update the run time statistics */\r
+                               rowsSeen++;\r
+\r
+                               retval = currentRow;\r
+                   } else {\r
+                               clearCurrentRow();\r
+                               baseRowLocation = null;\r
+\r
+                               retval = null;\r
+                       }\r
+           } \r
+               while ( (sourceRow != null) && (! restrict ) );\r
+\r
+               nextTime += getElapsedMillis(beginTime);\r
+       return retval;\r
+       }\r
+\r
+       /**\r
+        * If the result set has been opened,\r
+        * close the open scan.\r
+        *\r
+        * @exception StandardException thrown on error\r
+        */\r
+       public void     close() throws StandardException\r
+       {\r
+               beginTime = getCurrentTimeMillis();\r
+           if ( isOpen ) {\r
+\r
+                       // we don't want to keep around a pointer to the\r
+                       // row ... so it can be thrown away.\r
+                       // REVISIT: does this need to be in a finally\r
+                       // block, to ensure that it is executed?\r
+               clearCurrentRow();\r
+\r
+                       if (closeBaseCCHere)\r
+                       {\r
+                // This check should only be needed in the error case where\r
+                // we may call this close() routine as part of transaction\r
+                // backout cleanup if any of the following routines fail.\r
+                // If one of the subsequent statements gets an error, we\r
+                // will try to close this result set as part of transaction\r
+                // cleanup, and without this check we get a null pointer\r
+                // exception because we have null'd out baseCC.\r
+              \r
+                if (baseCC != null)\r
+                    baseCC.close();\r
+                       }\r
+\r
+                       /* Make sure to null out baseCC since\r
+                        * we check for null baseCC after looking\r
+                        * in the StatementContext.\r
+                        */\r
+                       baseCC = null;\r
+               source.close();\r
+\r
+                       super.close();\r
+           }\r
+               else if (SanityManager.DEBUG) {\r
+                       SanityManager.DEBUG("CloseRepeatInfo","Close of IndexRowToBaseRowResultSet repeated");\r
+               }\r
+\r
+               closeTime += getElapsedMillis(beginTime);\r
+       }\r
+\r
+       /**\r
+        * Return the total amount of time spent in this ResultSet\r
+        *\r
+        * @param type  CURRENT_RESULTSET_ONLY - time spent only in this ResultSet\r
+        *                              ENTIRE_RESULTSET_TREE  - time spent in this ResultSet and below.\r
+        *\r
+        * @return long         The total amount of time spent (in milliseconds).\r
+        */\r
+       public long getTimeSpent(int type)\r
+       {\r
+               long totTime = constructorTime + openTime + nextTime + closeTime;\r
+\r
+               if (type == NoPutResultSet.CURRENT_RESULTSET_ONLY)\r
+               {\r
+                       return  totTime - source.getTimeSpent(ENTIRE_RESULTSET_TREE);\r
+               }\r
+               else\r
+               {\r
+                       return totTime;\r
+               }\r
+       }\r
+\r
+       //\r
+       // CursorResultSet interface\r
+       //\r
+       /**\r
+        * Return the RowLocation of the base row.\r
+        *\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the row location of the current cursor row.\r
+        * @exception StandardException thrown on failure.\r
+        */\r
+       public RowLocation getRowLocation() throws StandardException {\r
+               return baseRowLocation;\r
+       }\r
+\r
+       /**\r
+        * @see NoPutResultSet#positionScanAtRowLocation\r
+        * \r
+        * Also remembers row location so that subsequent invocations of\r
+        * getCurrentRow will not read the index row to look up the row\r
+        * location base row, but reuse the saved row location.\r
+        */\r
+       public void positionScanAtRowLocation(RowLocation rl) \r
+               throws StandardException \r
+       {\r
+               baseRowLocation = rl;\r
+               source.positionScanAtRowLocation(rl);\r
+       }\r
+\r
+       /**      * Gets last row returned.\r
+        *\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the last row returned.\r
+        * @exception StandardException thrown on failure.\r
+        */\r
+       /* RESOLVE - this should return activation.getCurrentRow(resultSetNumber),\r
+        * once there is such a method.  (currentRow is redundant)\r
+        */\r
+       public ExecRow getCurrentRow() throws StandardException {\r
+           ExecRow sourceRow = null;\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       SanityManager.ASSERT(isOpen,\r
+                                       "IndexRowToBaseRowResultSet is expected to be open");\r
+               }\r
+\r
+               if (currentRowPrescanned)\r
+                       return currentRow;\r
+\r
+               /* Nothing to do if we're not currently on a row */\r
+               if (currentRow == null)\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               // We do not need to read the row from the index first, since we already \r
+               // have the rowLocation of the current row and can read it directly from \r
+               // the heap.\r
+               sourceRow = activation.getExecutionFactory().\r
+                               getValueRow(indexCols.length);\r
+               sourceRow.setRowArray(rowArray);\r
+               // Fetch the columns coming from the heap\r
+               boolean row_exists = \r
+                       baseCC.fetch(\r
+                               baseRowLocation, rowArray, (FormatableBitSet) null);\r
+               if (row_exists) {\r
+                       setCurrentRow(sourceRow);\r
+               } else {\r
+                       clearCurrentRow();\r
+               }\r
+               return currentRow;\r
+       }\r
+\r
+       /**\r
+        * Is this ResultSet or it's source result set for update.\r
+        * beetle 3865: updateable cursor using index scan.  We didn't need this function\r
+        * before because we couldn't use index for update cursor.\r
+        * \r
+        * @return Whether or not the result set is for update.\r
+        */\r
+       public boolean isForUpdate()\r
+       {\r
+               return source.isForUpdate();\r
+       }\r
+\r
+}\r