Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / CurrentOfNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java
new file mode 100644 (file)
index 0000000..c87b7e9
--- /dev/null
@@ -0,0 +1,597 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.CurrentOfNode\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.compile;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.OptimizablePredicateList;\r
+import org.apache.derby.iapi.sql.compile.Optimizer;\r
+import org.apache.derby.iapi.sql.compile.CostEstimate;\r
+import org.apache.derby.iapi.sql.compile.OptimizableList;\r
+import org.apache.derby.iapi.sql.compile.Optimizable;\r
+import org.apache.derby.iapi.sql.compile.RequiredRowOrdering;\r
+import org.apache.derby.iapi.sql.compile.RowOrdering;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.execute.ExecCursorTableReference;\r
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.Activation;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.util.Properties;\r
+\r
+/**\r
+ * The CurrentOf operator is used by positioned DELETE \r
+ * and UPDATE to get the current row and location\r
+ * for the target cursor.  The bind() operations for \r
+ * positioned DELETE and UPDATE add a column to \r
+ * the select list under the statement for the row location \r
+ * accessible from this node.\r
+ *\r
+ * This node is placed in the from clause of the select\r
+ * generated for the delete or update operation. It acts\r
+ * much like a FromBaseTable, using the information about\r
+ * the target table of the cursor to provide information.\r
+ *\r
+ */\r
+public final class CurrentOfNode extends FromTable {\r
+\r
+       private String                                  cursorName;\r
+       private ExecPreparedStatement    preStmt;\r
+       private TableName                               exposedTableName;\r
+       private TableName                               baseTableName;\r
+       private CostEstimate                    singleScanCostEstimate;\r
+\r
+       //\r
+       // initializers\r
+       //\r
+       public void init( Object correlationName, Object cursor, Object tableProperties)\r
+       {\r
+               super.init(correlationName, tableProperties);\r
+               cursorName = (String) cursor;\r
+       }\r
+\r
+       /*\r
+        * Optimizable interface\r
+        */\r
+\r
+       /**\r
+        * @see Optimizable#estimateCost\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public CostEstimate estimateCost(OptimizablePredicateList predList,\r
+                                                                       ConglomerateDescriptor cd,\r
+                                                                       CostEstimate outerCost,\r
+                                                                       Optimizer optimizer,\r
+                                                                       RowOrdering rowOrdering)\r
+                       throws StandardException\r
+       {\r
+               /*\r
+               ** Get the cost of a single scan of this result set.\r
+               **\r
+               ** Assume for now that the cost of a CURRENT OF is zero, with one row\r
+               ** fetched.  Is this true, and if not, does it make a difference?\r
+               ** CURRENT OF can only occur when there is only one table in the\r
+               ** FROM list, and when the only "predicate" is the WHERE CURRENT OF,\r
+               ** so there's nothing to optimize in this case.\r
+               */\r
+               if (singleScanCostEstimate == null)\r
+               {\r
+                       singleScanCostEstimate = optimizer.newCostEstimate();\r
+               }\r
+\r
+               singleScanCostEstimate.setCost(0.0d, 1.0d, 1.0d);\r
+               getBestAccessPath().setCostEstimate(singleScanCostEstimate);\r
+               getBestSortAvoidancePath().setCostEstimate(singleScanCostEstimate);\r
+\r
+               return singleScanCostEstimate;\r
+       }\r
+\r
+       //\r
+       // FromTable interface\r
+       //\r
+\r
+       /**\r
+        * Binding this FromTable means finding the prepared statement\r
+        * for the cursor and creating the result columns (the columns\r
+        * updatable on that cursor).\r
+        * \r
+        * We expect someone else to verify that the target table\r
+        * of the positioned update or delete is the table under this cursor.\r
+        *\r
+        * @param dataDictionary        The DataDictionary to use for binding\r
+        * @param fromListParam         FromList to use/append to.\r
+        *\r
+        * @return      ResultSetNode           Returns this.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public ResultSetNode bindNonVTITables(DataDictionary dataDictionary, \r
+                                                  FromList fromListParam) \r
+               throws StandardException {\r
+\r
+               // verify that the cursor exists\r
+\r
+               preStmt = getCursorStatement();\r
+\r
+               if (preStmt == null) {\r
+                       throw StandardException.newException(SQLState.LANG_CURSOR_NOT_FOUND, \r
+                                               cursorName);\r
+               }\r
+               \r
+        preStmt.rePrepare(getLanguageConnectionContext());\r
+\r
+               // verify that the cursor is updatable (UPDATE is responsible\r
+               // for checking that the right columns are updatable)\r
+               if (preStmt.getUpdateMode() != CursorNode.UPDATE)\r
+               {\r
+                       String printableString = (cursorName == null) ? "" : cursorName;\r
+                       throw StandardException.newException(SQLState.LANG_CURSOR_NOT_UPDATABLE, printableString);\r
+               }\r
+\r
+               ExecCursorTableReference refTab = preStmt.getTargetTable();\r
+               String schemaName = refTab.getSchemaName();\r
+               exposedTableName = makeTableName(null, refTab.getExposedName());\r
+               baseTableName = makeTableName(schemaName,\r
+                                                                         refTab.getBaseName());\r
+               SchemaDescriptor tableSchema = null;\r
+               tableSchema = getSchemaDescriptor(refTab.getSchemaName());\r
+\r
+               /*\r
+               ** This will only happen when we are binding against a publication\r
+               ** dictionary w/o the schema we are interested in.\r
+               */\r
+               if (tableSchema == null)\r
+               {\r
+                       throw StandardException.newException(SQLState.LANG_SCHEMA_DOES_NOT_EXIST, refTab.getSchemaName());\r
+               }\r
+\r
+               /* Create dependency on target table, in case table not named in \r
+                * positioned update/delete.  Make sure we find the table descriptor,\r
+                * we may fail to find it if we are binding a publication.\r
+                */\r
+               TableDescriptor td = getTableDescriptor(refTab.getBaseName(), tableSchema);\r
+\r
+               if (td == null)\r
+               {\r
+                       throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND, refTab.getBaseName());\r
+               }\r
+\r
+\r
+               /*\r
+               ** Add all the result columns from the target table.\r
+               ** For now, all updatable cursors have all columns\r
+               ** from the target table.  In the future, we should\r
+               ** relax this so that the cursor may do a partial\r
+               ** read and then the current of should make sure that\r
+               ** it can go to the base table to get all of the \r
+               ** columns needed by the referencing positioned\r
+               ** DML.  In the future, we'll probably need to get\r
+               ** the result columns from preparedStatement and\r
+               ** turn them into an RCL that we can run with.\r
+               */\r
+               resultColumns = (ResultColumnList) getNodeFactory().getNode(\r
+                                                                                       C_NodeTypes.RESULT_COLUMN_LIST,\r
+                                                                                       getContextManager());\r
+               ColumnDescriptorList cdl = td.getColumnDescriptorList();\r
+               int                                      cdlSize = cdl.size();\r
+\r
+               for (int index = 0; index < cdlSize; index++)\r
+               {\r
+                       /* Build a ResultColumn/BaseColumnNode pair for the column */\r
+                       ColumnDescriptor colDesc = (ColumnDescriptor) cdl.elementAt(index);\r
+\r
+                       BaseColumnNode bcn = (BaseColumnNode) getNodeFactory().getNode(\r
+                                                                                       C_NodeTypes.BASE_COLUMN_NODE,\r
+                                                                                       colDesc.getColumnName(),\r
+                                                                                       exposedTableName,\r
+                                                                                       colDesc.getType(),\r
+                                                                                       getContextManager());\r
+                       ResultColumn rc = (ResultColumn) getNodeFactory().getNode(\r
+                                                                                       C_NodeTypes.RESULT_COLUMN,\r
+                                                                                       colDesc,\r
+                                                                                       bcn,\r
+                                                                                       getContextManager());\r
+\r
+                       /* Build the ResultColumnList to return */\r
+                       resultColumns.addResultColumn(rc);\r
+               }\r
+\r
+               /* Assign the tableNumber */\r
+               if (tableNumber == -1)  // allow re-bind, in which case use old number\r
+                       tableNumber = getCompilerContext().getNextTableNumber();\r
+\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * Bind the expressions in this ResultSetNode.  This means binding the\r
+        * sub-expressions, as well as figuring out what the return type is for\r
+        * each expression.\r
+        *\r
+        * @param fromListParam         FromList to use/append to.\r
+        */\r
+       public void bindExpressions(FromList fromListParam)\r
+       {\r
+               /* No expressions to bind for a CurrentOfNode.\r
+                * NOTE - too involved to optimize so that this method\r
+                * doesn't get called, so just do nothing.\r
+                */\r
+       }\r
+\r
+       /**\r
+        * Try to find a ResultColumn in the table represented by this CurrentOfNode\r
+        * that matches the name in the given ColumnReference.\r
+        *\r
+        * @param columnReference       The columnReference whose name we're looking\r
+        *                              for in the given table.\r
+        *\r
+        * @return      A ResultColumn whose expression is the ColumnNode\r
+        *                      that matches the ColumnReference.\r
+        *              Returns null if there is no match.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public ResultColumn getMatchingColumn(ColumnReference columnReference) \r
+                                               throws StandardException {\r
+\r
+               ResultColumn    resultColumn = null;\r
+               TableName               columnsTableName;\r
+\r
+               columnsTableName = columnReference.getTableNameNode();\r
+\r
+        if(columnsTableName != null)\r
+            if(columnsTableName.getSchemaName() == null && correlationName == null)\r
+                columnsTableName.bind(this.getDataDictionary());\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(preStmt!=null, "must have prepared statement");\r
+               }\r
+\r
+               /*\r
+                * We use the base table name of the target table.\r
+                * This is necessary since we will be comparing with the table in\r
+                * the delete or update statement which doesn't have a correlation\r
+                * name.  The select for which this column is created might have a\r
+                * correlation name and so we won't find it if we look for exposed names\r
+                * We shouldn't have to worry about multiple table since there should be\r
+                * only one table. Beetle 4419\r
+                */\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(baseTableName!=null,"no name on target table");\r
+               }\r
+\r
+        if(baseTableName != null)\r
+            if(baseTableName.getSchemaName() == null && correlationName == null)\r
+                baseTableName.bind(this.getDataDictionary());\r
+\r
+               /*\r
+                * If the column did not specify a name, or the specified name\r
+                * matches the table we're looking at, see whether the column\r
+                * is in this table, and also whether it is in the for update list.\r
+               */\r
+               if (\r
+                          (columnsTableName == null) ||\r
+                          (columnsTableName.getFullTableName().equals(baseTableName.getFullTableName())) ||\r
+                          ((correlationName != null) && correlationName.equals( columnsTableName.getTableName()))\r
+                  )\r
+               {\r
+                       boolean notfound = false;\r
+\r
+                       resultColumn =\r
+                               resultColumns.getResultColumn(columnReference.getColumnName());\r
+\r
+                       if (resultColumn != null) \r
+                       {\r
+                               // If we found the ResultColumn, set the ColumnReference's\r
+                               // table number accordingly.  Note: we used to only set\r
+                               // the tableNumber for correlated references (as part of\r
+                               // changes for DERBY-171) but inspection of code (esp.\r
+                               // the comments in FromList.bindColumnReferences() and\r
+                               // the getMatchingColumn() methods on other FromTables)\r
+                               // suggests that we should always set the table number\r
+                               // if we've found the ResultColumn.  So we do that here.\r
+                               columnReference.setTableNumber( tableNumber );\r
+\r
+                               // If there is a result column, are we really updating it?\r
+                               // If so, verify that the column is updatable as well\r
+                               notfound = \r
+                                       (resultColumn.updatableByCursor() &&\r
+                                       !foundString(\r
+                                                       preStmt.getUpdateColumns(), \r
+                                                       columnReference.getColumnName()));\r
+                       }\r
+                       else \r
+                       {\r
+                               notfound = true;\r
+                       }\r
+\r
+                       if (notfound)\r
+                       {\r
+                               String printableString = (cursorName == null) ? "" : cursorName;\r
+                               throw StandardException.newException(SQLState.LANG_COLUMN_NOT_UPDATABLE_IN_CURSOR, \r
+                                                columnReference.getColumnName(), printableString);\r
+                       }\r
+               }\r
+\r
+               return resultColumn;\r
+       }\r
+\r
+       /**\r
+        * Preprocess a CurrentOfNode.  For a CurrentOfNode, this simply means allocating\r
+        * a referenced table map to avoid downstream NullPointerExceptions.\r
+        * NOTE: There are no bits set in the referenced table map.\r
+        *\r
+        * @param numTables                     The number of tables in the DML Statement\r
+        * @param gbl                           The group by list, if any\r
+        * @param fromList                      The from list, if any\r
+        *\r
+        * @return ResultSetNode at top of preprocessed tree.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public ResultSetNode preprocess(int numTables,\r
+                                                                       GroupByList gbl,\r
+                                                                       FromList fromList)\r
+                                                               throws StandardException\r
+       {\r
+               /* Generate an empty referenced table map */\r
+               referencedTableMap = new JBitSet(numTables);\r
+               return this;\r
+       }\r
+\r
+       /**                     \r
+        * Optimize this CurrentOfNode.  Nothing to do.\r
+        *\r
+        * @param dataDictionary        The DataDictionary to use for optimization\r
+        * @param predicateList         The PredicateList to optimize.  This should\r
+        *                              be a single-table predicate with the table\r
+        *                              the same as the table in this FromTable.\r
+        * @param outerRows                     The number of outer joining rows\r
+        *\r
+        * @return ResultSetNode        The top of the optimized subtree.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public ResultSetNode optimize(DataDictionary dataDictionary,\r
+                                            PredicateList predicateList,\r
+                                                double outerRows) \r
+                                               throws StandardException {\r
+               /* Get an optimizer so we can get a cost */\r
+               Optimizer optimizer = getOptimizer(\r
+                                                               (FromList) getNodeFactory().getNode(\r
+                                                                       C_NodeTypes.FROM_LIST,\r
+                                                                       getNodeFactory().doJoinOrderOptimization(),\r
+                                                                       this,\r
+                                                                       getContextManager()),\r
+                                                               predicateList,\r
+                                                               dataDictionary,\r
+                                                               (RequiredRowOrdering) null);\r
+\r
+               /* Assume there is no cost associated with fetching the current row */\r
+               bestCostEstimate = optimizer.newCostEstimate();\r
+               bestCostEstimate.setCost(0.0d, outerRows, outerRows);\r
+\r
+               return this;\r
+       }\r
+\r
+       /**\r
+        * Generation on a CurrentOfNode creates a scan on the\r
+        * cursor, CurrentOfResultSet.\r
+        * <p>\r
+        * This routine will generate and return a call of the form:\r
+        * <pre><verbatim>\r
+               ResultSetFactory.getCurrentOfResultSet(cursorName)\r
+          </verbatim></pre>\r
+        *\r
+        * @param acb   The ActivationClassBuilder for the class being built\r
+        * @param mb    The execute() method to be built\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void generate(ActivationClassBuilder acb,\r
+                                                               MethodBuilder mb)\r
+                                                       throws StandardException {\r
+\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT(!statementResultSet, \r
+                       "CurrentOfNode not expected to be statement node");\r
+\r
+               /* Get the next ResultSet #, so that we can number this ResultSetNode, its\r
+                * ResultColumnList and ResultSet.\r
+                */\r
+               assignResultSetNumber();\r
+\r
+               mb.pushThis(); // for the putField\r
+\r
+               // The generated java returned by this method is the expression:\r
+               // ResultSetFactory.getCurrentOfResultSet(\r
+               //              #cursorName(), this, resultSetNumber)\r
+\r
+               acb.pushGetResultSetFactoryExpression(mb);\r
+\r
+                 mb.push(cursorName);\r
+                 acb.pushThisAsActivation(mb);\r
+                 mb.push(resultSetNumber);\r
+               \r
+               mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getCurrentOfResultSet",\r
+                                               ClassName.NoPutResultSet, 3);\r
+\r
+               mb.cast(ClassName.CursorResultSet);\r
+\r
+        // the current of scan generator is what we return\r
+               /* This table is the target of an update or a delete, so we must \r
+                * wrap the Expression up in an assignment expression before \r
+                * returning. Delete or update use the field that is set\r
+                * to calculate the CurrentRowLocation value.\r
+                * NOTE - scanExpress is a ResultSet.  We will need to cast it to the\r
+                * appropriate subclass.\r
+                * For example, for a DELETE, instead of returning a call to the \r
+                * ResultSetFactory, we will generate and return:\r
+                *              this.SCANRESULTSET = (cast to appropriate ResultSet type) \r
+                * The outer cast back to ResultSet is needed so that\r
+                * we invoke the appropriate method in the call to the ResultSetFactory\r
+                */\r
+\r
+               mb.putField((String) null, acb.getRowLocationScanResultSetName(), ClassName.CursorResultSet);\r
+               mb.cast(ClassName.NoPutResultSet);\r
+\r
+               // add a check at activation reset time to see if the cursor has\r
+               // changed underneath us. Doing it in the constructor allows the\r
+               // compilation to happen \r
+               MethodBuilder rmb = acb.startResetMethod();\r
+\r
+               rmb.pushThis();\r
+               rmb.push(cursorName);\r
+               rmb.push(preStmt.getObjectName());\r
+               rmb.callMethod(VMOpcode.INVOKEVIRTUAL, ClassName.BaseActivation, "checkPositionedStatement",\r
+                                               "void", 2);\r
+\r
+               rmb.methodReturn();\r
+               rmb.complete();\r
+       }\r
+\r
+       /**\r
+        * Prints the sub-nodes of this object.  See QueryTreeNode.java for\r
+        * how tree printing is supposed to work.\r
+        *\r
+        * @param depth         The depth of this node in the tree\r
+        */\r
+       public void printSubNodes(int depth) {\r
+               if (SanityManager.DEBUG) {\r
+                       super.printSubNodes(depth);\r
+\r
+                       printLabel(depth, "cursor: ");\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Convert this object to a String.  See comments in QueryTreeNode.java\r
+        * for how this should be done for tree printing.\r
+        *\r
+        * @return      This object as a String\r
+        */\r
+       public String toString() {\r
+               if (SanityManager.DEBUG) {\r
+                       return "preparedStatement: " +\r
+                       (preStmt == null? "no prepared statement yet\n" :\r
+                               preStmt.toString() + "\n")+\r
+                               cursorName + "\n" +\r
+                               super.toString();\r
+               } else {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       //\r
+       // class interface\r
+       //\r
+\r
+       public String  getExposedName()\r
+       {\r
+               return exposedTableName.getFullTableName();\r
+       }\r
+       public TableName  getExposedTableName()\r
+       {\r
+               return exposedTableName;\r
+       }\r
+\r
+       public TableName  getBaseCursorTargetTableName()\r
+       {\r
+               return baseTableName;\r
+       }\r
+\r
+       public String getCursorName() \r
+       {\r
+               return cursorName;\r
+       }\r
+\r
+       /**\r
+        * Return the CursorNode associated with a positioned update/delete.\r
+        * \r
+        * @return CursorNode   The associated CursorNode.\r
+        *\r
+        */\r
+       ExecPreparedStatement getCursorStatement()\r
+       {\r
+               Activation activation = getLanguageConnectionContext().lookupCursorActivation(cursorName);\r
+\r
+               if (activation == null)\r
+                       return null;\r
+\r
+               return activation.getPreparedStatement();\r
+       }\r
+\r
+       /**\r
+        * Get the lock mode for this table as the target of an update statement\r
+        * (a delete or update).  This is implemented only for base tables and\r
+        * CurrentOfNodes.\r
+        *\r
+        * @see TransactionController\r
+        *\r
+        * @return      The lock mode\r
+        */\r
+       public int updateTargetLockMode()\r
+       {\r
+               /* Do row locking for positioned update/delete */\r
+               return TransactionController.MODE_RECORD;\r
+       }\r
+}\r