--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.AlterTableNode\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.reference.SQLState;\r
+import org.apache.derby.iapi.reference.Limits;\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.compile.C_NodeTypes;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+\r
+import org.apache.derby.impl.sql.execute.ColumnInfo;\r
+import org.apache.derby.impl.sql.execute.ConstraintConstantAction;\r
+\r
+/**\r
+ * A AlterTableNode represents a DDL statement that alters a table.\r
+ * It contains the name of the object to be created.\r
+ *\r
+ */\r
+\r
+public class AlterTableNode extends DDLStatementNode\r
+{\r
+ // The alter table action\r
+ public TableElementList tableElementList = null;\r
+ public char lockGranularity;\r
+ public boolean compressTable = false;\r
+ public boolean sequential = false;\r
+ public int behavior; // currently for drop column\r
+\r
+ public TableDescriptor baseTable;\r
+\r
+ protected int numConstraints;\r
+\r
+ private int changeType = UNKNOWN_TYPE;\r
+\r
+ private boolean truncateTable = false;\r
+\r
+ // constant action arguments\r
+\r
+ protected SchemaDescriptor schemaDescriptor = null;\r
+ protected ColumnInfo[] colInfos = null;\r
+ protected ConstraintConstantAction[] conActions = null;\r
+\r
+\r
+ /**\r
+ * Initializer for a TRUNCATE TABLE\r
+ *\r
+ * @param objectName The name of the table being truncated\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void init(Object objectName)\r
+ throws StandardException\r
+ {\r
+\r
+ //truncate table is not suppotted in this release\r
+ //semantics are not yet clearly defined by SQL Council yet\r
+ //truncate will be allowed only in DEBUG builds for testing purposes.\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ initAndCheck(objectName);\r
+ /* For now, this init() only called for truncate table */\r
+ truncateTable = true;\r
+ schemaDescriptor = getSchemaDescriptor();\r
+ }else\r
+ {\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED,\r
+ "truncate table");\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Initializer for a AlterTableNode for COMPRESS\r
+ *\r
+ * @param objectName The name of the table being altered\r
+ * @param sequential Whether or not the COMPRESS is SEQUENTIAL\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void init(Object objectName,\r
+ Object sequential)\r
+ throws StandardException\r
+ {\r
+ initAndCheck(objectName);\r
+\r
+ this.sequential = ((Boolean) sequential).booleanValue();\r
+ /* For now, this init() only called for compress table */\r
+ compressTable = true;\r
+\r
+ schemaDescriptor = getSchemaDescriptor();\r
+ }\r
+\r
+ /**\r
+ * Initializer for a AlterTableNode\r
+ *\r
+ * @param objectName The name of the table being altered\r
+ * @param tableElementList The alter table action\r
+ * @param lockGranularity The new lock granularity, if any\r
+ * @param changeType ADD_TYPE or DROP_TYPE\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void init(\r
+ Object objectName,\r
+ Object tableElementList,\r
+ Object lockGranularity,\r
+ Object changeType,\r
+ Object behavior,\r
+ Object sequential )\r
+ throws StandardException\r
+ {\r
+ initAndCheck(objectName);\r
+ this.tableElementList = (TableElementList) tableElementList;\r
+ this.lockGranularity = ((Character) lockGranularity).charValue();\r
+\r
+ int[] ct = (int[]) changeType, bh = (int[]) behavior;\r
+ this.changeType = ct[0];\r
+ this.behavior = bh[0];\r
+ boolean[] seq = (boolean[]) sequential;\r
+ this.sequential = seq[0];\r
+ switch ( this.changeType )\r
+ {\r
+ case ADD_TYPE:\r
+ case DROP_TYPE:\r
+ case MODIFY_TYPE:\r
+ case LOCKING_TYPE:\r
+\r
+ break;\r
+\r
+ default:\r
+\r
+ throw StandardException.newException(SQLState.NOT_IMPLEMENTED);\r
+ }\r
+\r
+ schemaDescriptor = getSchemaDescriptor();\r
+ }\r
+\r
+ /**\r
+ * Convert this object to a String. See comments in QueryTreeNode.java\r
+ * for how this should be done for tree printing.\r
+ *\r
+ * @return This object as a String\r
+ */\r
+\r
+ public String toString()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ return super.toString() +\r
+ "objectName: " + "\n" + getObjectName() + "\n" +\r
+ "tableElementList: " + "\n" + tableElementList + "\n" +\r
+ "lockGranularity: " + "\n" + lockGranularity + "\n" +\r
+ "compressTable: " + "\n" + compressTable + "\n" +\r
+ "sequential: " + "\n" + sequential + "\n" +\r
+ "truncateTable: " + "\n" + truncateTable + "\n";\r
+ }\r
+ else\r
+ {\r
+ return "";\r
+ }\r
+ }\r
+\r
+ public String statementToString()\r
+ {\r
+ if(truncateTable)\r
+ return "TRUNCATE TABLE";\r
+ else\r
+ return "ALTER TABLE";\r
+ }\r
+\r
+ public int getChangeType() { return changeType; }\r
+\r
+ // We inherit the generate() method from DDLStatementNode.\r
+\r
+ /**\r
+ * Bind this AlterTableNode. This means doing any static error\r
+ * checking that can be done before actually creating the table.\r
+ * For example, verifying that the user is not trying to add a \r
+ * non-nullable column.\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void bindStatement() throws StandardException\r
+ {\r
+ DataDictionary dd = getDataDictionary();\r
+ int numCheckConstraints = 0;\r
+ int numBackingIndexes = 0;\r
+\r
+ /*\r
+ ** Get the table descriptor. Checks the schema\r
+ ** and the table.\r
+ */\r
+ baseTable = getTableDescriptor();\r
+ //throw an exception if user is attempting to alter a temporary table\r
+ if (baseTable.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE);\r
+ }\r
+\r
+ /* Statement is dependent on the TableDescriptor */\r
+ getCompilerContext().createDependency(baseTable);\r
+\r
+ //If we are dealing with add column character type, then set that \r
+ //column's collation type to be the collation type of the schema.\r
+ //The collation derivation of such a column would be "implicit".\r
+ if (changeType == ADD_TYPE) {//the action is of type add.\r
+ if (tableElementList != null) {//check if is is add column\r
+ for (int i=0; i<tableElementList.size();i++) {\r
+ if (tableElementList.elementAt(i) instanceof ColumnDefinitionNode) {\r
+ ColumnDefinitionNode cdn = (ColumnDefinitionNode) tableElementList.elementAt(i);\r
+ //check if we are dealing with add character column\r
+ if (cdn.getDataTypeServices().getTypeId().isStringTypeId()) {\r
+ //we found what we are looking for. Set the \r
+ //collation type of this column to be the same as\r
+ //schema descriptor's collation. Set the collation\r
+ //derivation as implicit\r
+ cdn.getDataTypeServices().setCollationType(schemaDescriptor.getCollationType());\r
+ cdn.getDataTypeServices().setCollationDerivation(StringDataValue.COLLATION_DERIVATION_IMPLICIT);\r
+ } \r
+ }\r
+ }\r
+ \r
+ }\r
+ }\r
+ if (tableElementList != null)\r
+ {\r
+ tableElementList.validate(this, dd, baseTable);\r
+\r
+ /* Only 1012 columns allowed per table */\r
+ if ((tableElementList.countNumberOfColumns() + baseTable.getNumberOfColumns()) > Limits.DB2_MAX_COLUMNS_IN_TABLE)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_TOO_MANY_COLUMNS_IN_TABLE_OR_VIEW,\r
+ String.valueOf(tableElementList.countNumberOfColumns() + baseTable.getNumberOfColumns()),\r
+ getRelativeName(),\r
+ String.valueOf(Limits.DB2_MAX_COLUMNS_IN_TABLE));\r
+ }\r
+ /* Number of backing indexes in the alter table statment */\r
+ numBackingIndexes = tableElementList.countConstraints(DataDictionary.PRIMARYKEY_CONSTRAINT) +\r
+ tableElementList.countConstraints(DataDictionary.FOREIGNKEY_CONSTRAINT) +\r
+ tableElementList.countConstraints(DataDictionary.UNIQUE_CONSTRAINT);\r
+ /* Check the validity of all check constraints */\r
+ numCheckConstraints = tableElementList.countConstraints(\r
+ DataDictionary.CHECK_CONSTRAINT);\r
+ }\r
+\r
+ //If the sum of backing indexes for constraints in alter table statement and total number of indexes on the table\r
+ //so far is more than 32767, then we need to throw an exception \r
+ if ((numBackingIndexes + baseTable.getTotalNumberOfIndexes()) > Limits.DB2_MAX_INDEXES_ON_TABLE)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_TOO_MANY_INDEXES_ON_TABLE, \r
+ String.valueOf(numBackingIndexes + baseTable.getTotalNumberOfIndexes()),\r
+ getRelativeName(),\r
+ String.valueOf(Limits.DB2_MAX_INDEXES_ON_TABLE));\r
+ }\r
+\r
+ if (numCheckConstraints > 0)\r
+ {\r
+ /* In order to check the validity of the check constraints\r
+ * we must goober up a FromList containing a single table, \r
+ * the table being alter, with an RCL containing the existing and\r
+ * new columns and their types. This will allow us to\r
+ * bind the constraint definition trees against that\r
+ * FromList. When doing this, we verify that there are\r
+ * no nodes which can return non-deterministic results.\r
+ */\r
+ FromList fromList = (FromList) getNodeFactory().getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ getNodeFactory().doJoinOrderOptimization(),\r
+ getContextManager());\r
+ FromBaseTable table = (FromBaseTable)\r
+ getNodeFactory().getNode(\r
+ C_NodeTypes.FROM_BASE_TABLE,\r
+ getObjectName(),\r
+ null,\r
+ null,\r
+ null,\r
+ getContextManager());\r
+ fromList.addFromTable(table);\r
+ fromList.bindTables(dd,\r
+ (FromList) getNodeFactory().getNode(\r
+ C_NodeTypes.FROM_LIST,\r
+ getNodeFactory().doJoinOrderOptimization(),\r
+ getContextManager()));\r
+ tableElementList.appendNewColumnsToRCL(table);\r
+\r
+ /* Now that we've finally goobered stuff up, bind and validate\r
+ * the check constraints.\r
+ */\r
+ tableElementList.bindAndValidateCheckConstraints(fromList);\r
+\r
+ }\r
+\r
+ /* Unlike most other DDL, we will make this ALTER TABLE statement\r
+ * dependent on the table being altered. In general, we try to\r
+ * avoid this for DDL, but we are already requiring the table to\r
+ * exist at bind time (not required for create index) and we don't\r
+ * want the column ids to change out from under us before\r
+ * execution.\r
+ */\r
+ getCompilerContext().createDependency(baseTable);\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 alter table is on a SESSION schema table, then return true. \r
+ return isSessionSchema(baseTable.getSchemaName());\r
+ }\r
+\r
+ /**\r
+ * Create the Constant information that will drive the guts of Execution.\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public ConstantAction makeConstantAction() throws StandardException\r
+ {\r
+ prepConstantAction();\r
+\r
+ return getGenericConstantActionFactory().getAlterTableConstantAction(schemaDescriptor,\r
+ getRelativeName(),\r
+ baseTable.getUUID(),\r
+ baseTable.getHeapConglomerateId(),\r
+ TableDescriptor.BASE_TABLE_TYPE,\r
+ colInfos,\r
+ conActions,\r
+ lockGranularity,\r
+ compressTable,\r
+ behavior,\r
+ sequential,\r
+ truncateTable);\r
+ }\r
+\r
+ /**\r
+ * Generate arguments to constant action. Called by makeConstantAction() in this class and in\r
+ * our subclass RepAlterTableNode.\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public void prepConstantAction() throws StandardException\r
+ {\r
+ if (tableElementList != null)\r
+ {\r
+ genColumnInfo();\r
+ }\r
+\r
+ /* If we've seen a constraint, then build a constraint list */\r
+\r
+ if (numConstraints > 0)\r
+ {\r
+ conActions = new ConstraintConstantAction[numConstraints];\r
+\r
+ tableElementList.genConstraintActions(conActions, getRelativeName(), schemaDescriptor,\r
+ getDataDictionary());\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Generate the ColumnInfo argument for the constant action. Return the number of constraints.\r
+ */\r
+ public void genColumnInfo()\r
+ {\r
+ // for each column, stuff system.column\r
+ colInfos = new ColumnInfo[tableElementList.countNumberOfColumns()]; \r
+\r
+ numConstraints = tableElementList.genColumnInfos(colInfos);\r
+ }\r
+\r
+\r
+ /*\r
+ * class interface\r
+ */\r
+}\r
+\r
+\r
+\r
+\r