Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / compile / InsertNode.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java
new file mode 100644 (file)
index 0000000..ad199ff
--- /dev/null
@@ -0,0 +1,937 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.InsertNode\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.JavaFactory;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+import org.apache.derby.iapi.sql.compile.CompilerContext;\r
+\r
+import org.apache.derby.iapi.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.IndexLister;\r
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\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.vti.DeferModification;\r
+\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+import org.apache.derby.iapi.util.StringUtil;\r
+\r
+import org.apache.derby.catalog.UUID;\r
+\r
+import org.apache.derby.impl.sql.execute.FKInfo;\r
+\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.util.ReuseFactory;\r
+\r
+/**\r
+ * An InsertNode is the top node in a query tree for an\r
+ * insert statement.\r
+ * <p>\r
+ * After parsing, the node contains\r
+ *   targetTableName: the target table for the insert\r
+ *   collist: a list of column names, if specified\r
+ *   queryexpr: the expression being inserted, either\r
+ *                             a values clause or a select form; both\r
+ *                         of these are represented via the SelectNode,\r
+ *                             potentially with a TableOperatorNode such as\r
+ *                             UnionNode above it.\r
+ * <p>\r
+ * After binding, the node has had the target table's\r
+ * descriptor located and inserted, and the queryexpr\r
+ * and collist have been massaged so that they are identical\r
+ * to the table layout.  This involves adding any default\r
+ * values for missing columns, and reordering the columns\r
+ * to match the table's ordering of them.\r
+ * <p>\r
+ * After optimizing, ...\r
+ */\r
+public final class InsertNode extends DMLModStatementNode\r
+{\r
+       public          ResultColumnList        targetColumnList;\r
+       public          boolean                         deferred;\r
+       public          ValueNode                       checkConstraints;\r
+       public          Properties                      targetProperties;\r
+       public          FKInfo                          fkInfo;\r
+       protected       boolean                         bulkInsert;\r
+       private         boolean                         bulkInsertReplace;\r
+       \r
+       protected   RowLocation[]               autoincRowLocation;\r
+       /**\r
+        * Initializer for an InsertNode.\r
+        *\r
+        * @param targetName    The name of the table/VTI to insert into\r
+        * @param insertColumns A ResultColumnList with the names of the\r
+        *                      columns to insert into.  May be null if the\r
+        *                      user did not specify the columns - in this\r
+        *                      case, the binding phase will have to figure\r
+        *                      it out.\r
+        * @param queryExpression       The query expression that will generate\r
+        *                              the rows to insert into the given table\r
+        * @param targetProperties      The properties specified on the target table\r
+        */\r
+\r
+       public void init(\r
+                       Object targetName,\r
+                       Object insertColumns,\r
+                       Object queryExpression,\r
+                       Object targetProperties)\r
+       {\r
+               /* statementType gets set in super() before we've validated\r
+                * any properties, so we've kludged the code to get the\r
+                * right statementType for a bulk insert replace.\r
+                */\r
+               super.init(\r
+                               queryExpression,\r
+                               ReuseFactory.getInteger(getStatementType(\r
+                                                                                               (Properties) targetProperties))\r
+                               );\r
+               setTarget((QueryTreeNode) targetName);\r
+               targetColumnList = (ResultColumnList) insertColumns;\r
+               this.targetProperties = (Properties) targetProperties;\r
+\r
+               /* Remember that the query expression is the source to an INSERT */\r
+               getResultSetNode().setInsertSource();\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
+            try {\r
+                return ( (targetTableName!=null) ? targetTableName : targetVTI.getTableName() ).toString() + "\n"\r
+                    + targetProperties + "\n"\r
+                    + super.toString();\r
+            } catch (org.apache.derby.iapi.error.StandardException e) {\r
+                return "tableName: <not_known>\n"\r
+                    + targetProperties + "\n"\r
+                    + super.toString();\r
+            }\r
+               }\r
+               else\r
+               {\r
+                       return "";\r
+               }\r
+       }\r
+\r
+       public String statementToString()\r
+       {\r
+               return "INSERT";\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
+                       if (targetColumnList != null)\r
+                       {\r
+                               printLabel(depth, "targetColumnList: ");\r
+                               targetColumnList.treePrint(depth + 1);\r
+                       }\r
+\r
+                       /* RESOLVE - need to print out targetTableDescriptor */\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Bind this InsertNode.  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 insert will also massage the tree so that\r
+        * the collist and select column order/number are the\r
+        * same as the layout of the table in the store. \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
+\r
+               /* If any underlying ResultSetNode is a SelectNode, then we\r
+                * need to do a full bind(), including the expressions\r
+                * (since the fromList may include a FromSubquery).\r
+                */\r
+        DataDictionary dataDictionary = getDataDictionary();\r
+               super.bindResultSetsWithTables(dataDictionary);\r
+\r
+               /*\r
+               ** Get the TableDescriptor for the table we are inserting into\r
+               */\r
+               verifyTargetTable();\r
+\r
+               // Check the validity of the targetProperties, if they exist\r
+               if (targetProperties != null)\r
+               {\r
+                       verifyTargetProperties(dataDictionary);\r
+               }\r
+\r
+               /*\r
+               ** Get the resultColumnList representing the columns in the base\r
+               ** table or VTI.\r
+               */\r
+               getResultColumnList();\r
+\r
+               /* If we have a target column list, then it must have the same # of\r
+                * entries as the result set's RCL.\r
+                */\r
+               if (targetColumnList != null)\r
+               {\r
+                       /*\r
+                        * Normalize synonym qualifers for column references.\r
+                        */\r
+                       if (synonymTableName != null)\r
+                       {\r
+                               normalizeSynonymColumns ( targetColumnList, targetTableName );\r
+                       }\r
+                       \r
+                       /* Bind the target column list */\r
+                       getCompilerContext().pushCurrentPrivType( getPrivType());\r
+                       if (targetTableDescriptor != null)\r
+                       {\r
+                               targetColumnList.bindResultColumnsByName(targetTableDescriptor,\r
+                                                                                                               (DMLStatementNode) this);\r
+                       }\r
+                       else\r
+                       {\r
+                               targetColumnList.bindResultColumnsByName(targetVTI.getResultColumns(), targetVTI,\r
+                                                                                                               this);\r
+                       }\r
+                       getCompilerContext().popCurrentPrivType();\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
+               /* Replace any DEFAULTs with the associated tree */\r
+               resultSet.replaceDefaults(targetTableDescriptor, targetColumnList);\r
+\r
+               /* Bind the expressions now that the result columns are bound \r
+                * NOTE: This will be the 2nd time for those underlying ResultSets\r
+                * that have tables (no harm done), but it is necessary for those\r
+                * that do not have tables.  It's too hard/not work the effort to\r
+                * avoid the redundancy.\r
+                */\r
+               super.bindExpressions();\r
+\r
+               /*\r
+               ** If the result set is a union, it could be a table constructor.\r
+               ** Bind any nulls in the result columns of the table constructor\r
+               ** to the types of the table being inserted into.\r
+               **\r
+               ** The types of ? parameters in row constructors and table constructors\r
+               ** in an INSERT statement come from the result columns.\r
+               **\r
+               ** If there is a target column list, use that instead of the result\r
+               ** columns for the whole table, since the columns in the result set\r
+               ** correspond to the target column list.\r
+               */\r
+               if (targetColumnList != null)\r
+               {\r
+                       if (resultSet.getResultColumns().visibleSize() > targetColumnList.size())\r
+                               throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED); \r
+                       resultSet.bindUntypedNullsToResultColumns(targetColumnList);\r
+                       resultSet.setTableConstructorTypes(targetColumnList);\r
+               }\r
+               else\r
+               {\r
+                       if (resultSet.getResultColumns().visibleSize() > resultColumnList.size())\r
+                               throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED); \r
+                       resultSet.bindUntypedNullsToResultColumns(resultColumnList);\r
+                       resultSet.setTableConstructorTypes(resultColumnList);\r
+               }\r
+\r
+               /* Bind the columns of the result set to their expressions */\r
+               resultSet.bindResultColumns(fromList);\r
+\r
+               int resCols = resultSet.getResultColumns().visibleSize();\r
+               DataDictionary dd = getDataDictionary();\r
+               if (targetColumnList != null)\r
+               {\r
+                       if (targetColumnList.size() != resCols)\r
+                               throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED); \r
+               }\r
+               else \r
+               {\r
+                       if (targetTableDescriptor != null &&\r
+                                               targetTableDescriptor.getNumberOfColumns() != resCols)\r
+                               throw StandardException.newException(SQLState.LANG_DB2_INVALID_COLS_SPECIFIED); \r
+               }\r
+\r
+               /* See if the ResultSet's RCL needs to be ordered to match the target\r
+                * list, or "enhanced" to accommodate defaults.  It can only need to\r
+                * be ordered if there is a target column list.  It needs to be\r
+                * enhanced if there are fewer source columns than there are columns\r
+                * in the table.\r
+                */\r
+               boolean inOrder = true;\r
+               int numTableColumns = resultColumnList.size();\r
+\r
+               /* colMap[] will be the size of the target list, which could be larger\r
+                * than the current size of the source list.  In that case, the source\r
+                * list will be "enhanced" to include defaults.\r
+                */\r
+               int[] colMap = new int[numTableColumns];\r
+\r
+               // set the fields to an unused value\r
+               for (int i = 0; i < colMap.length; i++) \r
+               {\r
+                       colMap[i] = -1;\r
+               }\r
+\r
+               /* Create the source/target list mapping */\r
+               if (targetColumnList != null)\r
+               {\r
+                       /*\r
+                       ** There is a target column list, so the result columns might\r
+                       ** need to be ordered.  Step through the target column list\r
+                       ** and remember the position in the target table of each column.\r
+                       ** Remember if any of the columns are out of order.\r
+                       */\r
+                       int targetSize = targetColumnList.size();\r
+                       for (int index = 0; index < targetSize; index++)\r
+                       {\r
+                               int position =\r
+                                       ((ResultColumn) (targetColumnList.elementAt(index))).\r
+                                                                                               columnDescriptor.getPosition();\r
+\r
+                               if (index != position-1)\r
+                               {\r
+                                       inOrder = false;\r
+                               }\r
+\r
+                               // position is 1-base; colMap indexes and entries are 0-based.\r
+                               colMap[position-1] = index;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       /*\r
+                       ** There is no target column list, so the result columns in the\r
+                       ** source are presumed to be in the same order as the target\r
+                       ** table.\r
+                       */\r
+                       for (int position = 0;\r
+                               position < resultSet.getResultColumns().visibleSize();\r
+                               position++)\r
+                       {\r
+                               colMap[position] = position;\r
+                       }\r
+               }\r
+\r
+               enhanceAndCheckForAutoincrement(resultSet, inOrder,\r
+                               numTableColumns, colMap, dataDictionary,\r
+                               targetTableDescriptor, targetVTI);\r
+\r
+               resultColumnList.checkStorableExpressions(resultSet.getResultColumns());\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
+                                                                                               resultSet.getResultColumns()))\r
+               {\r
+                       resultSet = resultSet.genNormalizeResultSetNode(resultSet, false);\r
+                       resultColumnList.copyTypesAndLengthsToSource(resultSet.getResultColumns());\r
+               }\r
+\r
+               if (targetTableDescriptor != null)\r
+               {\r
+                       /* Get and bind all constraints on the table */\r
+                       ResultColumnList sourceRCL = resultSet.getResultColumns();\r
+                       sourceRCL.copyResultColumnNames(resultColumnList);\r
+                       checkConstraints = bindConstraints(dataDictionary,\r
+                                                                                               getNodeFactory(),\r
+                                                                                               targetTableDescriptor,\r
+                                                                                               null,\r
+                                                                                               sourceRCL,\r
+                                                                                               (int[]) null,\r
+                                                                                               (FormatableBitSet) null,\r
+                                                                                               false,\r
+                                                                                           true);  /* we always include\r
+                                                                                                                * triggers in core language */\r
+       \r
+                       /* Do we need to do a deferred mode insert */\r
+                       /* \r
+                       ** Deferred if:\r
+                       **      If the target table is also a source table\r
+                       **      Self-referencing foreign key constraint \r
+                       **      trigger\r
+                       */\r
+                       if (resultSet.referencesTarget(\r
+                                                                       targetTableDescriptor.getName(), true) ||\r
+                                requiresDeferredProcessing())\r
+                       {\r
+                               deferred = true;\r
+\r
+                               /* Disallow bulk insert replace when target table\r
+                                * is also a source table.\r
+                                */\r
+                               if (bulkInsertReplace &&\r
+                                       resultSet.referencesTarget(\r
+                                                                       targetTableDescriptor.getName(), true))\r
+                               {\r
+                                       throw StandardException.newException(SQLState.LANG_INVALID_BULK_INSERT_REPLACE, \r
+                                                                       targetTableDescriptor.getQualifiedName());\r
+                               }\r
+                       }\r
+\r
+                       /* Get the list of indexes on the table being inserted into */\r
+                       getAffectedIndexes(targetTableDescriptor);\r
+                       TransactionController tc = \r
+                               getLanguageConnectionContext().getTransactionCompile();\r
+\r
+                       autoincRowLocation = \r
+                               dd.computeAutoincRowLocations(tc, targetTableDescriptor);\r
+\r
+                       if (isPrivilegeCollectionRequired())\r
+                       {\r
+                               getCompilerContext().pushCurrentPrivType(getPrivType());\r
+                               getCompilerContext().addRequiredTablePriv(targetTableDescriptor);\r
+                               getCompilerContext().popCurrentPrivType();                              \r
+                       }\r
+\r
+               }\r
+               else\r
+               {\r
+            deferred = VTIDeferModPolicy.deferIt( DeferModification.INSERT_STATEMENT,\r
+                                                  targetVTI,\r
+                                                  null,\r
+                                                  resultSet);\r
+               }\r
+        \r
+               getCompilerContext().popCurrentPrivType();\r
+       }\r
+\r
+       /**\r
+        * Process ResultSet column lists for projection and autoincrement.\r
+        *\r
+        * This method recursively descends the result set node tree. When\r
+        * it finds a simple result set, it processes any autoincrement\r
+        * columns in that rs by calling checkAutoIncrement. When it finds\r
+        * a compound result set, like a Union or a PRN, it recursively\r
+        * descends to the child(ren) nodes. Union nodes can arise due to\r
+        * multi-rows in VALUES clause), PRN nodes can arise when the set\r
+        * of columns being inserted is a subset of the set of columns in \r
+        * the table.\r
+        *\r
+        * In addition to checking for autoincrement columns in the result set,\r
+        * we may need to enhance and re-order the column list to match the\r
+        * column list of the table we are inserting into. This work is handled\r
+        * by ResultsetNode.enhanceRCLForInsert.\r
+        *\r
+        * Note that, at the leaf level, we need to enhance the RCL first, then\r
+        * check for autoincrement columns. At the non-leaf levels, we have\r
+        * to enhance the RCL, but we don't have to check for autoincrement\r
+        * columns, since they only occur at the leaf level.\r
+        *\r
+        * This way, all ColumnDescriptor of all rows will be set properly.\r
+        *\r
+        * @param resultSet                     current node in the result set tree\r
+        * @param inOrder                       FALSE if the column list needs reordering\r
+        * @param numTableColumns   # of columns in target RCL\r
+        * @param colMap            correspondence between RCLs\r
+        * @param dataDictionary    DataDictionary to use\r
+        * @param targetTableDescriptor    Table Descriptor for target\r
+        * @param targetVTI         Target description if it is a VTI\r
+        *\r
+        * @exception StandardException Thrown on error\r
+        */\r
+       private void enhanceAndCheckForAutoincrement(ResultSetNode resultSet, \r
+                       boolean inOrder, int numTableColumns, int []colMap, \r
+                       DataDictionary dataDictionary,\r
+                       TableDescriptor targetTableDescriptor,\r
+                       FromVTI targetVTI)\r
+               throws StandardException\r
+       {\r
+               /*\r
+                * Some implementation notes:\r
+                * \r
+                * colmap[x] == y means that column x in the target table\r
+                * maps to column y in the source result set.\r
+                * colmap[x] == -1 means that column x in the target table\r
+                * maps to its default value.\r
+                * both colmap indexes and values are 0-based.\r
+                *\r
+                * if the list is in order and complete, we don't have to change\r
+                * the tree. If it is not, then we call RSN.enhanceRCLForInsert() \r
+                * which will reorder ("enhance") the source RCL within the same RSN)\r
+                *\r
+                * one thing we do know is that all of the resultsets underneath\r
+                * us have their resultColumn names filled in with the names of\r
+                * the target table columns.  That makes generating the mapping\r
+                * "easier" -- we simply generate the names of the target table columns\r
+                * that are included.  For the missing columns, we generate default\r
+                * value expressions.\r
+                */\r
+\r
+               if (resultSet instanceof SingleChildResultSetNode)\r
+               {\r
+                       enhanceAndCheckForAutoincrement(\r
+                               ((SingleChildResultSetNode)resultSet).getChildResult(),\r
+                               inOrder, numTableColumns, colMap, dataDictionary,\r
+                               targetTableDescriptor, targetVTI);\r
+                       if (! inOrder || resultSet.resultColumns.size() < numTableColumns)\r
+                               resultSet.enhanceRCLForInsert(\r
+                                               numTableColumns, colMap, dataDictionary,\r
+                                               targetTableDescriptor, targetVTI);\r
+               }\r
+               else if (resultSet instanceof UnionNode)\r
+               {\r
+                       enhanceAndCheckForAutoincrement(\r
+                               ((TableOperatorNode)resultSet).getLeftResultSet(),\r
+                               inOrder, numTableColumns, colMap, dataDictionary,\r
+                               targetTableDescriptor, targetVTI);\r
+                       enhanceAndCheckForAutoincrement(\r
+                               ((TableOperatorNode)resultSet).getRightResultSet(),\r
+                               inOrder, numTableColumns, colMap, dataDictionary,\r
+                               targetTableDescriptor, targetVTI);\r
+                       if (! inOrder || resultSet.resultColumns.size() < numTableColumns)\r
+                               resultSet.enhanceRCLForInsert(\r
+                                               numTableColumns, colMap, dataDictionary,\r
+                                               targetTableDescriptor, targetVTI);\r
+               }\r
+               else\r
+               {\r
+                       if (! inOrder || resultSet.resultColumns.size() < numTableColumns)\r
+                               resultSet.enhanceRCLForInsert(\r
+                                               numTableColumns, colMap, dataDictionary,\r
+                                               targetTableDescriptor, targetVTI);\r
+                       resultColumnList.checkAutoincrement(resultSet.getResultColumns());\r
+               }\r
+       }\r
+\r
+       int getPrivType()\r
+       {\r
+               return Authorizer.INSERT_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
+               boolean returnValue = false;\r
+\r
+               //If this node references a SESSION schema table, then return true. \r
+               if (targetTableDescriptor != null)\r
+                       returnValue = isSessionSchema(targetTableDescriptor.getSchemaDescriptor());\r
+\r
+               if (returnValue == false)\r
+                       returnValue = resultSet.referencesSessionSchema();\r
+\r
+               return returnValue;\r
+       }\r
+\r
+       /**\r
+        * Verify that the target properties that we are interested in\r
+        * all hold valid values.\r
+        * NOTE: Any target property which is valid but cannot be supported\r
+        * due to a target database, etc. will be turned off quietly.\r
+        *\r
+        * @param dd    The DataDictionary\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       private void verifyTargetProperties(DataDictionary dd)\r
+               throws StandardException\r
+       {\r
+               // The only property that we're currently interested in is insertMode\r
+               String insertMode = targetProperties.getProperty("insertMode");\r
+               if (insertMode != null)\r
+               {\r
+                       String upperValue = StringUtil.SQLToUpperCase(insertMode);\r
+                       if (! upperValue.equals("BULKINSERT") &&\r
+                               ! upperValue.equals("REPLACE"))\r
+                       {\r
+                               throw StandardException.newException(SQLState.LANG_INVALID_INSERT_MODE, \r
+                                                               insertMode,\r
+                                                               targetTableName);\r
+                       }\r
+                       else\r
+                       {\r
+                               /* Turn off bulkInsert if it is on and we can't support it. */\r
+                               if (! verifyBulkInsert(dd, upperValue))\r
+                               {\r
+                                       targetProperties.remove("insertMode");\r
+                               }\r
+                               else\r
+                               {\r
+                                       /* Now we know we're doing bulk insert */\r
+                                       bulkInsert = true;\r
+\r
+                                       if (upperValue.equals("REPLACE"))\r
+                                       {\r
+                                               bulkInsertReplace = true;\r
+                                       }\r
+\r
+                                       // Validate the bulkFetch property if specified\r
+                                       String bulkFetchStr = targetProperties.getProperty("bulkFetch");\r
+                                       if (bulkFetchStr != null)\r
+                                       {\r
+                                               int bulkFetch = getIntProperty(bulkFetchStr, "bulkFetch");\r
+\r
+                                               // verify that the specified value is valid\r
+                                               if (bulkFetch <= 0)\r
+                                               {\r
+                                                       throw StandardException.newException(SQLState.LANG_INVALID_BULK_FETCH_VALUE,\r
+                                                                       String.valueOf(bulkFetch));\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Do the bind time checks to see if bulkInsert is allowed on\r
+        * this table.  bulkInsert is disallowed at bind time for:\r
+        *              o  target databases\r
+        *              o  (tables with triggers?)\r
+        * (It is disallowed at execution time if the table has at\r
+        * least 1 row in it or if it is a deferred mode insert.)\r
+        *\r
+        * @param dd    The DataDictionary\r
+        * @param mode  The insert mode\r
+        *\r
+        * @return Whether or not bulkInsert is allowed.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       private boolean verifyBulkInsert(DataDictionary dd, String mode)\r
+               throws StandardException\r
+       {\r
+               return true;\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
+               /* Different constant actions for base tables and updatable VTIs */\r
+               if (targetTableDescriptor != null)\r
+               {\r
+                       // Base table\r
+\r
+                       long heapConglomId = targetTableDescriptor.getHeapConglomerateId();\r
+                       TransactionController tc = \r
+                               getLanguageConnectionContext().getTransactionCompile();\r
+                       int numIndexes = (targetTableDescriptor != null) ?\r
+                                                               indexConglomerateNumbers.length : 0;\r
+                       StaticCompiledOpenConglomInfo[] indexSCOCIs = \r
+                               new StaticCompiledOpenConglomInfo[numIndexes];\r
+\r
+                       for (int index = 0; index < numIndexes; index++)\r
+                       {\r
+                               indexSCOCIs[index] = tc.getStaticCompiledConglomInfo(indexConglomerateNumbers[index]);\r
+                       }\r
+\r
+                       /*\r
+                       ** If we're doing bulk insert, do table locking regardless of\r
+                       ** what the optimizer decided.  This is because bulk insert is\r
+                       ** generally done with a large number of rows into an empty table.\r
+                       ** We also do table locking if the table's lock granularity is\r
+                       ** set to table.\r
+                       */\r
+                       if (bulkInsert ||\r
+                               targetTableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY)\r
+                       {\r
+                               lockMode = TransactionController.MODE_TABLE;\r
+                       }\r
+\r
+                       return  getGenericConstantActionFactory().getInsertConstantAction\r
+                               ( targetTableDescriptor,\r
+                                 heapConglomId,\r
+                                 tc.getStaticCompiledConglomInfo(heapConglomId),\r
+                                 indicesToMaintain,\r
+                                 indexConglomerateNumbers,\r
+                                 indexSCOCIs,\r
+                                 indexNames,\r
+                                 deferred,\r
+                                 false,\r
+                                 targetTableDescriptor.getUUID(),\r
+                                 lockMode,\r
+                                 null, null, \r
+                                 targetProperties,\r
+                                 getFKInfo(),\r
+                                 getTriggerInfo(),\r
+                                 resultColumnList.getStreamStorableColIds(targetTableDescriptor.getNumberOfColumns()),\r
+                                 getIndexedCols(),\r
+                                 (UUID) null,\r
+                                 null,\r
+                                 null,\r
+                                 resultSet.isOneRowResultSet(), \r
+                                 autoincRowLocation\r
+                                 );\r
+               }\r
+               else\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.INSERT_STATEMENT,\r
+                                               deferred);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Create a boolean[] to track the (0-based) columns which are indexed.\r
+        *\r
+        * @return A boolean[] to track the (0-based) columns which are indexed.\r
+        *\r
+        * @exception StandardException         Thrown on failure\r
+        */\r
+       public boolean[] getIndexedCols() throws StandardException\r
+       {\r
+               /* Create a boolean[] to track the (0-based) columns which are indexed */\r
+               boolean[] indexedCols = new boolean[targetTableDescriptor.getNumberOfColumns()];\r
+               for (int index = 0; index < indicesToMaintain.length; index++)\r
+               {\r
+                       int[] colIds = indicesToMaintain[index].getIndexDescriptor().baseColumnPositions();\r
+\r
+                       for (int index2 = 0; index2 < colIds.length; index2++)\r
+                       {\r
+                               indexedCols[colIds[index2] - 1] = true;\r
+                       }\r
+               }\r
+\r
+               return indexedCols;\r
+       }\r
+\r
+       /**\r
+        * Code generation for insert\r
+        * creates an expression for:\r
+        *   ResultSetFactory.getInsertResultSet(resultSet.generate(ps), this )\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
+        * @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
+               generateParameterValueSet(acb);\r
+               // Base table\r
+               if (targetTableDescriptor != null)\r
+               {\r
+                       /*\r
+                       ** Generate the insert result set, giving it either the original\r
+                       ** source or the normalize result set, the constant action,\r
+                       ** and "this".\r
+                       */\r
+\r
+                       acb.pushGetResultSetFactoryExpression(mb);\r
+\r
+                       // arg 1\r
+                       resultSet.generate(acb, mb);\r
+\r
+                       // arg 2 generate code to evaluate CHECK CONSTRAINTS\r
+                       generateCheckConstraints( checkConstraints, acb, mb );\r
+\r
+                       mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getInsertResultSet", ClassName.ResultSet, 2);\r
+               }\r
+               else\r
+               {\r
+                       /* Generate code for the VTI\r
+                        * NOTE: we need to create a dummy cost estimate for the\r
+                        * targetVTI since we never optimized it.\r
+                        * RESOLVEVTI - we will have to optimize it in order to \r
+                        * push predicates into the VTI.\r
+                        */\r
+                       targetVTI.assignCostEstimate(resultSet.getNewCostEstimate());\r
+\r
+                       /*\r
+                       ** Generate the insert VTI result set, giving it either the original\r
+                       ** source or the normalize result set, the constant action,\r
+                       */\r
+                       acb.pushGetResultSetFactoryExpression(mb);\r
+\r
+                       // arg 1\r
+                       resultSet.generate(acb, mb);\r
+\r
+                       // arg 2\r
+                       targetVTI.generate(acb, mb);\r
+\r
+                       mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getInsertVTIResultSet", ClassName.ResultSet, 2);\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.INSERT;\r
+       }\r
+\r
+       /**\r
+        * Return the statement type, where it is dependent on\r
+        * the targetProperties.  (insertMode = replace causes\r
+        * statement type to be BULK_INSERT_REPLACE.\r
+        *\r
+        * @return the type of statement\r
+        */\r
+       static final int getStatementType(Properties targetProperties)\r
+       {\r
+               int retval = StatementType.INSERT;\r
+\r
+               // The only property that we're currently interested in is insertMode\r
+               String insertMode = (targetProperties == null) ? null : targetProperties.getProperty("insertMode");\r
+               if (insertMode != null)\r
+               {\r
+                       String upperValue = StringUtil.SQLToUpperCase(insertMode);\r
+                       if (upperValue.equals("REPLACE"))\r
+                       {\r
+                               retval = StatementType.BULK_INSERT_REPLACE;\r
+                       }\r
+               }\r
+               return retval;\r
+       }\r
+\r
+       /**\r
+        * Get the list of indexes on the table being inserted into.  This\r
+        * is used by INSERT.  This is an optimized version of what\r
+        * UPDATE and DELETE use. \r
+        *\r
+        * @param td    TableDescriptor for the table being inserted into\r
+        *                              or deleted from\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       private void getAffectedIndexes\r
+       (\r
+               TableDescriptor         td\r
+       )       \r
+                                       throws StandardException\r
+       {\r
+               IndexLister     indexLister = td.getIndexLister( );\r
+\r
+               indicesToMaintain = indexLister.getDistinctIndexRowGenerators();\r
+               indexConglomerateNumbers = indexLister.getDistinctIndexConglomerateNumbers();\r
+               indexNames = indexLister.getDistinctIndexNames();\r
+\r
+               /* Add dependencies on all indexes in the list */\r
+               ConglomerateDescriptor[]        cds = td.getConglomerateDescriptors();\r
+               CompilerContext cc = getCompilerContext();\r
+\r
+               for (int index = 0; index < cds.length; index++)\r
+               {\r
+                       cc.createDependency(cds[index]);\r
+               }\r
+       }\r
+       \r
+} // end of class InsertNode\r