--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.execute.RenameConstantAction\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.iapi.sql.dictionary.SchemaDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;\r
+import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.sql.depend.DependencyManager;\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.sql.Activation;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+\r
+import org.apache.derby.iapi.sql.execute.ConstantAction;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.catalog.UUID;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+\r
+/**\r
+ * This class describes actions that are ALWAYS performed for a\r
+ * RENAME TABLE/COLUMN/INDEX Statement at Execution time.\r
+ *\r
+ */\r
+\r
+class RenameConstantAction extends DDLSingleTableConstantAction\r
+{\r
+\r
+\r
+ private String fullTableName;\r
+ private String tableName;\r
+ private String newTableName;\r
+ private String oldObjectName;\r
+ private String newObjectName;\r
+ private UUID schemaId;\r
+ private SchemaDescriptor sd;\r
+ /* You can rename using either alter table or rename command to\r
+ * rename a table/column. An index can only be renamed with rename\r
+ * command. usedAlterTable flag is used to keep that information.\r
+ */\r
+ private boolean usedAlterTable;\r
+ /* renamingWhat will be set to 1 if user is renaming a table.\r
+ * Will be set to 2 if user is renaming a column and will be\r
+ * set to 3 if user is renaming an index\r
+ */\r
+ private int renamingWhat;\r
+\r
+ // CONSTRUCTORS\r
+\r
+ /**\r
+ * Make the ConstantAction for a RENAME TABLE/COLUMN/INDEX statement.\r
+ *\r
+ * @param fullTableName Fully qualified table name\r
+ * @param tableName Table name.\r
+ * @param oldObjectName This is either the name of column/index in case\r
+ * of rename column/index. For rename table, this is null.\r
+ * @param newObjectName This is new name for table/column/index\r
+ * @param sd Schema that table lives in.\r
+ * @param tableId UUID for table\r
+ * @param usedAlterTable True-Used Alter Table, False-Used Rename.\r
+ * For rename index, this will always be false because\r
+ * there is no alter table command to rename index\r
+ * @param renamingWhat Rename a 1 - table, 2 - column, 3 - index\r
+ *\r
+ */\r
+ public RenameConstantAction\r
+ (\r
+ String fullTableName,\r
+ String tableName,\r
+ String oldObjectName,\r
+ String newObjectName,\r
+ SchemaDescriptor sd,\r
+ UUID tableId,\r
+ boolean usedAlterTable,\r
+ int renamingWhat)\r
+ {\r
+ super(tableId);\r
+ this.fullTableName = fullTableName;\r
+ this.tableName = tableName;\r
+ this.sd = sd;\r
+ this.usedAlterTable = usedAlterTable;\r
+ this.renamingWhat = renamingWhat;\r
+\r
+ switch (this.renamingWhat)\r
+ {\r
+ case StatementType.RENAME_TABLE:\r
+ this.newTableName = newObjectName;\r
+ this.oldObjectName = null;\r
+ this.newObjectName=newObjectName;\r
+ break;\r
+\r
+ case StatementType.RENAME_COLUMN:\r
+ case StatementType.RENAME_INDEX:\r
+ this.oldObjectName = oldObjectName;\r
+ this.newObjectName = newObjectName;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected rename action in RenameConstantAction");\r
+ }\r
+ }\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(sd != null, "SchemaDescriptor is null");\r
+ }\r
+ }\r
+\r
+ // OBJECT METHODS\r
+\r
+ public String toString()\r
+ {\r
+ String renameString;\r
+ if (usedAlterTable)\r
+ renameString = "ALTER TABLE ";\r
+ else\r
+ renameString = "RENAME ";\r
+\r
+ switch (this.renamingWhat)\r
+ {\r
+ case StatementType.RENAME_TABLE:\r
+ if(usedAlterTable)\r
+ renameString = renameString + fullTableName + " RENAME TO " + newTableName;\r
+ else\r
+ renameString = renameString + " TABLE " + fullTableName + " TO " + newTableName;\r
+ break;\r
+\r
+ case StatementType.RENAME_COLUMN:\r
+ if(usedAlterTable)\r
+ renameString = renameString + fullTableName + " RENAME " + oldObjectName + " TO " + newObjectName;\r
+ else\r
+ renameString = renameString + " COLUMN " + fullTableName + "." + oldObjectName + " TO " + newObjectName;\r
+ break;\r
+\r
+ case StatementType.RENAME_INDEX:\r
+ renameString = renameString + " INDEX " + oldObjectName + " TO " + newObjectName;\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected rename action in RenameConstantAction");\r
+ }\r
+ break;\r
+ }\r
+\r
+ return renameString;\r
+ }\r
+\r
+ // INTERFACE METHODS\r
+\r
+\r
+ /**\r
+ * The guts of the Execution-time logic for RENAME TABLE/COLUMN/INDEX.\r
+ *\r
+ * @see ConstantAction#executeConstantAction\r
+ *\r
+ * @exception StandardException Thrown on failure\r
+ */\r
+ public void executeConstantAction\r
+ (\r
+ Activation activation)\r
+ throws StandardException\r
+ {\r
+ TableDescriptor td;\r
+ UUID tableID;\r
+\r
+ LanguageConnectionContext lcc = activation.getLanguageConnectionContext();\r
+ DataDictionary dd = lcc.getDataDictionary();\r
+ DependencyManager dm = dd.getDependencyManager();\r
+ TransactionController tc = lcc.getTransactionExecute();\r
+\r
+\r
+ /*\r
+ ** Inform the data dictionary that we are about to write to it.\r
+ ** There are several calls to data dictionary "get" methods here\r
+ ** that might be done in "read" mode in the data dictionary, but\r
+ ** it seemed safer to do this whole operation in "write" mode.\r
+ **\r
+ ** We tell the data dictionary we're done writing at the end of\r
+ ** the transaction.\r
+ */\r
+ dd.startWriting(lcc);\r
+\r
+ td = dd.getTableDescriptor(tableId);\r
+\r
+ if (td == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, fullTableName);\r
+ }\r
+\r
+ /*\r
+ ** If the schema descriptor is null, then\r
+ ** we must have just read ourselves in.\r
+ ** So we will get the corresponding schema\r
+ ** descriptor from the data dictionary.\r
+ */\r
+ if (sd == null)\r
+ {\r
+ sd = getAndCheckSchemaDescriptor(dd, schemaId, "RENAME TABLE");\r
+ }\r
+\r
+ long heapId = td.getHeapConglomerateId();\r
+\r
+ /* need to lock table, beetle 4271\r
+ */\r
+ lockTableForDDL(tc, heapId, true);\r
+\r
+ /* need to get td again, in case it's changed before lock acquired\r
+ */\r
+ td = dd.getTableDescriptor(tableId);\r
+ if (td == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, fullTableName);\r
+ }\r
+\r
+ switch (renamingWhat)\r
+ {\r
+ case StatementType.RENAME_TABLE:\r
+ execGutsRenameTable(td, activation);\r
+ break;\r
+\r
+ case StatementType.RENAME_COLUMN:\r
+ execGutsRenameColumn(td, activation);\r
+ break;\r
+\r
+ case StatementType.RENAME_INDEX:\r
+ execGutsRenameIndex(td, activation);\r
+ break;\r
+\r
+ default:\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected rename action in RenameConstantAction");\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ //do necessary work for rename table at execute time.\r
+ private void execGutsRenameTable\r
+ (\r
+ TableDescriptor td, Activation activation)\r
+ throws StandardException\r
+ {\r
+ ConstraintDescriptorList constraintDescriptorList;\r
+ ConstraintDescriptor constraintDescriptor;\r
+\r
+ LanguageConnectionContext lcc = activation.getLanguageConnectionContext();\r
+ DataDictionary dd = lcc.getDataDictionary();\r
+ DependencyManager dm = dd.getDependencyManager();\r
+ TransactionController tc = lcc.getTransactionExecute();\r
+ dm.invalidateFor(td, DependencyManager.RENAME, lcc);\r
+\r
+ /* look for foreign key dependency on the table. If found any,\r
+ use dependency manager to pass the rename action to the\r
+ dependents. */\r
+ constraintDescriptorList = dd.getConstraintDescriptors(td);\r
+ for(int index=0; index<constraintDescriptorList.size(); index++)\r
+ {\r
+ constraintDescriptor = constraintDescriptorList.elementAt(index);\r
+ if (constraintDescriptor instanceof ReferencedKeyConstraintDescriptor)\r
+ dm.invalidateFor(constraintDescriptor, DependencyManager.RENAME, lcc);\r
+ }\r
+\r
+ // Drop the table\r
+ dd.dropTableDescriptor(td, sd, tc);\r
+ // Change the table name of the table descriptor\r
+ td.setTableName(newTableName);\r
+ // add the table descriptor with new name\r
+ dd.addDescriptor(td, sd, DataDictionary.SYSTABLES_CATALOG_NUM,\r
+ false, tc);\r
+ }\r
+\r
+ //do necessary work for rename column at execute time.\r
+ private void execGutsRenameColumn\r
+ (\r
+ TableDescriptor td, Activation activation)\r
+ throws StandardException\r
+ {\r
+ ColumnDescriptor columnDescriptor = null;\r
+ int columnPosition = 0;\r
+ ConstraintDescriptorList constraintDescriptorList;\r
+ ConstraintDescriptor constraintDescriptor;\r
+ LanguageConnectionContext lcc = activation.getLanguageConnectionContext();\r
+ DataDictionary dd = lcc.getDataDictionary();\r
+ DependencyManager dm = dd.getDependencyManager();\r
+ TransactionController tc = lcc.getTransactionExecute();\r
+\r
+ /* get the column descriptor for column to be renamed and\r
+ * using it's position in the table, set the referenced\r
+ * column map of the table indicating which column is being\r
+ * renamed. Dependency Manager uses this to find out the\r
+ * dependents on the column.\r
+ */\r
+ columnDescriptor = td.getColumnDescriptor(oldObjectName);\r
+ columnPosition = columnDescriptor.getPosition();\r
+ FormatableBitSet toRename = new FormatableBitSet(td.getColumnDescriptorList().size() + 1);\r
+ toRename.set(columnPosition);\r
+ td.setReferencedColumnMap(toRename);\r
+ \r
+ dm.invalidateFor(td, DependencyManager.RENAME, lcc);\r
+\r
+ //look for foreign key dependency on the column.\r
+ constraintDescriptorList = dd.getConstraintDescriptors(td);\r
+ for(int index=0; index<constraintDescriptorList.size(); index++)\r
+ {\r
+ constraintDescriptor = constraintDescriptorList.elementAt(index);\r
+ int[] referencedColumns = constraintDescriptor.getReferencedColumns();\r
+ int numRefCols = referencedColumns.length;\r
+ for (int j = 0; j < numRefCols; j++)\r
+ {\r
+ if ((referencedColumns[j] == columnPosition) &&\r
+ (constraintDescriptor instanceof ReferencedKeyConstraintDescriptor))\r
+ dm.invalidateFor(constraintDescriptor, DependencyManager.RENAME, lcc);\r
+ }\r
+ }\r
+\r
+ // Drop the column\r
+ dd.dropColumnDescriptor(td.getUUID(), oldObjectName, tc);\r
+ columnDescriptor.setColumnName(newObjectName);\r
+ dd.addDescriptor(columnDescriptor, td,\r
+ DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);\r
+\r
+ //Need to do following to reload the cache so that table\r
+ //descriptor now has new column name\r
+ td = dd.getTableDescriptor(td.getObjectID());\r
+ }\r
+\r
+ //do necessary work for rename index at execute time.\r
+ private void execGutsRenameIndex\r
+ (\r
+ TableDescriptor td, Activation activation)\r
+ throws StandardException\r
+ {\r
+ LanguageConnectionContext lcc = activation.getLanguageConnectionContext();\r
+ DataDictionary dd = lcc.getDataDictionary();\r
+ DependencyManager dm = dd.getDependencyManager();\r
+ TransactionController tc = lcc.getTransactionExecute();\r
+ //for indexes, we only invalidate sps, rest we ignore(ie views)\r
+ dm.invalidateFor(td, DependencyManager.RENAME_INDEX, lcc);\r
+\r
+ ConglomerateDescriptor conglomerateDescriptor =\r
+ dd.getConglomerateDescriptor(oldObjectName, sd, true);\r
+\r
+ if (conglomerateDescriptor == null)\r
+ throw StandardException.newException(SQLState.LANG_INDEX_NOT_FOUND_DURING_EXECUTION,\r
+ oldObjectName);\r
+\r
+ /* Drop the index descriptor */\r
+ dd.dropConglomerateDescriptor(conglomerateDescriptor, tc);\r
+ // Change the index name of the index descriptor\r
+ conglomerateDescriptor.setConglomerateName(newObjectName);\r
+ // add the index descriptor with new name\r
+ dd.addDescriptor(conglomerateDescriptor, sd,\r
+ DataDictionary.SYSCONGLOMERATES_CATALOG_NUM, false, tc);\r
+ }\r
+\r
+ /* Following is used for error handling by repSourceCompilerUtilities\r
+ * in it's method checkIfRenameDependency */\r
+ public String getTableName() { return tableName; }\r
+\r
+}\r