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 / ModifyColumnNode.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/ModifyColumnNode.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/sql/compile/ModifyColumnNode.java
new file mode 100644 (file)
index 0000000..0c65da0
--- /dev/null
@@ -0,0 +1,393 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.sql.compile.ModifyColumnNode\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.sql.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;\r
+\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.impl.sql.execute.ColumnInfo;\r
+import org.apache.derby.catalog.TypeDescriptor;\r
+import org.apache.derby.catalog.UUID;\r
+import org.apache.derby.catalog.types.DefaultInfoImpl;\r
+\r
+/**\r
+ * A ModifyColumnNode represents a modify column in an ALTER TABLE statement.\r
+ *\r
+ */\r
+\r
+public class ModifyColumnNode extends ColumnDefinitionNode\r
+{\r
+       int             columnPosition = -1;\r
+       UUID    oldDefaultUUID;\r
+\r
+       /**\r
+        * Get the UUID of the old column default.\r
+        *\r
+        * @return The UUID of the old column default.\r
+        */\r
+       UUID getOldDefaultUUID()\r
+       {\r
+               return oldDefaultUUID;\r
+       }\r
+\r
+       /**\r
+        * Get the column position for the column.\r
+        *\r
+        * @return The column position for the column.\r
+        */\r
+       public int getColumnPosition()\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(columnPosition > 0,\r
+                               "columnPosition expected to be > 0");\r
+               }\r
+               return columnPosition;\r
+       }\r
+\r
+       /**\r
+        * Check the validity of a user type.  Checks that\r
+        * 1. the column type is either varchar, ....\r
+        * 2. is the same type after the alter.\r
+        * 3. length is greater than the old length.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+\r
+       public void checkUserType(TableDescriptor td)\r
+               throws StandardException\r
+       {\r
+               if (getNodeType() != C_NodeTypes.MODIFY_COLUMN_TYPE_NODE)\r
+                       return;                         // nothing to do if user not changing length\r
+\r
+        ColumnDescriptor cd = td.getColumnDescriptor(name);\r
+               if (cd == null)\r
+               {\r
+                       throw StandardException.newException(\r
+                               SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());\r
+               }\r
+               \r
+               DataTypeDescriptor oldType = cd.getType();\r
+        dataTypeServices = \r
+            getDataTypeServices().getNullabilityType(oldType.isNullable());\r
+\r
+               // can't change types yet.\r
+               if (!(oldType.getTypeId().equals(getDataTypeServices().getTypeId())))\r
+               {\r
+                       throw StandardException.newException(\r
+                                        SQLState.LANG_MODIFY_COLUMN_CHANGE_TYPE, name);\r
+               }                       \r
+               \r
+               // can only alter the length of varchar, bitvarying columns\r
+               String typeName = getDataTypeServices().getTypeName();\r
+               if (!(typeName.equals(TypeId.VARCHAR_NAME)) &&\r
+                       !(typeName.equals(TypeId.VARBIT_NAME)))\r
+               {\r
+                       throw StandardException.newException(\r
+                                                SQLState.LANG_MODIFY_COLUMN_INVALID_TYPE);\r
+               }\r
+               \r
+               // cannot decrease the length of a column\r
+               if (getDataTypeServices().getMaximumWidth() < oldType.getMaximumWidth())\r
+               {\r
+                       throw StandardException.newException(\r
+                                                SQLState.LANG_MODIFY_COLUMN_INVALID_LENGTH, name);\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * If the type of a column is being changed (for mulan, the length of the\r
+        * column is being increased then make sure that this does not violate\r
+        * any key constraints; \r
+        * the column being altered is \r
+        *   1. part of foreign key constraint \r
+        *         ==> ERROR. This references a Primary Key constraint and the\r
+        *             type & lengths of the pkey/fkey must match exactly.\r
+        *   2. part of a unique/primary key constraint\r
+        *         ==> OK if no fkey references this constraint.\r
+        *         ==> ERROR if any fkey in the system references this constraint.\r
+        *\r
+        * @param td            The Table Descriptor on which the ALTER is being done.\r
+        *\r
+        * @exception StandardException         Thrown on Error.\r
+        *\r
+        */\r
+       public void checkExistingConstraints(TableDescriptor td)\r
+                    throws StandardException\r
+       {\r
+               if ((getNodeType() != C_NodeTypes.MODIFY_COLUMN_TYPE_NODE) &&\r
+                       (getNodeType() != C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE) &&\r
+                       (getNodeType() != C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE))\r
+                       return;\r
+\r
+               DataDictionary dd = getDataDictionary();\r
+               ConstraintDescriptorList cdl = dd.getConstraintDescriptors(td);\r
+               int intArray[] = new int[1];\r
+               intArray[0] = columnPosition;\r
+\r
+               for (int index = 0; index < cdl.size(); index++)\r
+               {\r
+                       ConstraintDescriptor existingConstraint =\r
+                                                               cdl.elementAt(index);\r
+                       if (!(existingConstraint instanceof KeyConstraintDescriptor))\r
+                               continue;\r
+\r
+                       if (!existingConstraint.columnIntersects(intArray))\r
+                               continue;\r
+                                                                                                                        \r
+                       int constraintType = existingConstraint.getConstraintType();\r
+\r
+                       // cannot change the length of a column that is part of a \r
+                       // foreign key constraint. Must be an exact match between pkey\r
+                       // and fkey columns.\r
+                       if ((constraintType == DataDictionary.FOREIGNKEY_CONSTRAINT) \r
+                               &&\r
+                               (getNodeType() == C_NodeTypes.MODIFY_COLUMN_TYPE_NODE))\r
+                       {\r
+                               throw StandardException.newException(\r
+                                        SQLState.LANG_MODIFY_COLUMN_FKEY_CONSTRAINT, name, existingConstraint.getConstraintName());\r
+                       }       \r
+                       \r
+                       else\r
+                       {\r
+                               // a column that is part of a primary key or unique constraint\r
+                // is being made nullable; can't be done.\r
+                               if ((getNodeType() == \r
+                                        C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE) &&\r
+                                       ((existingConstraint.getConstraintType() == \r
+                                        DataDictionary.PRIMARYKEY_CONSTRAINT) ||\r
+                                        (existingConstraint.getConstraintType() == \r
+                                        DataDictionary.UNIQUE_CONSTRAINT)))\r
+                               {\r
+                               throw StandardException.newException(\r
+                                        SQLState.LANG_MODIFY_COLUMN_EXISTING_CONSTRAINT, name);\r
+                               }\r
+                               // unique key or primary key.\r
+                               ConstraintDescriptorList \r
+                                       refcdl = dd.getForeignKeys(existingConstraint.getUUID());\r
+                                \r
+                               if (refcdl.size() > 0)\r
+                               {\r
+                                       throw StandardException.newException(\r
+                                                SQLState.LANG_MODIFY_COLUMN_REFERENCED, name, refcdl.elementAt(0).getConstraintName());\r
+                               }\r
+                               \r
+                               // Make the statement dependent on the primary key constraint.\r
+                               getCompilerContext().createDependency(existingConstraint);\r
+                       }\r
+               }\r
+    }\r
+\r
+       /**\r
+        * If the column being modified is of character string type, then it should\r
+        * get it's collation from the corresponding column in the TableDescriptor.\r
+        * This will ensure that at alter table time, the existing character string\r
+        * type columns do not loose their collation type. If the alter table is \r
+        * doing a drop column, then we do not need to worry about collation info.\r
+        * \r
+        * @param td Table Descriptor that holds the column which is being altered\r
+        * @throws StandardException\r
+        */\r
+       public void useExistingCollation(TableDescriptor td)\r
+    throws StandardException\r
+    {\r
+               ColumnDescriptor cd;\r
+\r
+               // First verify that the column exists\r
+               cd = td.getColumnDescriptor(name);\r
+               if (cd == null)\r
+               {\r
+                       throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());\r
+               }\r
+               //getType() == null means we are dealing with drop column and hence \r
+               //no need to worry about collation info\r
+               if (getDataTypeServices() != null) {\r
+                       if (getDataTypeServices().getTypeId().isStringTypeId()) {\r
+                               this.getDataTypeServices().setCollationType(cd.getType().getCollationType());\r
+                               this.getDataTypeServices().setCollationDerivation(StringDataValue.COLLATION_DERIVATION_IMPLICIT);\r
+                       \r
+                       }\r
+               }\r
+    }\r
+       /**\r
+        * Get the action associated with this node.\r
+        *\r
+        * @return The action associated with this node.\r
+        */\r
+       int getAction()\r
+       {\r
+               switch (getNodeType())\r
+               {\r
+               case C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE:\r
+                       if (autoinc_create_or_modify_Start_Increment == ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE)\r
+                               return ColumnInfo.MODIFY_COLUMN_DEFAULT_RESTART;\r
+                       else if (autoinc_create_or_modify_Start_Increment ==\r
+                               ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE)\r
+                               return ColumnInfo.MODIFY_COLUMN_DEFAULT_INCREMENT;\r
+                       else\r
+                               return ColumnInfo.MODIFY_COLUMN_DEFAULT_VALUE;\r
+               case C_NodeTypes.MODIFY_COLUMN_TYPE_NODE:\r
+                       return ColumnInfo.MODIFY_COLUMN_TYPE;\r
+               case C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE:\r
+                       return ColumnInfo.MODIFY_COLUMN_CONSTRAINT;\r
+               case C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE:\r
+                       return ColumnInfo.MODIFY_COLUMN_CONSTRAINT_NOT_NULL;\r
+               case C_NodeTypes.DROP_COLUMN_NODE:\r
+                       return ColumnInfo.DROP;\r
+               default:\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               SanityManager.THROWASSERT("Unexpected nodeType = " + \r
+                                                                                 getNodeType());\r
+                       }\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * Check the validity of the default, if any, for this node.\r
+        *\r
+        * @param dd            The DataDictionary.\r
+        * @param td            The TableDescriptor.\r
+        *\r
+        * @exception StandardException         Thrown on error\r
+        */\r
+       void bindAndValidateDefault(DataDictionary dd, TableDescriptor td) \r
+               throws StandardException\r
+       {\r
+               ColumnDescriptor cd;\r
+\r
+               // First verify that the column exists\r
+               cd = td.getColumnDescriptor(name);\r
+               if (cd == null)\r
+               {\r
+                       throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());\r
+               }\r
+\r
+\r
+               // Get the UUID for the old default\r
+               DefaultDescriptor defaultDescriptor = cd.getDefaultDescriptor(dd);\r
+               \r
+               oldDefaultUUID = (defaultDescriptor == null) ? null : defaultDescriptor.getUUID();\r
+\r
+               // Remember the column position\r
+               columnPosition = cd.getPosition();\r
+\r
+               // No other work to do if no user specified default\r
+               if (getNodeType() != C_NodeTypes.MODIFY_COLUMN_DEFAULT_NODE)\r
+               {\r
+                       return;\r
+               }\r
+\r
+               // If the statement is not setting the column's default, then\r
+               // recover the old default and re-use it. If the statement is\r
+               // changing the start value for the auto-increment, then recover\r
+               // the old increment-by value and re-use it. If the statement is\r
+               // changing the increment-by value, then recover the old start value\r
+               // and re-use it. This way, the column alteration only changes the\r
+               // aspects of the autoincrement settings that it intends to change,\r
+               // and does not lose the other aspecs.\r
+               if (defaultNode == null)\r
+                       defaultInfo = (DefaultInfoImpl)cd.getDefaultInfo();\r
+               if (autoinc_create_or_modify_Start_Increment ==\r
+                               ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE)\r
+                       autoincrementIncrement = cd.getAutoincInc();\r
+               if (autoinc_create_or_modify_Start_Increment ==\r
+                               ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE)\r
+                       autoincrementStart = cd.getAutoincStart();\r
+\r
+               /* Fill in the DataTypeServices from the DataDictionary */\r
+               dataTypeServices = cd.getType();\r
+\r
+               // Now validate the default\r
+               validateDefault(dd, td);\r
+       }\r
+       \r
+       private ColumnDescriptor getLocalColumnDescriptor(String name, TableDescriptor td)\r
+                throws StandardException\r
+       {\r
+               ColumnDescriptor cd;\r
+\r
+               // First verify that the column exists\r
+               cd = td.getColumnDescriptor(name);\r
+               if (cd == null)\r
+               {\r
+                       throw StandardException.newException(\r
+                               SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, name, td.getName());\r
+               }\r
+\r
+               return cd;\r
+       }\r
+       /**\r
+        * check the validity of autoincrement values in the case that we are \r
+        * modifying an existing column (includes checking if autoincrement is set\r
+        * when making a column nullable)\r
+        */\r
+       public void validateAutoincrement(DataDictionary dd, TableDescriptor td, int tableType)\r
+                throws StandardException\r
+       {\r
+               ColumnDescriptor cd;\r
+\r
+               // a column that has an autoincrement default can't be made nullable\r
+               if (getNodeType() == C_NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE)\r
+               {\r
+                       cd = getLocalColumnDescriptor(name, td);\r
+                       if (cd.isAutoincrement())\r
+                       {\r
+                               throw StandardException.newException(SQLState.LANG_AI_CANNOT_NULL_AI,\r
+                                               getColumnName());\r
+                       }\r
+               }\r
+\r
+               if (autoincrementVerify)\r
+               {\r
+                       cd = getLocalColumnDescriptor(name, td);\r
+                       if (!cd.isAutoincrement())\r
+                               throw StandardException.newException(SQLState.LANG_INVALID_ALTER_TABLE_ATTRIBUTES,\r
+                                                               td.getQualifiedName(), name);\r
+               }\r
+               if (isAutoincrement == false)\r
+                       return;\r
+               \r
+               super.validateAutoincrement(dd, td, tableType);\r
+               if (getDataTypeServices().isNullable())\r
+                       throw StandardException.newException(SQLState.LANG_AI_CANNOT_ADD_AI_TO_NULLABLE,\r
+                                                                                               getColumnName());\r
+       }\r
+}\r