Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / sql / execute / ConstraintConstantAction.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/sql/execute/ConstraintConstantAction.java
new file mode 100644 (file)
index 0000000..755dd0b
--- /dev/null
@@ -0,0 +1,330 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.execute.ConstraintConstantAction\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 org.apache.derby.catalog.UUID;\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.PreparedStatement;\r
+import org.apache.derby.iapi.sql.ResultSet;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.execute.ExecRow;\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.GroupFetchScanController;\r
+import org.apache.derby.iapi.store.access.ScanController;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.NumberDataValue;\r
+/**\r
+ *     This class  describes actions that are ALWAYS performed for a\r
+ *     constraint creation at Execution time.\r
+ *\r
+ *     @version 0.1\r
+ */\r
+\r
+public abstract class ConstraintConstantAction extends DDLSingleTableConstantAction \r
+{\r
+\r
+       protected       String                  constraintName;\r
+       protected       int                             constraintType;\r
+       protected       String                  tableName;\r
+       protected       String                  schemaName;\r
+       protected       UUID                    schemaId;\r
+       protected  IndexConstantAction indexAction;\r
+\r
+       // CONSTRUCTORS\r
+       /**\r
+        *      Make one of these puppies.\r
+        *\r
+        *  @param constraintName       Constraint name.\r
+        *  @param constraintType       Constraint type.\r
+        *  @param tableName            Table name.\r
+        *  @param tableId                      UUID of table.\r
+        *  @param schemaName           schema that table and constraint lives in.\r
+        *  @param indexAction          IndexConstantAction for constraint (if necessary)\r
+        *  RESOLVE - the next parameter should go away once we use UUIDs\r
+        *                        (Generated constraint names will be based off of uuids)\r
+        */\r
+       ConstraintConstantAction(\r
+                              String   constraintName,\r
+                                          int          constraintType,\r
+                              String   tableName,\r
+                                          UUID         tableId,\r
+                                          String       schemaName,\r
+                                          IndexConstantAction indexAction)\r
+       {\r
+               super(tableId);\r
+               this.constraintName = constraintName;\r
+               this.constraintType = constraintType;\r
+               this.tableName = tableName;\r
+               this.indexAction = indexAction;\r
+               this.schemaName = schemaName;\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(schemaName != null, "Constraint schema name is null");\r
+               }\r
+       }\r
+\r
+       // Class implementation\r
+\r
+       /**\r
+        * Get the constraint type.\r
+        *\r
+        * @return The constraint type\r
+        */\r
+       public  int getConstraintType()\r
+       {\r
+               return constraintType;\r
+       }\r
+\r
+       /**\r
+         *     Get the constraint name\r
+         *\r
+         *     @return the constraint name\r
+         */\r
+    public     String  getConstraintName() { return constraintName; }\r
+\r
+       /**\r
+         *     Get the associated index constant action.\r
+         *\r
+         *     @return the constant action for the backing index\r
+         */\r
+    public     IndexConstantAction     getIndexAction() { return indexAction; }\r
+\r
+       /**\r
+        * Make sure that the foreign key constraint is valid\r
+        * with the existing data in the target table.  Open\r
+        * the table, if there aren't any rows, ok.  If there\r
+        * are rows, open a scan on the referenced key with\r
+        * table locking at level 2.  Pass in the scans to\r
+        * the BulkRIChecker.  If any rows fail, barf.\r
+        *\r
+        * @param       tc              transaction controller\r
+        * @param       dd              data dictionary\r
+        * @param       fk              foreign key constraint\r
+        * @param       refcd   referenced key\r
+        * @param       indexTemplateRow        index template row\r
+        *\r
+        * @exception StandardException on error\r
+        */\r
+       static void validateFKConstraint\r
+       (\r
+               TransactionController                           tc,\r
+               DataDictionary                                          dd,\r
+               ForeignKeyConstraintDescriptor          fk,\r
+               ReferencedKeyConstraintDescriptor       refcd,\r
+               ExecRow                                                         indexTemplateRow \r
+       )\r
+               throws StandardException\r
+       {\r
+\r
+               GroupFetchScanController refScan = null;\r
+\r
+               GroupFetchScanController fkScan = \r
+            tc.openGroupFetchScan(\r
+                fk.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),\r
+                false,                                         // hold \r
+                0,                                                                             // read only\r
+                tc.MODE_TABLE,                                                 // already locked\r
+                tc.ISOLATION_READ_COMMITTED,                   // whatever\r
+                (FormatableBitSet)null,                                                        // retrieve all fields\r
+                (DataValueDescriptor[])null,               // startKeyValue\r
+                ScanController.GE,                             // startSearchOp\r
+                null,                                          // qualifier\r
+                (DataValueDescriptor[])null,                   // stopKeyValue\r
+                ScanController.GT                              // stopSearchOp \r
+                );\r
+\r
+               try\r
+               {\r
+                       /*\r
+                       ** If we have no rows, then we are ok.  This will \r
+                       ** catch the CREATE TABLE T (x int references P) case\r
+                       ** (as well as an ALTER TABLE ADD CONSTRAINT where there\r
+                       ** are no rows in the target table).\r
+                       */      \r
+                       if (!fkScan.next())\r
+                       {\r
+                               fkScan.close();\r
+                               return;\r
+                       }\r
+\r
+                       fkScan.reopenScan(\r
+                                       (DataValueDescriptor[])null,                    // startKeyValue\r
+                                       ScanController.GE,                              // startSearchOp\r
+                                       null,                                           // qualifier\r
+                                       (DataValueDescriptor[])null,                    // stopKeyValue\r
+                                       ScanController.GT                               // stopSearchOp \r
+                                       );\r
+\r
+                       /*\r
+                       ** Make sure each row in the new fk has a matching\r
+                       ** referenced key.  No need to get any special locking\r
+                       ** on the referenced table because it cannot delete\r
+                       ** any keys we match because it will block on the table\r
+                       ** lock on the fk table (we have an ex tab lock on\r
+                       ** the target table of this ALTER TABLE command).\r
+                       ** Note that we are doing row locking on the referenced\r
+                       ** table.  We could speed things up and get table locking\r
+                       ** because we are likely to be hitting a lot of rows\r
+                       ** in the referenced table, but we are going to err\r
+                       ** on the side of concurrency here.\r
+                       */\r
+                       refScan = \r
+                tc.openGroupFetchScan(\r
+                                       refcd.getIndexConglomerateDescriptor(dd).getConglomerateNumber(),\r
+                        false,                         // hold \r
+                        0,                                                             // read only\r
+                        tc.MODE_RECORD,\r
+                        tc.ISOLATION_READ_COMMITTED,   // read committed is good enough\r
+                        (FormatableBitSet)null,                                        // retrieve all fields\r
+                        (DataValueDescriptor[])null,    // startKeyValue\r
+                        ScanController.GE,             // startSearchOp\r
+                        null,                          // qualifier\r
+                        (DataValueDescriptor[])null,   // stopKeyValue\r
+                        ScanController.GT              // stopSearchOp \r
+                        );\r
+\r
+                       RIBulkChecker riChecker = new RIBulkChecker(refScan, \r
+                                                                               fkScan, \r
+                                                                               indexTemplateRow,       \r
+                                                                               true,                           // fail on 1st failure\r
+                                                                               (ConglomerateController)null,\r
+                                                                               (ExecRow)null);\r
+\r
+                       int numFailures = riChecker.doCheck();\r
+                       if (numFailures > 0)\r
+                       {\r
+                               StandardException se = StandardException.newException(SQLState.LANG_ADD_FK_CONSTRAINT_VIOLATION, \r
+                                                                       fk.getConstraintName(), \r
+                                                                       fk.getTableDescriptor().getName());\r
+                               throw se;\r
+                       }\r
+               }\r
+               finally\r
+               {\r
+                       if (fkScan != null)\r
+                       {\r
+                               fkScan.close();\r
+                               fkScan = null;\r
+                       }\r
+                       if (refScan != null)\r
+                       {\r
+                               refScan.close();\r
+                               refScan = null;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Evaluate a check constraint or not null column constraint.  \r
+        * Generate a query of the\r
+        * form SELECT COUNT(*) FROM t where NOT(<check constraint>)\r
+        * and run it by compiling and executing it.   Will\r
+        * work ok if the table is empty and query returns null.\r
+        *\r
+        * @param constraintName        constraint name\r
+        * @param constraintText        constraint text\r
+        * @param td                            referenced table\r
+        * @param lcc                           the language connection context\r
+        * @param isCheckConstraint     the constraint is a check constraint\r
+     *\r
+        * @return true if null constraint passes, false otherwise\r
+        *\r
+        * @exception StandardException if check constraint fails\r
+        */\r
+        static boolean validateConstraint\r
+       (\r
+               String                                                  constraintName,\r
+               String                                                  constraintText,\r
+               TableDescriptor                                 td,\r
+               LanguageConnectionContext               lcc,\r
+               boolean                                                 isCheckConstraint\r
+       )\r
+               throws StandardException\r
+       {\r
+               StringBuffer checkStmt = new StringBuffer();\r
+               /* should not use select sum(not(<check-predicate>) ? 1: 0) because\r
+                * that would generate much more complicated code and may exceed Java\r
+                * limits if we have a large number of check constraints, beetle 4347\r
+                */\r
+               checkStmt.append("SELECT COUNT(*) FROM ");\r
+               checkStmt.append(td.getQualifiedName());\r
+               checkStmt.append(" WHERE NOT(");\r
+               checkStmt.append(constraintText);\r
+               checkStmt.append(")");\r
+       \r
+               ResultSet rs = null;\r
+               try\r
+               {\r
+                       PreparedStatement ps = lcc.prepareInternalStatement(checkStmt.toString());\r
+\r
+            // This is a substatement; for now, we do not set any timeout\r
+            // for it. We might change this behaviour later, by linking\r
+            // timeout to its parent statement's timeout settings.\r
+                       rs = ps.execute(lcc, false, 0L);\r
+                       ExecRow row = rs.getNextRow();\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               if (row == null)\r
+                               {\r
+                                       SanityManager.THROWASSERT("did not get any rows back from query: "+checkStmt.toString());\r
+                               }\r
+                       }\r
+\r
+                       DataValueDescriptor[] rowArray = row.getRowArray();\r
+                       Number value = ((Number)((NumberDataValue)row.getRowArray()[0]).getObject());\r
+                       /*\r
+                       ** Value may be null if there are no rows in the\r
+                       ** table.\r
+                       */\r
+                       if ((value != null) && (value.longValue() != 0))\r
+                       {       \r
+                               //check constraint violated\r
+                               if (isCheckConstraint)\r
+                                       throw StandardException.newException(SQLState.LANG_ADD_CHECK_CONSTRAINT_FAILED, \r
+                                               constraintName, td.getQualifiedName(), value.toString());\r
+                               /*\r
+                                * for not null constraint violations exception will be thrown in caller\r
+                                * check constraint will not get here since exception is thrown\r
+                                * above\r
+                                */\r
+                               return false;\r
+                       }\r
+               }\r
+               finally\r
+               {\r
+                       if (rs != null)\r
+                       {\r
+                               rs.close();\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+}\r