Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / UpdateNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
new file mode 100644 (file)
index 0000000..321e6a7
--- /dev/null
@@ -0,0 +1,1138 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.UpdateNode\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.services.loader.GeneratedMethod;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.impl.sql.execute.FKInfo;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ExecPreparedStatement;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.vti.DeferModification;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.util.ReuseFactory;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.lang.reflect.Modifier;\r
+import java.sql.SQLException;\r
+import java.util.Properties;\r
+import java.util.Vector;\r
+\r
+/**\r
+ * An UpdateNode represents an UPDATE statement.  It is the top node of the\r
+ * query tree for that statement.\r
+ * For positioned update, there may be no from table specified.\r
+ * The from table will be derived from the cursor specification of\r
+ * the named cursor.\r
+ *\r
+ */\r
+\r
+public final class UpdateNode extends DMLModStatementNode\r
+{\r
+       //Note: These are public so they will be visible to\r
+       //the RepUpdateNode.\r
+       public int[]                            changedColumnIds;\r
+       public ExecRow                          emptyHeapRow;\r
+       public boolean                          deferred;\r
+       public ValueNode                        checkConstraints;\r
+       public FKInfo                           fkInfo;\r
+       \r
+       protected FromTable                     targetTable;\r
+       protected FormatableBitSet                      readColsBitSet;\r
+       protected boolean                       positionedUpdate;\r
+\r
+       /* Column name for the RowLocation in the ResultSet */\r
+       public static final String COLUMNNAME = "###RowLocationToUpdate";\r
+\r
+       /**\r
+        * Initializer for an UpdateNode.\r
+        *\r
+        * @param targetTableName       The name of the table to update\r
+        * @param resultSet             The ResultSet that will generate\r
+        *                              the rows to update from the given table\r
+        */\r
+\r
+       public void init(\r
+                          Object targetTableName,\r
+                          Object resultSet)\r
+       {\r
+               super.init(resultSet);\r
+               this.targetTableName = (TableName) targetTableName;\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
+\r
+       public String toString()\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       return targetTableName.toString() + "\n" +\r
+                               super.toString();\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       public String statementToString()\r
+       {\r
+               return "UPDATE";\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
+\r
+       public void printSubNodes(int depth)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       super.printSubNodes(depth);\r
+\r
+                       if (targetTableName != null)\r
+                       {\r
+                               printLabel(depth, "targetTableName: ");\r
+                               targetTableName.treePrint(depth + 1);\r
+                       }\r
+\r
+                       /* RESOLVE - need to print out targetTableDescriptor */\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Bind this UpdateNode.  This means looking up tables and columns and\r
+        * getting their types, and figuring out the result types of all\r
+        * expressions, as well as doing view resolution, permissions checking,\r
+        * etc.\r
+        * <p>\r
+        * Binding an update will also massage the tree so that\r
+        * the ResultSetNode has a set of columns to contain the old row\r
+        * value, followed by a set of columns to contain the new row\r
+        * value, followed by a column to contain the RowLocation of the\r
+        * row to be updated.\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void bindStatement() throws StandardException\r
+       {\r
+               // We just need select privilege on the expressions\r
+               getCompilerContext().pushCurrentPrivType( Authorizer.SELECT_PRIV);\r
+\r
+               FromList        fromList = (FromList) getNodeFactory().getNode(\r
+                                                                       C_NodeTypes.FROM_LIST,\r
+                                                                       getNodeFactory().doJoinOrderOptimization(),\r
+                                                                       getContextManager());\r
+               ResultColumn                            rowLocationColumn = null;\r
+               ValueNode                           rowLocationNode = null;\r
+               TableName                                       cursorTargetTableName = null;\r
+               CurrentOfNode                   currentOfNode = null;\r
+               FromList                                        resultFromList;\r
+               ResultColumnList                        afterColumns = null;\r
+\r
+               DataDictionary dataDictionary = getDataDictionary();\r
+\r
+               // check if targetTable is a synonym\r
+               if (targetTableName != null)\r
+               {\r
+                       TableName synonymTab = resolveTableToSynonym(this.targetTableName);\r
+                       if (synonymTab != null)\r
+                       {\r
+                               this.synonymTableName = targetTableName;\r
+                               this.targetTableName  = synonymTab;\r
+                       }\r
+               }\r
+\r
+               bindTables(dataDictionary);\r
+\r
+               // wait to bind named target table until the cursor\r
+               // binding is done, so that we can get it from the\r
+               // cursor if this is a positioned update.\r
+\r
+               // for positioned update, get the cursor's target table.\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT((resultSet!=null && resultSet instanceof SelectNode), \r
+                               "Update must have a select result set");\r
+               }\r
+\r
+               SelectNode sel;\r
+               sel = (SelectNode)resultSet;\r
+               targetTable = (FromTable) sel.fromList.elementAt(0);\r
+\r
+               if (targetTable instanceof CurrentOfNode) \r
+               {       \r
+                       positionedUpdate = true;\r
+                       currentOfNode = (CurrentOfNode) targetTable;\r
+                       cursorTargetTableName = currentOfNode.getBaseCursorTargetTableName();\r
+\r
+                       // instead of an assert, we might say the cursor is not updatable.\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               SanityManager.ASSERT(cursorTargetTableName != null);\r
+                       }\r
+               }\r
+\r
+               if (targetTable instanceof FromVTI)\r
+               {\r
+                       targetVTI = (FromVTI) targetTable;\r
+                       targetVTI.setTarget();\r
+               }\r
+               else\r
+               {\r
+                       // positioned update can leave off the target table.\r
+                       // we get it from the cursor supplying the position.\r
+                       if (targetTableName == null)\r
+                       {\r
+                               // verify we have current of\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(cursorTargetTableName!=null);\r
+\r
+                               targetTableName = cursorTargetTableName;\r
+                       }\r
+                       // for positioned update, we need to verify that\r
+                       // the named table is the same as the cursor's target.\r
+                       else if (cursorTargetTableName != null)\r
+                       {\r
+                               // this match requires that the named table in the update\r
+                               // be the same as a correlation name in the cursor.\r
+                               if ( !targetTableName.equals(cursorTargetTableName))\r
+                               {\r
+                                       throw StandardException.newException(SQLState.LANG_CURSOR_UPDATE_MISMATCH, \r
+                                               targetTableName,\r
+                                               currentOfNode.getCursorName());\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               // because we verified that the tables match\r
+               // and we already bound the cursor or the select,\r
+               // the table descriptor should always be found.\r
+               verifyTargetTable();\r
+               \r
+               /* OVERVIEW - We generate a new ResultColumn, CurrentRowLocation(), and\r
+                * prepend it to the beginning of the source ResultColumnList.  This\r
+                * will tell us which row(s) to update at execution time.  However,\r
+                * we must defer prepending this generated column until the other\r
+                * ResultColumns are bound since there will be no ColumnDescriptor\r
+                * for the generated column.  Thus, the sequence of actions is:\r
+                *\r
+                *              o  Bind existing ResultColumnList (columns in SET clause)\r
+                *              o  If this is a positioned update with a FOR UPDATE OF list,\r
+                *                 then verify that all of the target columns are in the\r
+                *                 FOR UPDATE OF list.\r
+                *              o  Get the list of indexes that need to be updated.\r
+                *              o  Create a ResultColumnList of all the columns in the target\r
+                *                 table - this represents the old row.\r
+                *              o  If we don't know which columns are being updated, \r
+                *                 expand the original ResultColumnList to include all the\r
+                *                 columns in the target table, and sort it to be in the\r
+                *                 order of the columns in the target table.  This represents\r
+                *                 the new row.  Append it to the ResultColumnList representing\r
+                *                 the old row.\r
+                *              o  Construct the changedColumnIds array sorted by column position.\r
+                *              o  Generate the read column bit map and append any columns\r
+                *                 needed for index maint, etc.\r
+                *              o  Generate a new ResultColumn for CurrentRowLocation() and \r
+                *                 mark it as a generated column.\r
+                *              o  Append the new ResultColumn to the ResultColumnList\r
+                *                 (This must be done before binding the expressions, so\r
+                *                 that the proper type info gets propagated to the new \r
+                *                 ResultColumn.)\r
+                *              o  Bind the expressions.\r
+                *              o  Bind the generated ResultColumn.\r
+                */\r
+\r
+               /* Verify that all underlying ResultSets reclaimed their FromList */\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(fromList.size() == 0,\r
+                               "fromList.size() is expected to be 0, not " + \r
+                               fromList.size() +\r
+                               " on return from RS.bindExpressions()");\r
+               }\r
+\r
+               /*\r
+               ** The current result column list is the one supplied by the user.\r
+               ** Mark these columns as "updated", so we can tell later which\r
+               ** columns are really being updated, and which have been added\r
+               ** but are not really being updated.\r
+               */\r
+               resultSet.getResultColumns().markUpdated();\r
+\r
+               /* Prepend CurrentRowLocation() to the select's result column list. */\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT((resultSet.resultColumns != null), \r
+                                                         "resultColumns is expected not to be null at bind time");\r
+\r
+               /*\r
+               ** Get the result FromTable, which should be the only table in the\r
+               ** from list.\r
+               */\r
+               resultFromList = resultSet.getFromList();\r
+               if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT(resultFromList.size() == 1,\r
+                       "More than one table in result from list in an update.");\r
+\r
+               /* Normalize the SET clause's result column list for synonym */\r
+               if (synonymTableName != null)\r
+                       normalizeSynonymColumns( resultSet.resultColumns, targetTable );\r
+               \r
+               /* Bind the original result columns by column name */\r
+               normalizeCorrelatedColumns( resultSet.resultColumns, targetTable );\r
+\r
+               getCompilerContext().pushCurrentPrivType(getPrivType()); // Update privilege\r
+               resultSet.bindResultColumns(targetTableDescriptor,\r
+                                       targetVTI,\r
+                                       resultSet.resultColumns, this,\r
+                                       fromList);\r
+               getCompilerContext().popCurrentPrivType();\r
+\r
+               LanguageConnectionContext lcc = getLanguageConnectionContext();\r
+               if (lcc.getAutoincrementUpdate() == false)\r
+                       resultSet.getResultColumns().checkAutoincrement(null);\r
+\r
+               /*\r
+               ** Mark the columns in this UpdateNode's result column list as\r
+               ** updateable in the ResultColumnList of the table being updated.\r
+               ** only do this for FromBaseTables - if the result table is a\r
+               ** CurrentOfNode, it already knows what columns in its cursor\r
+               ** are updateable.\r
+               */\r
+               boolean allColumns = false;\r
+               if (targetTable instanceof FromBaseTable)\r
+               {\r
+                       ((FromBaseTable) targetTable).markUpdated(\r
+                                                                                               resultSet.getResultColumns());\r
+               }\r
+               else if (targetTable instanceof FromVTI)\r
+               {\r
+            resultColumnList = resultSet.getResultColumns();\r
+               }\r
+               else\r
+               {\r
+                       /*\r
+                       ** Positioned update: WHERE CURRENT OF\r
+                       */\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               SanityManager.ASSERT(currentOfNode != null, "currentOfNode is null");\r
+                       }\r
+\r
+                       ExecPreparedStatement    cursorStmt = currentOfNode.getCursorStatement();\r
+                       String[] ucl = cursorStmt.getUpdateColumns();\r
+\r
+                       /*\r
+                       ** If there is no update column list, we need to build\r
+                       ** out the result column list to have all columns.\r
+                       */\r
+                       if (ucl == null || (ucl.length == 0))\r
+                       {\r
+                               /*\r
+                               ** Get the resultColumnList representing ALL of the columns in the \r
+                               ** base table.  This is the "before" portion of the result row.\r
+                               */\r
+                               getResultColumnList();\r
+\r
+                               /*\r
+                               ** Add the "after" portion of the result row.  This is the update\r
+                               ** list augmented to include every column in the target table.\r
+                               ** Those columns that are not being updated are set to themselves.\r
+                               ** The expanded list will be in the order of the columns in the base\r
+                               ** table.\r
+                               */\r
+                               afterColumns = resultSet.getResultColumns().expandToAll(\r
+                                                                                                       targetTableDescriptor,\r
+                                                                                                       targetTable.getTableName());\r
+       \r
+                               /*\r
+                               ** Need to get all indexes here since we aren't calling\r
+                               ** getReadMap().\r
+                               */\r
+                               getAffectedIndexes(targetTableDescriptor, \r
+                                                                       (ResultColumnList)null, (FormatableBitSet)null); \r
+                               allColumns = true;\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Check the updatability */\r
+                               resultSet.getResultColumns().checkColumnUpdateability(ucl,\r
+                                                               currentOfNode.getCursorName());\r
+                       }\r
+               }\r
+\r
+               changedColumnIds = getChangedColumnIds(resultSet.getResultColumns());\r
+\r
+               /*\r
+               ** We need to add in all the columns that are needed\r
+               ** by the constraints on this table.  \r
+               */\r
+               if (!allColumns && targetVTI == null)\r
+               {\r
+                       getCompilerContext().pushCurrentPrivType( Authorizer.NULL_PRIV);\r
+                       try\r
+                       {\r
+                               readColsBitSet = new FormatableBitSet();\r
+                               FromBaseTable fbt = getResultColumnList(resultSet.getResultColumns());\r
+                               afterColumns = resultSet.getResultColumns().copyListAndObjects();\r
+\r
+                               readColsBitSet = getReadMap(dataDictionary, \r
+                                                                               targetTableDescriptor, \r
+                                                                               afterColumns);\r
+\r
+                               afterColumns = fbt.addColsToList(afterColumns, readColsBitSet);\r
+                               resultColumnList = fbt.addColsToList(resultColumnList, readColsBitSet);\r
+\r
+                               /*\r
+                               ** If all bits are set, then behave as if we chose all\r
+                               ** in the first place\r
+                               */\r
+                               int i = 1;\r
+                               int size = targetTableDescriptor.getMaxColumnID();\r
+                               for (; i <= size; i++)\r
+                               {\r
+                                       if (!readColsBitSet.get(i))\r
+                                       {\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if (i > size)\r
+                               {\r
+                                       readColsBitSet = null;\r
+                                       allColumns = true;\r
+                               }       \r
+                       }\r
+                       finally\r
+                       {\r
+                               getCompilerContext().popCurrentPrivType();\r
+                       }\r
+               }\r
+\r
+               if (targetVTI == null)\r
+               {\r
+                       /*\r
+                       ** Construct an empty heap row for use in our constant action.\r
+                       */\r
+                       emptyHeapRow = targetTableDescriptor.getEmptyExecRow();\r
+\r
+                       /* Append the list of "after" columns to the list of "before" columns,\r
+                        * preserving the afterColumns list.  (Necessary for binding\r
+                        * check constraints.)\r
+                        */\r
+                       resultColumnList.appendResultColumns(afterColumns, false);\r
+\r
+                       /* Generate the RowLocation column */\r
+                       rowLocationNode = (CurrentRowLocationNode) getNodeFactory().getNode(\r
+                                                                               C_NodeTypes.CURRENT_ROW_LOCATION_NODE,\r
+                                                                               getContextManager());\r
+        }\r
+        else\r
+        {\r
+                       rowLocationNode = (NumericConstantNode) getNodeFactory().getNode(\r
+                                                                               C_NodeTypes.INT_CONSTANT_NODE,\r
+                                        ReuseFactory.getInteger( 0),\r
+                                                                               getContextManager());\r
+        }\r
+            \r
+        rowLocationColumn =\r
+          (ResultColumn) getNodeFactory().getNode(\r
+              C_NodeTypes.RESULT_COLUMN,\r
+              COLUMNNAME,\r
+              rowLocationNode,\r
+              getContextManager());\r
+        rowLocationColumn.markGenerated();\r
+\r
+                       /* Append to the ResultColumnList */\r
+        resultColumnList.addResultColumn(rowLocationColumn);\r
+\r
+               /*\r
+                * The last thing that we do to the generated RCL is to clear\r
+                * the table name out from each RC. See comment on \r
+                * checkTableNameAndScrubResultColumns().\r
+                */\r
+               checkTableNameAndScrubResultColumns(resultColumnList);\r
+\r
+               /* Set the new result column list in the result set */\r
+               resultSet.setResultColumns(resultColumnList);\r
+\r
+               /* Bind the expressions */\r
+               getCompilerContext().pushCurrentPrivType(getPrivType()); // Update privilege\r
+               super.bindExpressions();\r
+               getCompilerContext().popCurrentPrivType();\r
+\r
+               /* Bind untyped nulls directly under the result columns */\r
+               resultSet.\r
+                       getResultColumns().\r
+                               bindUntypedNullsToResultColumns(resultColumnList);\r
+\r
+               if (null != rowLocationColumn)\r
+               {\r
+                       /* Bind the new ResultColumn */\r
+                       rowLocationColumn.bindResultColumnToExpression();\r
+               }\r
+\r
+               resultColumnList.checkStorableExpressions();\r
+\r
+               /* Insert a NormalizeResultSetNode above the source if the source\r
+                * and target column types and lengths do not match.\r
+                */\r
+               if (! resultColumnList.columnTypesAndLengthsMatch())\r
+               {\r
+                       resultSet = resultSet.genNormalizeResultSetNode(resultSet, true);\r
+                       resultColumnList.copyTypesAndLengthsToSource(resultSet.getResultColumns());\r
+                                                               \r
+                       if (hasCheckConstraints(dataDictionary, targetTableDescriptor))\r
+                       {\r
+                               /* Get and bind all check constraints on the columns\r
+                                * being updated.  We want to bind the check constraints against\r
+                                * the after columns.  We need to bind against the portion of the\r
+                                * resultColumns in the new NormalizeResultSet that point to \r
+                                * afterColumns.  Create an RCL composed of just those RCs in\r
+                                * order to bind the check constraints.\r
+                                */\r
+                               int afterColumnsSize = afterColumns.size();\r
+                               afterColumns = (ResultColumnList) getNodeFactory().getNode(\r
+                                                                                               C_NodeTypes.RESULT_COLUMN_LIST,\r
+                                                                                               getContextManager());\r
+                               ResultColumnList normalizedRCs = resultSet.getResultColumns();\r
+                               for (int index = 0; index < afterColumnsSize; index++)\r
+                               {\r
+                                       afterColumns.addElement(normalizedRCs.elementAt(index + afterColumnsSize));\r
+                               }\r
+                       }\r
+               }\r
+\r
+        if( null != targetVTI)\r
+               {\r
+            deferred = VTIDeferModPolicy.deferIt( DeferModification.UPDATE_STATEMENT,\r
+                                                  targetVTI,\r
+                                                  resultColumnList.getColumnNames(),\r
+                                                  sel.getWhereClause());\r
+               }\r
+        else // not VTI\r
+        {\r
+            /* we always include triggers in core language */\r
+            boolean hasTriggers = (getAllRelevantTriggers(dataDictionary, targetTableDescriptor, \r
+                                                          changedColumnIds, true).size() > 0);\r
+\r
+            /* Get and bind all constraints on the columns being updated */\r
+            checkConstraints = bindConstraints( dataDictionary,\r
+                                                getNodeFactory(),\r
+                                                targetTableDescriptor,\r
+                                                null,\r
+                                                hasTriggers ? resultColumnList : afterColumns,\r
+                                                changedColumnIds,\r
+                                                readColsBitSet,\r
+                                                false,\r
+                                                true); /* we always include triggers in core language */\r
+\r
+            /* If the target table is also a source table, then\r
+             * the update will have to be in deferred mode\r
+             * For updates, this means that the target table appears in a\r
+             * subquery.  Also, self referencing foreign keys are\r
+             * deferred.  And triggers cause an update to be deferred.\r
+             */\r
+            if (resultSet.subqueryReferencesTarget(\r
+                targetTableDescriptor.getName(), true) ||\r
+                requiresDeferredProcessing())\r
+            {\r
+                deferred = true;\r
+            }\r
+        }\r
+\r
+               getCompilerContext().popCurrentPrivType();              \r
+\r
+       } // end of bind()\r
+\r
+       int getPrivType()\r
+       {\r
+               return Authorizer.UPDATE_PRIV;\r
+       }\r
+\r
+       /**\r
+        * Return true if the node references SESSION schema tables (temporary or permanent)\r
+        *\r
+        * @return      true if references SESSION schema tables, else false\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public boolean referencesSessionSchema()\r
+               throws StandardException\r
+       {\r
+               //If this node references a SESSION schema table, then return true. \r
+               return(resultSet.referencesSessionSchema());\r
+\r
+       }\r
+\r
+       /**\r
+        * Compile constants that Execution will use\r
+        *\r
+        * @exception StandardException         Thrown on failure\r
+        */\r
+       public ConstantAction   makeConstantAction() throws StandardException\r
+       {\r
+               /*\r
+               ** Updates are also deferred if they update a column in the index\r
+               ** used to scan the table being updated.\r
+               */\r
+               if (! deferred )\r
+               {\r
+                       ConglomerateDescriptor updateCD =\r
+                                                                               targetTable.\r
+                                                                                       getTrulyTheBestAccessPath().\r
+                                                                                               getConglomerateDescriptor();\r
+\r
+                       if (updateCD != null && updateCD.isIndex())\r
+                       {\r
+                               int [] baseColumns =\r
+                                               updateCD.getIndexDescriptor().baseColumnPositions();\r
+\r
+                               if (resultSet.\r
+                                               getResultColumns().\r
+                                                                               updateOverlaps(baseColumns))\r
+                               {\r
+                                       deferred = true;\r
+                               }\r
+                       }\r
+               }\r
+\r
+        if( null == targetTableDescriptor)\r
+               {\r
+                       /* Return constant action for VTI\r
+                        * NOTE: ConstantAction responsible for preserving instantiated\r
+                        * VTIs for in-memory queries and for only preserving VTIs\r
+                        * that implement Serializable for SPSs.\r
+                        */\r
+                       return  getGenericConstantActionFactory().getUpdatableVTIConstantAction( DeferModification.UPDATE_STATEMENT,\r
+                                               deferred, changedColumnIds);\r
+               }\r
+\r
+               int lockMode = resultSet.updateTargetLockMode();\r
+               long heapConglomId = targetTableDescriptor.getHeapConglomerateId();\r
+               TransactionController tc = \r
+                       getLanguageConnectionContext().getTransactionCompile();\r
+               StaticCompiledOpenConglomInfo[] indexSCOCIs = \r
+                       new StaticCompiledOpenConglomInfo[indexConglomerateNumbers.length];\r
+\r
+               for (int index = 0; index < indexSCOCIs.length; index++)\r
+               {\r
+                       indexSCOCIs[index] = tc.getStaticCompiledConglomInfo(indexConglomerateNumbers[index]);\r
+               }\r
+\r
+               /*\r
+               ** Do table locking if the table's lock granularity is\r
+               ** set to table.\r
+               */\r
+               if (targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY)\r
+               {\r
+                       lockMode = TransactionController.MODE_TABLE;\r
+               }\r
+\r
+\r
+               return  getGenericConstantActionFactory().getUpdateConstantAction\r
+                       ( heapConglomId,\r
+                         targetTableDescriptor.getTableType(),\r
+                         tc.getStaticCompiledConglomInfo(heapConglomId),\r
+                         indicesToMaintain,\r
+                         indexConglomerateNumbers,\r
+                         indexSCOCIs,\r
+                         indexNames,\r
+                         emptyHeapRow,\r
+                         deferred,\r
+                         targetTableDescriptor.getUUID(),\r
+                         lockMode,\r
+                         false,\r
+                         changedColumnIds, null, null, \r
+                         getFKInfo(),\r
+                         getTriggerInfo(),\r
+                         (readColsBitSet == null) ? (FormatableBitSet)null : new FormatableBitSet(readColsBitSet),\r
+                         getReadColMap(targetTableDescriptor.getNumberOfColumns(),readColsBitSet),\r
+                         resultColumnList.getStreamStorableColIds(targetTableDescriptor.getNumberOfColumns()),\r
+                         (readColsBitSet == null) ? \r
+                                 targetTableDescriptor.getNumberOfColumns() :\r
+                                 readColsBitSet.getNumBitsSet(),                       \r
+                         positionedUpdate,\r
+                         resultSet.isOneRowResultSet()\r
+                         );\r
+       }\r
+\r
+       /**\r
+        * Updates are deferred if they update a column in the index\r
+        * used to scan the table being updated.\r
+        */\r
+       protected void setDeferredForUpdateOfIndexColumn()\r
+       {\r
+               /* Don't bother checking if we're already deferred */\r
+               if (! deferred )\r
+               {\r
+                       /* Get the conglomerate descriptor for the target table */\r
+                       ConglomerateDescriptor updateCD =\r
+                                                                               targetTable.\r
+                                                                                       getTrulyTheBestAccessPath().\r
+                                                                                               getConglomerateDescriptor();\r
+\r
+                       /* If it an index? */\r
+                       if (updateCD != null && updateCD.isIndex())\r
+                       {\r
+                               int [] baseColumns =\r
+                                               updateCD.getIndexDescriptor().baseColumnPositions();\r
+\r
+                               /* Are any of the index columns updated? */\r
+                               if (resultSet.\r
+                                               getResultColumns().\r
+                                                                               updateOverlaps(baseColumns))\r
+                               {\r
+                                       deferred = true;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Code generation for update.\r
+        * The generated code will contain:\r
+        *              o  A static member for the (xxx)ResultSet with the RowLocations and\r
+        *                 new update values\r
+        *              o  The static member will be assigned the appropriate ResultSet within\r
+        *                 the nested calls to get the ResultSets.  (The appropriate cast to the\r
+        *                 (xxx)ResultSet will be generated.)\r
+        *              o  The CurrentRowLocation() in SelectNode's select list will generate\r
+        *                 a new method for returning the RowLocation as well as a call to\r
+        *                 that method when generating the (xxx)ResultSet.\r
+        *\r
+        * @param acb   The ActivationClassBuilder for the class being built\r
+        * @param mb    The method for the execute() method to be built\r
+        *\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void generate(ActivationClassBuilder acb,\r
+                                                               MethodBuilder mb)\r
+                                                       throws StandardException\r
+       {\r
+               // If the DML is on the temporary table, generate the code to\r
+               // mark temporary table as modified in the current UOW. After\r
+               // DERBY-827 this must be done in execute() since\r
+               // fillResultSet() will only be called once.\r
+               generateCodeForTemporaryTable(acb, acb.getExecuteMethod());\r
+\r
+               /* generate the parameters */\r
+               if(!isDependentTable)\r
+                       generateParameterValueSet(acb);\r
+\r
+\r
+               /* Create the static declaration for the scan ResultSet which generates the\r
+                * RowLocations to be updated\r
+                * RESOLVE - Need to deal with the type of the static member.\r
+                */\r
+               acb.newFieldDeclaration(Modifier.PRIVATE, \r
+                                                               ClassName.CursorResultSet, \r
+                                                               acb.newRowLocationScanResultSetName());\r
+\r
+               /*\r
+               ** Generate the update result set, giving it either the original\r
+               ** source or the normalize result set, the constant action.\r
+               */\r
+\r
+               acb.pushGetResultSetFactoryExpression(mb);\r
+               resultSet.generate(acb, mb); // arg 1\r
+\r
+        if( null != targetVTI)\r
+        {\r
+                       targetVTI.assignCostEstimate(resultSet.getNewCostEstimate());\r
+            mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getUpdateVTIResultSet", ClassName.ResultSet, 1);\r
+               }\r
+        else\r
+        {\r
+            // generate code to evaluate CHECK CONSTRAINTS\r
+            generateCheckConstraints( checkConstraints, acb, mb ); // arg 2\r
+\r
+            if(isDependentTable)\r
+            {\r
+                mb.push(acb.addItem(makeConstantAction()));\r
+                mb.push(acb.addItem(makeResultDescription()));\r
+                mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getDeleteCascadeUpdateResultSet",\r
+                              ClassName.ResultSet, 4);\r
+            }else\r
+            {\r
+                mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getUpdateResultSet",\r
+                              ClassName.ResultSet, 2);\r
+            }\r
+        }\r
+       }\r
+\r
+       /**\r
+        * Return the type of statement, something from\r
+        * StatementType.\r
+        *\r
+        * @return the type of statement\r
+        */\r
+       protected final int getStatementType()\r
+       {\r
+               return StatementType.UPDATE;\r
+       }\r
+\r
+\r
+       /**\r
+        * Gets the map of all columns which must be read out of the base table.\r
+        * These are the columns needed to<UL>:\r
+        *              <LI>maintain indices</LI>\r
+        *              <LI>maintain foreign keys</LI>\r
+        *              <LI>support Replication's Delta Optimization</LI></UL>\r
+        * <p>\r
+        * The returned map is a FormatableBitSet with 1 bit for each column in the\r
+        * table plus an extra, unsued 0-bit. If a 1-based column id must\r
+        * be read from the base table, then the corresponding 1-based bit\r
+        * is turned ON in the returned FormatableBitSet.\r
+        * <p> \r
+        * <B>NOTE</B>: this method is not expected to be called when\r
+        * all columns are being updated (i.e. updateColumnList is null).\r
+        *\r
+        * @param dd                            the data dictionary to look in\r
+        * @param baseTable             the base table descriptor\r
+        * @param updateColumnList the rcl for the update. CANNOT BE NULL\r
+        *\r
+        * @return a FormatableBitSet of columns to be read out of the base table\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public  FormatableBitSet        getReadMap\r
+       (\r
+               DataDictionary          dd,\r
+               TableDescriptor         baseTable,\r
+               ResultColumnList        updateColumnList\r
+       )\r
+               throws StandardException\r
+       {\r
+               boolean[]       needsDeferredProcessing = new boolean[1];\r
+               needsDeferredProcessing[0] = requiresDeferredProcessing();\r
+\r
+               Vector          conglomVector = new Vector();\r
+               relevantCdl = new ConstraintDescriptorList();\r
+               relevantTriggers =  new GenericDescriptorList();\r
+\r
+               FormatableBitSet        columnMap = UpdateNode.getUpdateReadMap(baseTable,\r
+                       updateColumnList, conglomVector, relevantCdl, relevantTriggers, needsDeferredProcessing );\r
+\r
+               markAffectedIndexes( conglomVector );\r
+\r
+               adjustDeferredFlag( needsDeferredProcessing[0] );\r
+\r
+               return  columnMap;\r
+       }\r
+\r
+\r
+       /**\r
+        * Construct the changedColumnIds array. Note we sort its entries by\r
+        * columnId.\r
+        */\r
+       private int[] getChangedColumnIds(ResultColumnList rcl)\r
+       {\r
+               if (rcl == null) { return (int[])null; }\r
+               else { return rcl.sortMe(); }\r
+       }\r
+    /**\r
+         *     Builds a bitmap of all columns which should be read from the\r
+         *     Store in order to satisfy an UPDATE statement.\r
+         *\r
+         *     Is passed a list of updated columns. Does the following:\r
+         *\r
+         *     1)      finds all indices which overlap the updated columns\r
+         *     2)      adds the index columns to a bitmap of affected columns\r
+         *     3)      adds the index descriptors to a list of conglomerate\r
+         *             descriptors.\r
+         *     4)      finds all constraints which overlap the updated columns\r
+         *             and adds the constrained columns to the bitmap\r
+         *     5)      finds all triggers which overlap the updated columns.\r
+         *     6)      if there are any triggers, marks all columns in the bitmap\r
+         *     7)      adds the triggers to an evolving list of triggers\r
+         *\r
+         *     @param  updateColumnList        a list of updated columns\r
+         *     @param  conglomVector           OUT: vector of affected indices\r
+         *     @param  relevantConstraints     IN/OUT. Empty list is passed in. We hang constraints on it as we go.\r
+         *     @param  relevantTriggers        IN/OUT. Passed in as an empty list. Filled in as we go.\r
+         *     @param  needsDeferredProcessing IN/OUT. true if the statement already needs\r
+         *                                                                     deferred processing. set while evaluating this\r
+         *                                                                     routine if a trigger or constraint requires\r
+         *                                                                     deferred processing\r
+         *\r
+         * @return a FormatableBitSet of columns to be read out of the base table\r
+         *\r
+         * @exception StandardException                Thrown on error\r
+         */\r
+       public static FormatableBitSet getUpdateReadMap\r
+       (\r
+               TableDescriptor                         baseTable,\r
+               ResultColumnList                        updateColumnList,\r
+               Vector                                          conglomVector,\r
+               ConstraintDescriptorList        relevantConstraints,\r
+               GenericDescriptorList           relevantTriggers,\r
+               boolean[]                                       needsDeferredProcessing\r
+       )\r
+               throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(updateColumnList != null, "updateColumnList is null");\r
+               }\r
+\r
+               int             columnCount = baseTable.getMaxColumnID();\r
+               FormatableBitSet        columnMap = new FormatableBitSet(columnCount + 1);\r
+\r
+               /*\r
+               ** Add all the changed columns.  We don't strictly\r
+               ** need the before image of the changed column in all cases,\r
+               ** but it makes life much easier since things are set\r
+               ** up around the assumption that we have the before\r
+               ** and after image of the column.\r
+               */\r
+               int[]   changedColumnIds = updateColumnList.sortMe();\r
+\r
+               for (int ix = 0; ix < changedColumnIds.length; ix++)\r
+               {\r
+                       columnMap.set(changedColumnIds[ix]);\r
+               }\r
+\r
+               /* \r
+               ** Get a list of the indexes that need to be \r
+               ** updated.  ColumnMap contains all indexed\r
+               ** columns where 1 or more columns in the index\r
+               ** are going to be modified.\r
+               */\r
+               DMLModStatementNode.getXAffectedIndexes(baseTable, updateColumnList, columnMap, conglomVector );\r
\r
+               /* \r
+               ** Add all columns needed for constraints.  We don't\r
+               ** need to bother with foreign key/primary key constraints\r
+               ** because they are added as a side effect of adding\r
+               ** their indexes above.\r
+               */\r
+               baseTable.getAllRelevantConstraints\r
+                       ( StatementType.UPDATE, false, changedColumnIds, needsDeferredProcessing, relevantConstraints );\r
+\r
+               int rclSize = relevantConstraints.size();\r
+               for (int index = 0; index < rclSize; index++)\r
+               {\r
+                       ConstraintDescriptor cd = relevantConstraints.elementAt(index);\r
+                       if (cd.getConstraintType() != DataDictionary.CHECK_CONSTRAINT)\r
+                       {\r
+                               continue;\r
+                       }\r
+\r
+                       int[] refColumns = ((CheckConstraintDescriptor)cd).getReferencedColumns();\r
+                       for (int i = 0; i < refColumns.length; i++)\r
+                       {\r
+                               columnMap.set(refColumns[i]);\r
+                       }\r
+               }\r
+\r
+               /*\r
+               ** If we have any triggers, then get all the columns\r
+               ** because we don't know what the user will ultimately\r
+               ** reference.\r
+               */\r
+\r
+               baseTable.getAllRelevantTriggers( StatementType.UPDATE, changedColumnIds, relevantTriggers );\r
+               if ( relevantTriggers.size() > 0 ) { needsDeferredProcessing[0] = true; }\r
+\r
+               if (relevantTriggers.size() > 0)\r
+               {\r
+                       for (int i = 1; i <= columnCount; i++)\r
+                       {\r
+                               columnMap.set(i);\r
+                       }\r
+               }\r
+\r
+               return  columnMap;\r
+       }\r
+\r
+       /*\r
+        * Force correlated column references in the SET clause to have the\r
+        * name of the base table. This dances around the problem alluded to\r
+        * in scrubResultColumn().\r
+        */\r
+       private void    normalizeCorrelatedColumns( ResultColumnList rcl, FromTable fromTable )\r
+               throws StandardException\r
+       {\r
+               String          correlationName = fromTable.getCorrelationName();\r
+\r
+               if ( correlationName == null ) { return; }\r
+\r
+               TableName       tableNameNode;\r
+\r
+               if ( fromTable instanceof CurrentOfNode )\r
+               { tableNameNode = ((CurrentOfNode) fromTable).getBaseCursorTargetTableName(); }\r
+               else { tableNameNode = makeTableName( null, fromTable.getBaseTableName() ); }\r
+               \r
+               int                     count = rcl.size();\r
+\r
+               for ( int i = 0; i < count; i++ )\r
+               {\r
+                       ResultColumn    column = (ResultColumn) rcl.elementAt( i );\r
+                       ColumnReference reference = column.getReference();\r
+\r
+                       if ( (reference != null) && correlationName.equals( reference.getTableName() ) )\r
+                       {\r
+                               reference.setTableNameNode( tableNameNode );\r
+                       }\r
+               }\r
+               \r
+       }\r
+\r
+       /**\r
+        * Check table name and then clear it from the result set columns.\r
+        * \r
+        * @exception StandardExcepion if invalid column/table is specified.\r
+        */\r
+       private void checkTableNameAndScrubResultColumns(ResultColumnList rcl) \r
+                       throws StandardException\r
+       {\r
+               int columnCount = rcl.size();\r
+               int tableCount = ((SelectNode)resultSet).fromList.size();\r
+\r
+               for ( int i = 0; i < columnCount; i++ )\r
+               {\r
+                       boolean foundMatchingTable = false;                     \r
+                       ResultColumn    column = (ResultColumn) rcl.elementAt( i );\r
+\r
+                       if (column.getTableName() != null) {\r
+                               for (int j = 0; j < tableCount; j++) {\r
+                                       FromTable fromTable = (FromTable) ((SelectNode)resultSet).\r
+                                                       fromList.elementAt(j);\r
+                                       final String tableName;\r
+                                       if ( fromTable instanceof CurrentOfNode ) { \r
+                                               tableName = ((CurrentOfNode)fromTable).\r
+                                                               getBaseCursorTargetTableName().getTableName();\r
+                                       } else { \r
+                                               tableName = fromTable.getBaseTableName();\r
+                                       }\r
+\r
+                                       if (column.getTableName().equals(tableName)) {\r
+                                               foundMatchingTable = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if (!foundMatchingTable) {\r
+                                       throw StandardException.newException(\r
+                                                       SQLState.LANG_COLUMN_NOT_FOUND, \r
+                                                       column.getTableName() + "." + column.getName());\r
+                               }\r
+                       }\r
+\r
+                       /* The table name is\r
+                        * unnecessary for an update.  More importantly, though, it\r
+                        * creates a problem in the degenerate case with a positioned\r
+                        * update.  The user must specify the base table name for a\r
+                        * positioned update.  If a correlation name was specified for\r
+                        * the cursor, then a match for the ColumnReference would not\r
+                        * be found if we didn't null out the name.  (Aren't you\r
+                        * glad you asked?)\r
+                        */\r
+                       column.clearTableName();\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Normalize synonym column references to have the name of the base table. \r
+        *\r
+        * @param rcl       The result column list of the target table\r
+        * @param fromTable The table name to set the column refs to\r
+        * \r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       private void normalizeSynonymColumns(\r
+    ResultColumnList    rcl, \r
+    FromTable           fromTable)\r
+               throws StandardException\r
+       {\r
+               if (fromTable.getCorrelationName() != null) \r
+        { \r
+            return; \r
+        }\r
+               \r
+               TableName tableNameNode;\r
+               if (fromTable instanceof CurrentOfNode)\r
+               { \r
+                       tableNameNode = \r
+                ((CurrentOfNode) fromTable).getBaseCursorTargetTableName(); \r
+               }\r
+               else \r
+               { \r
+                       tableNameNode = makeTableName(null, fromTable.getBaseTableName()); \r
+               }\r
+               \r
+               super.normalizeSynonymColumns(rcl, tableNameNode);\r
+       }\r
+       \r
+} // end of UpdateNode\r