Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / execute / CurrentOfResultSet.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/CurrentOfResultSet.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/CurrentOfResultSet.java
new file mode 100644 (file)
index 0000000..a131120
--- /dev/null
@@ -0,0 +1,344 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.CurrentOfResultSet\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.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.sql.execute.CursorActivation;\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.sql.Activation;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.PreparedStatement;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.depend.DependencyManager;\r
+\r
+/**\r
+ * Takes a cursor name and returns the current row\r
+ * of the cursor; for use in generating the source\r
+ * row and row location for positioned update/delete operations.\r
+ * <p>\r
+ * This result set returns only one row.\r
+ *\r
+ */\r
+class CurrentOfResultSet extends NoPutResultSetImpl\r
+       implements CursorResultSet {\r
+\r
+    private boolean next;\r
+       private RowLocation rowLocation;\r
+\r
+       private CursorResultSet cursor;\r
+       private CursorResultSet target;\r
+       private ExecRow                 sparseRow;\r
+\r
+    // set in constructor and not altered during\r
+    // life of object.\r
+       private final String cursorName;\r
+\r
+    //\r
+    // class interface\r
+    //\r
+    CurrentOfResultSet(String cursorName, Activation activation, \r
+                                                         int resultSetNumber)\r
+       {\r
+               super(activation, resultSetNumber, 0.0d, 0.0d);\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT( cursorName!=null, "current of scan must get cursor name");\r
+        this.cursorName = cursorName;\r
+    }\r
+\r
+       //\r
+       // ResultSet interface (leftover from NoPutResultSet)\r
+       //\r
+       /**\r
+     * open a scan on the table. scan parameters are evaluated\r
+     * at each open, so there is probably some way of altering\r
+     * their values...\r
+        *\r
+        * @exception StandardException thrown on failure to open\r
+     */\r
+       public void     openCore() throws StandardException {\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT( ! isOpen, "CurrentOfResultSet already open");\r
+\r
+               // get the cursor\r
+               getCursor();\r
+\r
+               next = false;\r
+           isOpen = true;\r
+       }\r
+\r
+       /**\r
+     * If open and not returned yet, returns the row.\r
+        *\r
+        * @exception StandardException thrown on failure.\r
+     */\r
+       public ExecRow  getNextRowCore() throws StandardException {\r
+\r
+               if ( isOpen ) {\r
+               if ( ! next ) {\r
+                   next = true;\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(! cursor.isClosed(), "cursor closed");\r
+\r
+                               ExecRow cursorRow = cursor.getCurrentRow();\r
+\r
+                               // requalify the current row\r
+                               if (cursorRow == null) {\r
+                                       throw StandardException.newException(SQLState.NO_CURRENT_ROW);\r
+                               }\r
+                               // we know it will be requested, may as well get it now.\r
+                               rowLocation = cursor.getRowLocation();\r
+\r
+                               // get the row from the base table, which is the real result\r
+                               // row for the CurrentOfResultSet\r
+                               currentRow = target.getCurrentRow();\r
+\r
+                               // if the source result set is a ScrollInsensitiveResultSet, and\r
+                               // the current row has been deleted (while the cursor was \r
+                               // opened), the cursor result set (scroll insensitive) will \r
+                               // return the cached row, while the target result set will \r
+                               // return null (row has been deleted under owr feet).\r
+                               if (rowLocation == null  || \r
+                                               (cursorRow != null && currentRow == null)) {\r
+                                       activation.addWarning(StandardException.\r
+                                                       newWarning(SQLState.CURSOR_OPERATION_CONFLICT));\r
+                                       return null;\r
+                               }\r
+\r
+                               /* beetle 3865: updateable cursor using index.  If underlying is a covering\r
+                                * index, target is a TableScanRS (instead of a IndexRow2BaseRowRS) for the\r
+                                * index scan.  But the problem is it returns a compact row in index key order.\r
+                                * However the ProjectRestrictRS above us that sets up the old and new column\r
+                                * values expects us to return a sparse row in heap order.  We have to do the\r
+                                * wiring here, since we don't have IndexRow2BaseRowRS to do this work.  This\r
+                                * problem was not exposed before, because we never used index scan for updateable\r
+                                * cursors.\r
+                                */\r
+                               if (target instanceof TableScanResultSet)\r
+                               {\r
+                                       TableScanResultSet scan = (TableScanResultSet) target;\r
+                                       if (scan.indexCols != null && currentRow != null)\r
+                                               currentRow = getSparseRow(currentRow, scan.indexCols);\r
+                               }\r
+                               /* If we are updating rows from cached RIDs, we should compare with forward-most\r
+                                * scan key when deciding whether to add RID to hash table or not.\r
+                                */\r
+                               TableScanResultSet scan = (TableScanResultSet) activation.getForUpdateIndexScan();\r
+                               if (scan != null)\r
+                               {\r
+                                       if (target instanceof IndexRowToBaseRowResultSet)\r
+                                               scan.compareToLastKey = ((IndexRowToBaseRowResultSet) target).currentRowPrescanned;\r
+                                       else if (target instanceof TableScanResultSet)\r
+                                               scan.compareToLastKey = ((TableScanResultSet) target).currentRowPrescanned;\r
+                               }\r
+\r
+                               // REMIND: verify the row is still there\r
+                               // at present we get an ugly exception from the store,\r
+                               // Hopefully someday we can just do this:\r
+                               //\r
+                               // if (!rowLocation.rowExists())\r
+                               //     throw StandardException.newException(SQLState.LANG_NO_CURRENT_ROW, cursorName);\r
+                       }\r
+                       else {\r
+                               currentRow = null;\r
+                               rowLocation = null;\r
+                       }\r
+           }\r
+               else {\r
+                       currentRow = null;\r
+                       rowLocation = null;\r
+               }\r
+               setCurrentRow(currentRow);\r
+           return currentRow;\r
+       }\r
+\r
+       /**\r
+        * Return a sparse heap row, based on a compact index row.\r
+        *\r
+        * @param row           compact referenced index row\r
+        * @param indexCols     base column positions of index keys, signed with asc/desc info\r
+        *\r
+        * @return                      a sparse heap row with referenced columns\r
+        */\r
+       private ExecRow getSparseRow(ExecRow row, int[] indexCols) throws StandardException\r
+       {\r
+               int colPos;\r
+               if (sparseRow == null)\r
+               {\r
+                       int numCols = 1;\r
+                       for (int i = 0; i < indexCols.length; i++)\r
+                       {\r
+                               colPos = (indexCols[i] > 0) ? indexCols[i] : -indexCols[i];\r
+                               if (colPos > numCols)\r
+                                       numCols = colPos;\r
+                       }\r
+                       sparseRow = new ValueRow(numCols);\r
+               }\r
+               for (int i = 1; i <= indexCols.length; i++)\r
+               {\r
+                       colPos = (indexCols[i-1] > 0) ? indexCols[i-1] : -indexCols[i-1];\r
+                       sparseRow.setColumn(colPos, row.getColumn(i));\r
+               }\r
+\r
+               return sparseRow;\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
+           if ( isOpen ) {\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
+               next = false;\r
+\r
+                       super.close();\r
+           }\r
+               else\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.DEBUG("CloseRepeatInfo","Close of CurrentOfResultSet repeated");\r
+       }\r
+       public void     finish() throws StandardException\r
+       {\r
+               finishAndRTS();\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
+               /* RESOLVE - RunTimeStats not implemented yet */\r
+               return 0;\r
+       }\r
+\r
+       /**\r
+        * This result set has its row location from\r
+        * the last fetch done. If it is closed,\r
+        * a null is returned.\r
+        *\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the row location of the current row.\r
+        * @exception StandardException thrown on failure to get row location\r
+        */\r
+       public RowLocation getRowLocation()  {\r
+               return rowLocation;\r
+       }\r
+\r
+       /**\r
+        * @see CursorResultSet\r
+        *\r
+        * @return the last row returned by getNextRow.\r
+        */\r
+       public ExecRow getCurrentRow() {\r
+               return currentRow;\r
+       }\r
+\r
+       //\r
+       // class implementation\r
+       //\r
+       /**\r
+               Because the positioned operation only gets one location\r
+               per execution, and the cursor could be completely different\r
+               for each execution (closed and reopened, perhaps), we \r
+               determine where caching the cursor could be applied.\r
+               <p>\r
+               When cached, we check if the cursor was closed'd, \r
+               and if so, throw it out and \r
+               see if there's one in the cache with our name. \r
+\r
+        */\r
+       private void getCursor() throws StandardException {\r
+\r
+               // need to look again if cursor was closed\r
+               if (cursor != null) {\r
+                       if (cursor.isClosed())\r
+                       {\r
+                               cursor = null;\r
+                               target = null;\r
+                       }\r
+               }\r
+\r
+               if (cursor == null) {\r
+\r
+                       LanguageConnectionContext lcc = getLanguageConnectionContext();\r
+\r
+                       CursorActivation cursorActivation = lcc.lookupCursorActivation(cursorName);\r
+\r
+                       if (cursorActivation != null)\r
+                       {\r
+                               \r
+                               cursor = cursorActivation.getCursorResultSet();\r
+                               target = cursorActivation.getTargetResultSet();\r
+                               /* beetle 3865: updateable cursor using index. 2 way communication between\r
+                                * update activation and cursor activation. Cursor passes index scan to\r
+                                * update and update passes heap conglom controller to cursor.\r
+                                */\r
+                               activation.setForUpdateIndexScan(cursorActivation.getForUpdateIndexScan());\r
+                               if (cursorActivation.getHeapConglomerateController() != null)\r
+                                       cursorActivation.getHeapConglomerateController().close();\r
+                               cursorActivation.setHeapConglomerateController(activation.getHeapConglomerateController());                             \r
+                       }\r
+               }\r
+\r
+               if (cursor == null || cursor.isClosed()) {\r
+                       throw StandardException.newException(SQLState.LANG_CURSOR_NOT_FOUND, cursorName);       \r
+               }\r
+       }\r
+\r
+       /**\r
+        * @see NoPutResultSet#updateRow\r
+        */\r
+       public void updateRow (ExecRow row) throws StandardException {\r
+               ((NoPutResultSet)cursor).updateRow(row);\r
+       }\r
+       \r
+       /**\r
+        * @see NoPutResultSet#markRowAsDeleted\r
+        */\r
+       public void markRowAsDeleted() throws StandardException {\r
+               ((NoPutResultSet)cursor).markRowAsDeleted();\r
+       }\r
+       \r
+}\r