Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / sql / compile / DeleteNode.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java
new file mode 100644 (file)
index 0000000..4879481
--- /dev/null
@@ -0,0 +1,1001 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.DeleteNode\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.reference.SQLState;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.conn.Authorizer;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;\r
+\r
+\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+\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.reference.ClassName;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\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
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\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.catalog.UUID;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+\r
+import org.apache.derby.impl.sql.execute.FKInfo;\r
+\r
+import java.lang.reflect.Modifier;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+import org.apache.derby.iapi.services.io.FormatableProperties;\r
+import java.util.Vector;\r
+import java.util.Hashtable;\r
+import java.util.Properties;\r
+import org.apache.derby.iapi.sql.compile.NodeFactory;\r
+import org.apache.derby.iapi.util.ReuseFactory;\r
+import org.apache.derby.iapi.sql.depend.Dependent;\r
+import org.apache.derby.iapi.sql.ResultDescription;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+\r
+\r
+/**\r
+ * A DeleteNode represents a DELETE statement. It is the top-level node\r
+ * for the statement.\r
+ *\r
+ * For positioned delete, 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 class DeleteNode extends DMLModStatementNode\r
+{\r
+       /* Column name for the RowLocation column in the ResultSet */\r
+       private static final String COLUMNNAME = "###RowLocationToDelete";\r
+\r
+       /* Filled in by bind. */\r
+       protected boolean                               deferred;\r
+       protected ExecRow                               emptyHeapRow;\r
+       protected FromTable                             targetTable;\r
+       protected FKInfo                                fkInfo;\r
+       protected FormatableBitSet readColsBitSet;\r
+\r
+       private ConstantAction[] dependentConstantActions;\r
+       private boolean cascadeDelete;\r
+       private StatementNode[] dependentNodes;\r
+\r
+       /**\r
+        * Initializer for a DeleteNode.\r
+        *\r
+        * @param targetTableName       The name of the table to delete from\r
+        * @param queryExpression       The query expression that will generate\r
+        *                              the rows to delete from the given table\r
+        */\r
+\r
+       public void init(Object targetTableName,\r
+                                         Object queryExpression)\r
+       {\r
+               super.init(queryExpression);\r
+               this.targetTableName = (TableName) targetTableName;\r
+       }\r
+\r
+       public String statementToString()\r
+       {\r
+               return "DELETE";\r
+       }\r
+\r
+       /**\r
+        * Bind this DeleteNode.  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
+        * If any indexes need to be updated, we add all the columns in the\r
+        * base table to the result column list, so that we can use the column\r
+        * values as look-up keys for the index rows to be deleted.  Binding a\r
+        * delete will also massage the tree so that the ResultSetNode has \r
+        * column containing the RowLocation of the base row.\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 where clause tables\r
+               getCompilerContext().pushCurrentPrivType( Authorizer.SELECT_PRIV);\r
+               try\r
+               {\r
+                       FromList        fromList = (FromList) getNodeFactory().getNode(\r
+                                                                       C_NodeTypes.FROM_LIST,\r
+                                                                       getNodeFactory().doJoinOrderOptimization(),\r
+                                                                       getContextManager());\r
+                       ResultColumn                            rowLocationColumn = null;\r
+                       CurrentRowLocationNode          rowLocationNode;\r
+                       TableName                                       cursorTargetTableName = null;\r
+                       CurrentOfNode                   currentOfNode = null;\r
+               \r
+                       DataDictionary dataDictionary = getDataDictionary();\r
+                       super.bindTables(dataDictionary);\r
+\r
+                       // wait to bind named target table until the underlying\r
+                       // cursor is bound, so that we can get it from the\r
+                       // cursor if this is a positioned delete.\r
+\r
+                       // for positioned delete, get the cursor's target table.\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.ASSERT(resultSet != null && resultSet instanceof SelectNode,\r
+                               "Delete must have a select result set");\r
+\r
+                       SelectNode sel;\r
+                       sel = (SelectNode)resultSet;\r
+                       targetTable = (FromTable) sel.fromList.elementAt(0);\r
+                       if (targetTable instanceof CurrentOfNode)\r
+                       {\r
+                               currentOfNode = (CurrentOfNode) targetTable;\r
+\r
+                               cursorTargetTableName = currentOfNode.getBaseCursorTargetTableName();\r
+                               // instead of an assert, we might say the cursor is not updatable.\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(cursorTargetTableName != null);\r
+                       }\r
+\r
+                       if (targetTable instanceof FromVTI)\r
+                       {\r
+                               targetVTI = (FromVTI) targetTable;\r
+                               targetVTI.setTarget();\r
+                       }\r
+                       else\r
+                       {\r
+                               // positioned delete 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 delete, we need to verify that\r
+                               // the named table is the same as the cursor's target (base table name).\r
+                               else if (cursorTargetTableName != null)\r
+                               {\r
+                                       // this match requires that the named table in the delete\r
+                                       // be the same as a base name in the cursor.\r
+                                       if ( !targetTableName.equals(cursorTargetTableName))\r
+                                       {\r
+                                               throw StandardException.newException(SQLState.LANG_CURSOR_DELETE_MISMATCH, \r
+                                                       targetTableName,\r
+                                                       currentOfNode.getCursorName());\r
+                                       }\r
+                               }\r
+                       }\r
+               \r
+                       // descriptor must exist, tables already bound.\r
+                       verifyTargetTable();\r
+\r
+                       /* Generate a select list for the ResultSetNode - CurrentRowLocation(). */\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.ASSERT((resultSet.resultColumns == null),\r
+                                                         "resultColumns is expected to be null until bind time");\r
+\r
+\r
+                       if (targetTable instanceof FromVTI)\r
+                       {\r
+                               getResultColumnList();\r
+                               resultColumnList = targetTable.getResultColumnsForList(null, \r
+                                                               resultColumnList, null);\r
+\r
+                               /* Set the new result column list in the result set */\r
+                               resultSet.setResultColumns(resultColumnList);\r
+                       }\r
+                       else\r
+                       {\r
+                               /*\r
+                               ** Start off assuming no columns from the base table\r
+                               ** are needed in the rcl.\r
+                               */\r
+\r
+                               resultColumnList = new ResultColumnList();\r
+\r
+                               FromBaseTable fbt = getResultColumnList(resultColumnList);\r
+\r
+                               readColsBitSet = getReadMap(dataDictionary,\r
+                                                                               targetTableDescriptor);\r
+\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
+                               }\r
+\r
+                               /*\r
+                               ** Construct an empty heap row for use in our constant action.\r
+                               */\r
+                               emptyHeapRow = targetTableDescriptor.getEmptyExecRow();\r
+\r
+                               /* Generate the RowLocation column */\r
+                               rowLocationNode = (CurrentRowLocationNode) getNodeFactory().getNode(\r
+                                                                               C_NodeTypes.CURRENT_ROW_LOCATION_NODE,\r
+                                                                               getContextManager());\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
+                               /* Force the added columns to take on the table's correlation name, if any */\r
+                               correlateAddedColumns( resultColumnList, targetTable );\r
+                       \r
+                               /* Set the new result column list in the result set */\r
+                               resultSet.setResultColumns(resultColumnList);\r
+                       }\r
+\r
+                       /* Bind the expressions before the ResultColumns are bound */\r
+                       super.bindExpressions();\r
+\r
+                       /* Bind untyped nulls directly under the result columns */\r
+                       resultSet.getResultColumns().\r
+                               bindUntypedNullsToResultColumns(resultColumnList);\r
+\r
+                       if (! (targetTable instanceof FromVTI))\r
+                       {\r
+                               /* Bind the new ResultColumn */\r
+                               rowLocationColumn.bindResultColumnToExpression();\r
+\r
+                               bindConstraints(dataDictionary,\r
+                                                       getNodeFactory(),\r
+                                                       targetTableDescriptor,\r
+                                                       null,\r
+                                                       resultColumnList,\r
+                                                       (int[]) null,\r
+                                                       readColsBitSet,\r
+                                                       false,\r
+                                                       true);  /* we alway include triggers in core language */\r
+\r
+                               /* If the target table is also a source table, then\r
+                               * the delete will have to be in deferred mode\r
+                               * For deletes, this means that the target table appears in a\r
+                               * subquery.  Also, self-referencing foreign key deletes\r
+                               * are deferred.  And triggers cause the delete to be deferred.\r
+                               */\r
+                               if (resultSet.subqueryReferencesTarget(\r
+                                                                       targetTableDescriptor.getName(), true) ||\r
+                                       requiresDeferredProcessing())\r
+                               {\r
+                                       deferred = true;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+               deferred = VTIDeferModPolicy.deferIt( DeferModification.DELETE_STATEMENT,\r
+                                                  targetVTI,\r
+                                                  null,\r
+                                                  sel.getWhereClause());\r
+                       }\r
+               sel = null; // done with sel\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
+                       //In case of cascade delete , create nodes for\r
+                       //the ref action  dependent tables and bind them.\r
+                       if(fkTableNames != null)\r
+                       {\r
+                               String currentTargetTableName = targetTableDescriptor.getSchemaName() +\r
+                                                "." + targetTableDescriptor.getName();\r
+\r
+                               if(!isDependentTable){\r
+                                       //graph node\r
+                                       graphHashTable = new Hashtable();\r
+                               }\r
+\r
+                               /*Check whether the current tatget is already been explored.\r
+                               *If we are seeing the same table name which we binded earlier\r
+                               *means we have cyclic references.\r
+                               */\r
+                               if(!graphHashTable.containsKey(currentTargetTableName))\r
+                               {\r
+                                       cascadeDelete = true;\r
+                                       int noDependents = fkTableNames.length;\r
+                                       dependentNodes = new StatementNode[noDependents];\r
+                                       graphHashTable.put(currentTargetTableName, new Integer(noDependents));\r
+                                       for(int i =0 ; i < noDependents ; i ++)\r
+                                       {\r
+                                               dependentNodes[i] = getDependentTableNode(fkTableNames[i],\r
+                                                                                                                         fkRefActions[i],\r
+                                                                                                                         fkColDescriptors[i]);\r
+                                               dependentNodes[i].bindStatement();\r
+                                       }\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               //case where current dependent table does not have dependent tables\r
+                               if(isDependentTable)\r
+                               {\r
+                                       String currentTargetTableName = targetTableDescriptor.getSchemaName()\r
+                                                        + "." + targetTableDescriptor.getName();\r
+                                       graphHashTable.put(currentTargetTableName, new Integer(0));\r
+\r
+                               }\r
+                       }\r
+                       if (isPrivilegeCollectionRequired())\r
+                       {\r
+                               getCompilerContext().pushCurrentPrivType( getPrivType());\r
+                               getCompilerContext().addRequiredTablePriv( targetTableDescriptor);\r
+                               getCompilerContext().popCurrentPrivType();\r
+                       }\r
+               }\r
+               finally\r
+               {\r
+                       getCompilerContext().popCurrentPrivType();\r
+               }\r
+       } // end of bind\r
+\r
+       int getPrivType()\r
+       {\r
+               return Authorizer.DELETE_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 delete table is on a SESSION schema table, then return true. \r
+               return resultSet.referencesSessionSchema();\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
+                       int lockMode = resultSet.updateTargetLockMode();\r
+                       long heapConglomId = targetTableDescriptor.getHeapConglomerateId();\r
+                       TransactionController tc = 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
+                       ResultDescription resultDescription = null;\r
+                       if(isDependentTable)\r
+                       {\r
+                               //triggers need the result description ,\r
+                               //dependent tables  don't have a source from generation time\r
+                               //to get the result description\r
+                               resultDescription = makeResultDescription();\r
+                       }\r
+\r
+\r
+                       return  getGenericConstantActionFactory().getDeleteConstantAction\r
+                               ( heapConglomId,\r
+                                 targetTableDescriptor.getTableType(),\r
+                                 tc.getStaticCompiledConglomInfo(heapConglomId),\r
+                                 indicesToMaintain,\r
+                                 indexConglomerateNumbers,\r
+                                 indexSCOCIs,\r
+                                 emptyHeapRow,\r
+                                 deferred,\r
+                                 false,\r
+                                 targetTableDescriptor.getUUID(),\r
+                                 lockMode,\r
+                                 null, null, null, 0, null, null, \r
+                                 resultDescription,\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
+                                 (UUID) null,\r
+                                 resultSet.isOneRowResultSet(),\r
+                                 dependentConstantActions);\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.DELETE_STATEMENT,\r
+                                               deferred);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Code generation for delete.\r
+        * The generated code will contain:\r
+        *              o  A static member for the (xxx)ResultSet with the RowLocations\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 which will be stuffed in the call to the \r
+        *                  ProjectRestrictResultSet.\r
+        *      o In case of referential actions, this function generate an\r
+        *        array of resultsets on its dependent tables.\r
+        *\r
+        * @param acb   The ActivationClassBuilder for the class being built\r
+        * @param mb    The execute() method to be built\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void generate(ActivationClassBuilder acb,\r
+                                                               MethodBuilder mb)\r
+                                                       throws StandardException\r
+       {\r
+\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
+               acb.pushGetResultSetFactoryExpression(mb); \r
+               acb.newRowLocationScanResultSetName();\r
+               resultSet.generate(acb, mb); // arg 1\r
+\r
+               String resultSetGetter;\r
+               int argCount;\r
+               String parentResultSetId;\r
+\r
+               // Base table\r
+               if (targetTableDescriptor != null)\r
+               {\r
+                       /* Create the declaration for the scan ResultSet which generates the\r
+                        * RowLocations to be deleted.\r
+                        * Note that the field cannot be static because there\r
+                        * can be multiple activations of the same activation class,\r
+                        * and they can't share this field.  Only exprN fields can\r
+                        * be shared (or, more generally, read-only fields).\r
+                        * RESOLVE - Need to deal with the type of the field.\r
+                        */\r
+\r
+                       acb.newFieldDeclaration(Modifier.PRIVATE, \r
+                                                                       ClassName.CursorResultSet, \r
+                                                                       acb.getRowLocationScanResultSetName());\r
+\r
+                       if(cascadeDelete || isDependentTable)\r
+                       {\r
+                               resultSetGetter = "getDeleteCascadeResultSet";\r
+                               argCount = 4;\r
+                       }               \r
+                       else\r
+                       {\r
+                               resultSetGetter = "getDeleteResultSet";\r
+                               argCount = 1;\r
+                       }\r
+                       \r
+               } else {\r
+                       argCount = 1;\r
+                       resultSetGetter = "getDeleteVTIResultSet";\r
+               }\r
+\r
+               if(isDependentTable)\r
+               {\r
+                       mb.push(acb.addItem(makeConstantAction()));\r
+               \r
+               }else\r
+               {\r
+                       if(cascadeDelete)\r
+                       {\r
+                               mb.push(-1); //root table.\r
+                       }\r
+               }               \r
+\r
+               String          resultSetArrayType = ClassName.ResultSet + "[]";\r
+               if(cascadeDelete)\r
+               {\r
+                       parentResultSetId = targetTableDescriptor.getSchemaName() +\r
+                                              "." + targetTableDescriptor.getName();\r
+                       // Generate the code to build the array\r
+                       LocalField arrayField =\r
+                               acb.newFieldDeclaration(Modifier.PRIVATE, resultSetArrayType);\r
+                       mb.pushNewArray(ClassName.ResultSet, dependentNodes.length);  // new ResultSet[size]\r
+                       mb.setField(arrayField);\r
+                       for(int index=0 ; index <  dependentNodes.length ; index++)\r
+                       {\r
+\r
+                               dependentNodes[index].setRefActionInfo(fkIndexConglomNumbers[index],\r
+                                                                                                          fkColArrays[index],\r
+                                                                                                          parentResultSetId,\r
+                                                                                                          true);\r
+                               mb.getField(arrayField); // first arg (resultset array reference)\r
+                               /*beetle:5360 : if too many statements are added  to a  method, \r
+                                *size of method can hit  65k limit, which will\r
+                                *lead to the class format errors at load time.\r
+                                *To avoid this problem, when number of statements added \r
+                                *to a method is > 2048, remaing statements are added to  a new function\r
+                                *and called from the function which created the function.\r
+                                *See Beetle 5135 or 4293 for further details on this type of problem.\r
+                               */\r
+                               if(mb.statementNumHitLimit(10))\r
+                               {\r
+                                       MethodBuilder dmb = acb.newGeneratedFun(ClassName.ResultSet, Modifier.PRIVATE);\r
+                                       dependentNodes[index].generate(acb,dmb); //generates the resultset expression\r
+                                       dmb.methodReturn();\r
+                                       dmb.complete();\r
+                                       /* Generate the call to the new method */\r
+                                       mb.pushThis(); \r
+                                       //second arg will be generated by this call\r
+                                       mb.callMethod(VMOpcode.INVOKEVIRTUAL, (String) null, dmb.getName(), ClassName.ResultSet, 0);\r
+                               }else\r
+                               {\r
+                                       dependentNodes[index].generate(acb,mb); //generates the resultset expression\r
+                               }\r
+\r
+                               mb.setArrayElement(index);\r
+                       }       \r
+                       mb.getField(arrayField); // fourth argument - array reference\r
+               }\r
+               else\r
+               {\r
+                       if(isDependentTable)\r
+                       {\r
+                               mb.pushNull(resultSetArrayType); //No dependent tables for this table\r
+                       }\r
+               }\r
+\r
+\r
+               if(cascadeDelete || isDependentTable)\r
+               {\r
+                       parentResultSetId = targetTableDescriptor.getSchemaName() +\r
+                                              "." + targetTableDescriptor.getName();\r
+                       mb.push(parentResultSetId);\r
+\r
+               }\r
+               mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, resultSetGetter, ClassName.ResultSet, argCount);\r
+\r
+\r
+               if(!isDependentTable && cascadeDelete)\r
+               {\r
+                       int numResultSets = acb.getRowCount();\r
+                       if(numResultSets > 0)\r
+                       {\r
+                               //generate activation.raParentResultSets = new NoPutResultSet[size]\r
+                               MethodBuilder constructor = acb.getConstructor();\r
+                               constructor.pushThis();\r
+                               constructor.pushNewArray(ClassName.CursorResultSet, numResultSets);\r
+                               constructor.putField(ClassName.BaseActivation,\r
+                                                                        "raParentResultSets",\r
+                                                                        ClassName.CursorResultSet + "[]");\r
+                               constructor.endStatement();\r
+                       }\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.DELETE;\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:\r
+         *\r
+         *             o       maintain indices\r
+         *             o       maintain foreign keys\r
+         *\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
+         *\r
+         *     @param  dd                              the data dictionary to look in\r
+         *     @param  baseTable               the base table descriptor\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
+       )\r
+               throws StandardException\r
+       {\r
+               boolean[]       needsDeferredProcessing = new boolean[1];\r
+               needsDeferredProcessing[0] = requiresDeferredProcessing();\r
+\r
+               Vector          conglomVector = new Vector();\r
+               relevantTriggers = new GenericDescriptorList();\r
+\r
+               FormatableBitSet        columnMap = DeleteNode.getDeleteReadMap(baseTable, conglomVector, relevantTriggers, needsDeferredProcessing );\r
+\r
+               markAffectedIndexes( conglomVector );\r
+\r
+               adjustDeferredFlag( needsDeferredProcessing[0] );\r
+\r
+               return  columnMap;\r
+       }\r
+\r
+       /**\r
+        * In case of referential actions, we require to perform\r
+        * DML (UPDATE or DELETE) on the dependent tables. \r
+        * Following function returns the DML Node for the dependent table.\r
+        */\r
+       private StatementNode getDependentTableNode(String tableName, int refAction,\r
+                                                                                               ColumnDescriptorList cdl) throws StandardException\r
+       {\r
+               StatementNode node=null;\r
+\r
+               int index = tableName.indexOf('.');\r
+               String schemaName = tableName.substring(0 , index);\r
+               String tName = tableName.substring(index+1);\r
+               if(refAction == StatementType.RA_CASCADE)\r
+               {\r
+                       node = getEmptyDeleteNode(schemaName , tName);\r
+                       ((DeleteNode)node).isDependentTable = true;\r
+                       ((DeleteNode)node).graphHashTable = graphHashTable;\r
+               }\r
+\r
+               if(refAction == StatementType.RA_SETNULL)\r
+               {\r
+                       node = getEmptyUpdateNode(schemaName , tName, cdl);\r
+                       ((UpdateNode)node).isDependentTable = true;\r
+                       ((UpdateNode)node).graphHashTable = graphHashTable;\r
+               }\r
+\r
+               return node;\r
+       }\r
+\r
+\r
+    private StatementNode getEmptyDeleteNode(String schemaName, String targetTableName)\r
+        throws StandardException\r
+    {\r
+\r
+        ValueNode whereClause = null;\r
+\r
+        TableName tableName = new TableName();\r
+        tableName.init(schemaName , targetTableName);\r
+\r
+        NodeFactory nodeFactory = getNodeFactory();\r
+        FromList   fromList = (FromList) nodeFactory.getNode(C_NodeTypes.FROM_LIST, getContextManager());\r
+        FromTable fromTable = (FromTable) nodeFactory.getNode(\r
+                                                    C_NodeTypes.FROM_BASE_TABLE,\r
+                                                    tableName,\r
+                                                    null,\r
+                                                    ReuseFactory.getInteger(FromBaseTable.DELETE),\r
+                                                    null,\r
+                                                    getContextManager());\r
+\r
+               //we would like to use references index & table scan instead of \r
+               //what optimizer says for the dependent table scan.\r
+               Properties targetProperties = new FormatableProperties();\r
+               targetProperties.put("index", "null");\r
+               ((FromBaseTable) fromTable).setTableProperties(targetProperties);\r
+\r
+        fromList.addFromTable(fromTable);\r
+        SelectNode resultSet = (SelectNode) nodeFactory.getNode(\r
+                                                     C_NodeTypes.SELECT_NODE,\r
+                                                     null,\r
+                                                     null,   /* AGGREGATE list */\r
+                                                     fromList, /* FROM list */\r
+                                                     whereClause, /* WHERE clause */\r
+                                                     null, /* GROUP BY list */\r
+                                                     null, /* having clause */\r
+                                                     getContextManager());\r
+\r
+        return (StatementNode) nodeFactory.getNode(\r
+                                                    C_NodeTypes.DELETE_NODE,\r
+                                                    tableName,\r
+                                                    resultSet,\r
+                                                    getContextManager());\r
+\r
+    }\r
+\r
+\r
+       \r
+    private StatementNode getEmptyUpdateNode(String schemaName, \r
+                                                                                        String targetTableName,\r
+                                                                                        ColumnDescriptorList cdl)\r
+        throws StandardException\r
+    {\r
+\r
+        ValueNode whereClause = null;\r
+\r
+        TableName tableName = new TableName();\r
+        tableName.init(schemaName , targetTableName);\r
+\r
+        NodeFactory nodeFactory = getNodeFactory();\r
+        FromList   fromList = (FromList) nodeFactory.getNode(C_NodeTypes.FROM_LIST, getContextManager());\r
+        FromTable fromTable = (FromTable) nodeFactory.getNode(\r
+                                                    C_NodeTypes.FROM_BASE_TABLE,\r
+                                                    tableName,\r
+                                                    null,\r
+                                                    ReuseFactory.getInteger(FromBaseTable.DELETE),\r
+                                                    null,\r
+                                                    getContextManager());\r
+\r
+\r
+               //we would like to use references index & table scan instead of \r
+               //what optimizer says for the dependent table scan.\r
+               Properties targetProperties = new FormatableProperties();\r
+               targetProperties.put("index", "null");\r
+               ((FromBaseTable) fromTable).setTableProperties(targetProperties);\r
+\r
+        fromList.addFromTable(fromTable);\r
+\r
+        SelectNode resultSet = (SelectNode) nodeFactory.getNode(\r
+                                                     C_NodeTypes.SELECT_NODE,\r
+                                                     getSetClause(tableName, cdl),\r
+                                                     null,   /* AGGREGATE list */\r
+                                                     fromList, /* FROM list */\r
+                                                     whereClause, /* WHERE clause */\r
+                                                     null, /* GROUP BY list */\r
+                                                    null, /* having clause */\r
+                                                     getContextManager());\r
+\r
+        return (StatementNode) nodeFactory.getNode(\r
+                                                    C_NodeTypes.UPDATE_NODE,\r
+                                                    tableName,\r
+                                                    resultSet,\r
+                                                    getContextManager());\r
+\r
+    }\r
+\r
+\r
\r
+       private ResultColumnList getSetClause(TableName tabName,\r
+                                                                                 ColumnDescriptorList cdl)\r
+               throws StandardException\r
+       {\r
+               ResultColumn resultColumn;\r
+               ValueNode        valueNode;\r
+\r
+               NodeFactory nodeFactory = getNodeFactory();\r
+               ResultColumnList        columnList = (ResultColumnList) nodeFactory.getNode(\r
+                                                                                               C_NodeTypes.RESULT_COLUMN_LIST,\r
+                                                                                               getContextManager());\r
+\r
+               valueNode =  (ValueNode) nodeFactory.getNode(C_NodeTypes.UNTYPED_NULL_CONSTANT_NODE,\r
+                                                                                                                        getContextManager());\r
+               for(int index =0 ; index < cdl.size() ; index++)\r
+               {\r
+                       ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);\r
+                       //only columns that are nullable need to be set to 'null' for ON\r
+                       //DELETE SET NULL\r
+                       if((cd.getType()).isNullable())\r
+                       {\r
+                               resultColumn = (ResultColumn) nodeFactory.getNode(\r
+                                                                           C_NodeTypes.RESULT_COLUMN,\r
+                                                                               cd,\r
+                                                                               valueNode,\r
+                                                                               getContextManager());\r
+\r
+                               columnList.addResultColumn(resultColumn);\r
+                       }\r
+               }\r
+               return columnList;\r
+       }\r
+\r
+\r
+       public void optimizeStatement() throws StandardException\r
+       {\r
+               if(cascadeDelete)\r
+               {\r
+                       for(int index=0 ; index < dependentNodes.length ; index++)\r
+                       {\r
+                               dependentNodes[index].optimizeStatement();\r
+                       }\r
+               }\r
+\r
+               super.optimizeStatement();\r
+       }\r
+\r
+    /**\r
+         *     Builds a bitmap of all columns which should be read from the\r
+         *     Store in order to satisfy an DELETE statement.\r
+         *\r
+         *\r
+         *     1)      finds all indices on this table\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 DELETE triggers on the table\r
+         *     5)      if there are any DELETE triggers, marks all columns in the bitmap\r
+         *     6)      adds the triggers to an evolving list of triggers\r
+         *\r
+         *     @param  conglomVector           OUT: vector of affected indices\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 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
+       private static FormatableBitSet getDeleteReadMap\r
+       (\r
+               TableDescriptor                         baseTable,\r
+               Vector                                          conglomVector,\r
+               GenericDescriptorList           relevantTriggers,\r
+               boolean[]                                       needsDeferredProcessing\r
+       )\r
+               throws StandardException\r
+       {\r
+               int             columnCount = baseTable.getMaxColumnID();\r
+               FormatableBitSet        columnMap = new FormatableBitSet(columnCount + 1);\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
+               ** Notice that we don't need to add constraint\r
+               ** columns.  This is because we add all key constraints\r
+               ** (e.g. foreign keys) as a side effect of adding their\r
+               ** indexes above.  And we don't need to deal with\r
+               ** check constraints on a delete.\r
+               **\r
+               ** Adding indexes also takes care of the replication \r
+               ** requirement of having the primary key.\r
+               */\r
+               DMLModStatementNode.getXAffectedIndexes(baseTable,  null, columnMap, conglomVector );\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
+               baseTable.getAllRelevantTriggers( StatementType.DELETE, (int[])null, 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 column references (particularly those added by the compiler)\r
+        * to use the correlation name on the base table, if any.\r
+        */\r
+       private void    correlateAddedColumns( ResultColumnList rcl, FromTable fromTable )\r
+               throws StandardException\r
+       {\r
+               String          correlationName = fromTable.getCorrelationName();\r
+\r
+               if ( correlationName == null ) { return; }\r
+\r
+               TableName       correlationNameNode = makeTableName( null, correlationName );\r
+               int                     count = rcl.size();\r
+\r
+               for ( int i = 0; i < count; i++ )\r
+               {\r
+                       ResultColumn    column = (ResultColumn) rcl.elementAt( i );\r
+\r
+                       ValueNode               expression = column.getExpression();\r
+\r
+                       if ( (expression != null) && (expression instanceof ColumnReference) )\r
+                       {\r
+                               ColumnReference reference = (ColumnReference) expression;\r
+                               \r
+                               reference.setTableNameNode( correlationNameNode );\r
+                       }\r
+               }\r
+               \r
+       }\r
+       \r
+}\r