Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / sql / execute / DeleteResultSet.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
new file mode 100644 (file)
index 0000000..59e1058
--- /dev/null
@@ -0,0 +1,654 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.DeleteResultSet\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.execute;\r
+\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.db.TriggerExecutionContext;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.ResultDescription;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+import org.apache.derby.iapi.sql.execute.CursorResultSet;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;\r
+import org.apache.derby.iapi.sql.execute.RowChanger;\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+/**\r
+ * Delete the rows from the specified\r
+ * base table. This will cause constraints to be checked\r
+ * and triggers to be executed based on the c's and t's\r
+ * compiled into the insert plan.\r
+ */\r
+class DeleteResultSet extends DMLWriteResultSet\r
+{\r
+       private TransactionController           tc;\r
+       DeleteConstantAction            constants;\r
+    protected ResultDescription                                resultDescription;\r
+       protected  NoPutResultSet                       source;\r
+       NoPutResultSet                  savedSource;\r
+       int                                                     numIndexes;\r
+       protected RowChanger                    rc;\r
+       private ExecRow                                 row;\r
+\r
+       protected ConglomerateController        deferredBaseCC;\r
+\r
+       protected TemporaryRowHolderImpl        rowHolder;\r
+\r
+       private int                                             numOpens; // number of opens w/o a close\r
+       private boolean                                 firstExecute;\r
+\r
+       // cached across opens()s\r
+       private FormatableBitSet                                baseRowReadList; \r
+       private int                                             rlColumnNumber;\r
+       protected FKInfo[]                              fkInfoArray;\r
+       private TriggerInfo                     triggerInfo;\r
+       private RISetChecker                    fkChecker;\r
+       private TriggerEventActivator   triggerActivator;\r
+       private boolean                                 noTriggersOrFks;\r
+\r
+       ExecRow         deferredSparseRow; \r
+       ExecRow         deferredBaseRow;\r
+       int lockMode; \r
+       protected  boolean cascadeDelete;\r
+       ExecRow         deferredRLRow = null;\r
+       int     numberOfBaseColumns = 0;\r
+\r
+       /**\r
+     * Returns the description of the deleted rows.\r
+     * REVISIT: Do we want this to return NULL instead?\r
+        */\r
+       public ResultDescription getResultDescription()\r
+       {\r
+           return resultDescription;\r
+       }\r
+\r
+    /*\r
+     * class interface\r
+     *\r
+     */\r
+    DeleteResultSet\r
+       (\r
+               NoPutResultSet          source,\r
+               Activation                      activation\r
+       )\r
+               throws StandardException\r
+    {\r
+               this(source, activation.getConstantAction(), activation);\r
+       }\r
+    /**\r
+     * REMIND: At present this takes just the conglomerate id\r
+     * of the table. We can expect this to expand to include\r
+     * passing information about triggers, constraints, and\r
+     * any additional conglomerates on the underlying table\r
+     * for access methods.\r
+     *\r
+        * @exception StandardException         Thrown on error\r
+     */\r
+    DeleteResultSet\r
+       (\r
+               NoPutResultSet          source,\r
+               ConstantAction          passedInConstantAction,\r
+               Activation                      activation\r
+       )\r
+               throws StandardException\r
+    {\r
+               super(activation, passedInConstantAction);\r
+               this.source = source;\r
+\r
+               tc = activation.getTransactionController();\r
+               constants = (DeleteConstantAction) constantAction;\r
+               fkInfoArray = constants.getFKInfo();\r
+               triggerInfo = constants.getTriggerInfo();\r
+               noTriggersOrFks = ((fkInfoArray == null) && (triggerInfo == null));\r
+               baseRowReadList = constants.getBaseRowReadList();\r
+               if(source != null)\r
+                       resultDescription = source.getResultDescription();\r
+               else\r
+                       resultDescription = constants.resultDescription;\r
+\r
+       }\r
+\r
+       /**\r
+               @exception StandardException Standard Derby error policy\r
+       */\r
+       public void open() throws StandardException\r
+       {\r
+\r
+               setup();\r
+               boolean rowsFound = collectAffectedRows(); //this call also deletes rows , if not deferred\r
+               if (! rowsFound)\r
+               {\r
+                       activation.addWarning(\r
+                                               StandardException.newWarning(\r
+                                                       SQLState.LANG_NO_ROW_FOUND));\r
+               }\r
+\r
+               /*\r
+               ** If the delete is deferred, scan the temporary conglomerate to\r
+               ** get the RowLocations of the rows to be deleted.  Re-fetch the\r
+               ** rows and delete them using the RowChanger.\r
+               */\r
+               if (constants.deferred)\r
+               {\r
+                       runFkChecker(true); //check for only RESTRICT referential action rule violations\r
+                       fireBeforeTriggers();\r
+                       deleteDeferredRows();\r
+                       runFkChecker(false); //check for all constraint violations\r
+                       // apply \r
+                       rc.finish();\r
+                       fireAfterTriggers();\r
+               }\r
+\r
+       \r
+               /* Cache query plan text for source, before it gets blown away */\r
+               if (lcc.getRunTimeStatisticsMode())\r
+               {\r
+                       /* savedSource nulled after run time statistics generation */\r
+                       savedSource = source;\r
+               }\r
+\r
+               cleanUp();\r
+               endTime = getCurrentTimeMillis();\r
+\r
+    }\r
+       \r
+\r
+       //this routine open the source and find the dependent rows \r
+       void  setup() throws StandardException\r
+       {\r
+               super.setup();\r
+\r
+               // Remember if this is the 1st execution\r
+               firstExecute = (rc == null);\r
+\r
+               try {\r
+\r
+                       //open the source for the parent tables\r
+                       if (numOpens++ == 0)\r
+                       {\r
+                               source.openCore();\r
+                       }\r
+                       else\r
+                       {\r
+                       source.reopenCore();\r
+                       }\r
+               } catch (StandardException se) {\r
+                       activation.checkStatementValidity();\r
+                       throw se;\r
+\r
+               }\r
+\r
+               activation.checkStatementValidity();\r
+\r
+               /* Get or re-use the row changer.\r
+                * NOTE: We need to set ourself as the top result set\r
+                * if this is not the 1st execution.  (Done in constructor\r
+                * for 1st execution.)\r
+                */\r
+               if (firstExecute)\r
+               {\r
+                       rc = lcc.getLanguageConnectionFactory().getExecutionFactory().\r
+                                            getRowChanger( \r
+                                                               constants.conglomId,\r
+                                                               constants.heapSCOCI, \r
+                                                               heapDCOCI,\r
+                                                               constants.irgs,\r
+                                                               constants.indexCIDS,\r
+                                                               constants.indexSCOCIs,\r
+                                                           indexDCOCIs,\r
+                                                               constants.numColumns,\r
+                                                               tc,\r
+                                                               (int[])null,\r
+                                                               baseRowReadList,\r
+                                                               constants.getBaseRowReadMap(),\r
+                                                               constants.getStreamStorableHeapColIds(),\r
+                                                               activation);\r
+               }\r
+               else\r
+               {\r
+                       lcc.getStatementContext().setTopResultSet(this, subqueryTrackingArray);\r
+               }\r
+               /* decode the lock mode for the execution isolation level */\r
+               lockMode = decodeLockMode(constants.lockMode);\r
+\r
+               /* Open the RowChanger before the source ResultSet so that\r
+                * the store will see the RowChanger's lock as a covering lock\r
+                * if it is a table lock.\r
+                */\r
+               rc.open(lockMode); \r
+\r
+               /* The source does not know whether or not we are doing a\r
+                * deferred mode delete.  If we are, then we must clear the\r
+                * index scan info from the activation so that the row changer\r
+                * does not re-use that information (which won't be valid for\r
+                * a deferred mode delete).\r
+                */\r
+               if (constants.deferred || cascadeDelete)\r
+               {\r
+                       activation.clearIndexScanInfo();\r
+               }\r
+\r
+        rowCount = 0;\r
+        if(!cascadeDelete)\r
+                       row = getNextRowCore(source);\r
+\r
+               /*\r
+               ** We need the number of columns even if there are\r
+               ** no rows. Note that source.ressultDescription() may \r
+               ** be null on a rep target doing a refresh.\r
+               */\r
+               if (resultDescription == null)\r
+               {\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               /*\r
+                               ** We NEED a result description when we are going to\r
+                               ** to have to kick off a trigger.  In a replicated environment\r
+                               ** we don't get a result description when we are replaying\r
+                               ** source xacts on the target, but we shouldn't be firing\r
+                               ** a trigger in that case anyway.\r
+                               */\r
+                               SanityManager.ASSERT(triggerInfo == null, "result description is needed to supply to trigger result sets");\r
+                       }\r
+                       numberOfBaseColumns = (row == null) ? 0 : row.nColumns();\r
+               }\r
+               else\r
+               {\r
+                       numberOfBaseColumns = resultDescription.getColumnCount();\r
+               }\r
+\r
+               numIndexes = constants.irgs.length;\r
+\r
+               if (constants.deferred || cascadeDelete)\r
+               {\r
+                       Properties properties = new Properties();\r
+\r
+                       // Get the properties on the old heap\r
+                       rc.getHeapConglomerateController().getInternalTablePropertySet(properties);\r
+\r
+                       /*\r
+                       ** If deferred and fk or trigger, we are going to grab\r
+                       ** the entire row.  \r
+                       **\r
+                       ** If we are deferred w/o a fk, then we only\r
+                       ** save the row location.\r
+                       */\r
+                       deferredRLRow = RowUtil.getEmptyValueRow(1, lcc);\r
+                       rlColumnNumber = noTriggersOrFks ? 1: numberOfBaseColumns;\r
+                       if(cascadeDelete)\r
+                       {\r
+                               rowHolder = new TemporaryRowHolderImpl(activation, properties, \r
+                                               (resultDescription != null) ?\r
+                                                       resultDescription.truncateColumns(rlColumnNumber) :\r
+                                                       null, false);\r
+\r
+\r
+                       }else\r
+                       {\r
+\r
+                               rowHolder = new TemporaryRowHolderImpl(activation, properties, \r
+                                               (resultDescription != null) ?\r
+                                                       resultDescription.truncateColumns(rlColumnNumber) :\r
+                                                       null);\r
+\r
+                       }\r
+\r
+                       rc.setRowHolder(rowHolder);\r
+               }\r
+\r
+               if (fkInfoArray != null)\r
+               {\r
+                       if (fkChecker == null)\r
+                       {\r
+                               fkChecker = new RISetChecker(tc, fkInfoArray);\r
+                       }\r
+                       else\r
+                       {\r
+                               fkChecker.reopen();\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+       boolean  collectAffectedRows() throws StandardException\r
+       {       \r
+\r
+               DataValueDescriptor             rlColumn;\r
+               RowLocation     baseRowLocation;\r
+               boolean rowsFound = false;\r
+\r
+               if(cascadeDelete)\r
+                       row = getNextRowCore(source);\r
+\r
+               while ( row != null )\r
+               {\r
+                       /* By convention, the last column for a delete contains a SQLRef\r
+                        * containing the RowLocation of the row to be deleted.  If we're\r
+                        * doing a deferred delete, store the RowLocations in the\r
+                        * temporary conglomerate.  If we're not doing a deferred delete,\r
+                        * just delete the rows immediately.\r
+                        */\r
+\r
+                       rowsFound = true;\r
+\r
+                       rlColumn = row.getColumn( row.nColumns() );\r
+               \r
+                       if (constants.deferred || cascadeDelete)\r
+                       {\r
+\r
+                               /*\r
+                               ** If we are deferred because of a trigger or foreign\r
+                               ** key, we need to save off the entire row.  Otherwise,\r
+                               ** we just save the RID.\r
+                               */\r
+                               if (noTriggersOrFks)\r
+                               {\r
+                                       deferredRLRow.setColumn(1, rlColumn);\r
+                                       rowHolder.insert(deferredRLRow);\r
+                               }\r
+                               else\r
+                               {\r
+                                       rowHolder.insert(row);\r
+                               }\r
+                               \r
+                               /*\r
+                               ** If we haven't already, lets get a template to\r
+                               ** use as a template for our rescan of the base table.\r
+                               ** Do this now while we have a real row to use\r
+                               ** as a copy.\r
+                               **\r
+                               ** There is one less column in the base row than\r
+                               ** there is in source row, because the base row\r
+                               ** doesn't contain the row location.\r
+                               */\r
+                               if (deferredBaseRow == null)\r
+                               {\r
+                                       deferredBaseRow = RowUtil.getEmptyValueRow(numberOfBaseColumns - 1, lcc);\r
+                       \r
+                                       RowUtil.copyCloneColumns(deferredBaseRow, row, \r
+                                                                                       numberOfBaseColumns - 1);\r
+                                       deferredSparseRow = makeDeferredSparseRow(deferredBaseRow,\r
+                                                                                                                               baseRowReadList,\r
+                                                                                                                               lcc);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               if (fkChecker != null)\r
+                               {\r
+                                       fkChecker.doPKCheck(row, false);\r
+                               }\r
+\r
+                               baseRowLocation = \r
+                                       (RowLocation) (rlColumn).getObject();\r
+\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       SanityManager.ASSERT(baseRowLocation != null,\r
+                                                       "baseRowLocation is null");\r
+                               }\r
+\r
+                               rc.deleteRow(row,baseRowLocation);\r
+                               source.markRowAsDeleted();\r
+                       }\r
+\r
+            rowCount++;\r
+\r
+                       // No need to do a next on a single row source\r
+                       if (constants.singleRowSource)\r
+                       {\r
+                               row = null;\r
+                       }\r
+                       else\r
+                       {\r
+                               row = getNextRowCore(source);\r
+                       }\r
+               }\r
+\r
+               return rowsFound;\r
+       }\r
+\r
+\r
+       // execute the before triggers set on the table\r
+    void fireBeforeTriggers() throws StandardException\r
+       {\r
+\r
+               if (triggerInfo != null)\r
+               {\r
+                       if (triggerActivator == null)\r
+                       {\r
+                               triggerActivator = new TriggerEventActivator(lcc, \r
+                                                                                                                        tc, \r
+                                                                                                                        constants.targetUUID,\r
+                                                                                                                        triggerInfo,\r
+                                                                                                                        TriggerExecutionContext.DELETE_EVENT,\r
+                                                                                                                        activation, null\r
+                                                                                                                        );\r
+                       }\r
+                       else\r
+                       {\r
+                               triggerActivator.reopen();\r
+                       }\r
+\r
+                       // fire BEFORE trigger\r
+                       triggerActivator.notifyEvent(TriggerEvents.BEFORE_DELETE, \r
+                                                                                rowHolder.getResultSet(), \r
+                                                                                (CursorResultSet)null);\r
+                       triggerActivator.cleanup();\r
+\r
+               }\r
+\r
+       }\r
+\r
+       //execute the after triggers set on the table.\r
+       void fireAfterTriggers() throws StandardException\r
+       {\r
+\r
+               // fire AFTER trigger\r
+               if (triggerActivator != null)\r
+               {\r
+                       triggerActivator.reopen();\r
+                       triggerActivator.notifyEvent(TriggerEvents.AFTER_DELETE, \r
+                                                                                rowHolder.getResultSet(),\r
+                                                                                (CursorResultSet)null);\r
+                       triggerActivator.cleanup();\r
+               }\r
+               \r
+       }\r
+\r
+\r
+       //delete the rows that in case deferred case and\r
+       //during cascade delete (All deletes are deferred during cascade action)\r
+       void deleteDeferredRows() throws StandardException\r
+       {\r
+               \r
+               DataValueDescriptor             rlColumn;\r
+               RowLocation     baseRowLocation;\r
+               ExecRow         deferredRLRow = null;\r
+\r
+               deferredBaseCC = tc.openCompiledConglomerate(false,\r
+                                                                                                        tc.OPENMODE_FORUPDATE|tc.OPENMODE_SECONDARY_LOCKED,\r
+                                                                                                        lockMode,\r
+                                                                                                        TransactionController.ISOLATION_SERIALIZABLE,\r
+                                                                                                        constants.heapSCOCI,\r
+                                                                                                        heapDCOCI);\r
+                       \r
+               CursorResultSet rs = rowHolder.getResultSet();\r
+               try\r
+               {\r
+                       /*\r
+                       ** We need to do a fetch doing a partial row\r
+                       ** read.  We need to shift our 1-based bit\r
+                       ** set to a zero based bit set like the store\r
+                       ** expects.\r
+                       */\r
+                       FormatableBitSet readBitSet = RowUtil.shift(baseRowReadList, 1);\r
+\r
+                       rs.open();\r
+                       while ((deferredRLRow = rs.getNextRow()) != null)\r
+                       {\r
+                               rlColumn = deferredRLRow.getColumn(rlColumnNumber);\r
+                               baseRowLocation = \r
+                                       (RowLocation) (rlColumn).getObject();\r
+       \r
+                               /* Get the base row at the given RowLocation */\r
+                               boolean row_exists = \r
+                                       deferredBaseCC.fetch(\r
+                                                                                baseRowLocation, deferredSparseRow.getRowArray(), \r
+                                                                                readBitSet);\r
+\r
+                               // In case of cascade delete , things like before triggers can delete \r
+                               // the rows before the dependent result get a chance to delete\r
+                               if(cascadeDelete && !row_exists)\r
+                                       continue;\r
+\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       if (!row_exists)\r
+                                       {\r
+                               SanityManager.THROWASSERT("could not find row "+baseRowLocation);\r
+                                       }\r
+                               }\r
+       \r
+                               rc.deleteRow(deferredBaseRow, baseRowLocation);\r
+                               source.markRowAsDeleted();\r
+                       }\r
+               } finally\r
+               {\r
+                               rs.close();\r
+               }\r
+       }\r
+\r
+\r
+       // make sure foreign key constraints are not violated\r
+    void runFkChecker(boolean restrictCheckOnly) throws StandardException\r
+       {\r
+\r
+               ExecRow         deferredRLRow = null;\r
+               if (fkChecker != null)\r
+               {\r
+                       /*\r
+                       ** Second scan to make sure all the foreign key\r
+                       ** constraints are ok.  We have to do this after\r
+                       ** we have completed the deletes in case of self referencing\r
+                       ** constraints.\r
+                       */\r
+                       CursorResultSet rs = rowHolder.getResultSet();\r
+                       try\r
+                       {\r
+                               rs.open();\r
+                               while ((deferredRLRow = rs.getNextRow()) != null)\r
+                               {\r
+                                       fkChecker.doPKCheck(deferredRLRow, restrictCheckOnly);\r
+                               }\r
+                       } finally\r
+                       {\r
+                               rs.close();\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+         *     create a source for the dependent table\r
+         *\r
+         * <P>Delete Cascade ResultSet class will override this method.\r
+         *\r
+         * @exception StandardException                Thrown on error\r
+         */\r
+       NoPutResultSet createDependentSource(RowChanger rc)\r
+               throws StandardException\r
+       {\r
+               return null;\r
+       }\r
+\r
+\r
+       /**\r
+        * @see ResultSet#cleanUp\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       public void     cleanUp() throws StandardException\r
+       { \r
+               numOpens = 0;\r
+\r
+               /* Close down the source ResultSet tree */\r
+               if (source != null)\r
+               {\r
+                       source.close();\r
+                       // source is reused across executions\r
+               }\r
+               if (rc != null)\r
+               {\r
+                       rc.close();\r
+                       // rc is reused across executions\r
+               }\r
+\r
+               if (rowHolder != null)\r
+               {\r
+                       rowHolder.close();\r
+                       // rowHolder is reused across executions\r
+               }\r
+\r
+               if (fkChecker != null)\r
+               {\r
+                       fkChecker.close();\r
+                       // fkcheckers is reused across executions\r
+               }\r
+\r
+               if (deferredBaseCC != null)\r
+                       deferredBaseCC.close();\r
+               deferredBaseCC = null;\r
+\r
+               if (rc != null) {\r
+                       rc.close();\r
+               }\r
+               super.close();\r
+       }\r
+\r
+       public void finish() throws StandardException {\r
+               if (source != null)\r
+                       source.finish();\r
+               super.finish();\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r