001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.RenameConstantAction
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.execute;
023:
024: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
025: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
026: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
027: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
028: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
029: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
030: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
031: import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
032: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
033: import org.apache.derby.iapi.store.access.TransactionController;
034:
035: import org.apache.derby.iapi.sql.depend.DependencyManager;
036: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
037:
038: import org.apache.derby.iapi.reference.SQLState;
039:
040: import org.apache.derby.iapi.sql.Activation;
041: import org.apache.derby.iapi.sql.StatementType;
042:
043: import org.apache.derby.iapi.sql.execute.ConstantAction;
044:
045: import org.apache.derby.iapi.error.StandardException;
046:
047: import org.apache.derby.iapi.services.sanity.SanityManager;
048:
049: import org.apache.derby.catalog.UUID;
050:
051: import org.apache.derby.iapi.services.io.FormatableBitSet;
052:
053: /**
054: * This class describes actions that are ALWAYS performed for a
055: * RENAME TABLE/COLUMN/INDEX Statement at Execution time.
056: *
057: * @author Mamta Satoor.
058: */
059:
060: class RenameConstantAction extends DDLSingleTableConstantAction {
061:
062: private String fullTableName;
063: private String tableName;
064: private String newTableName;
065: private String oldObjectName;
066: private String newObjectName;
067: private UUID schemaId;
068: private SchemaDescriptor sd;
069: /* You can rename using either alter table or rename command to
070: * rename a table/column. An index can only be renamed with rename
071: * command. usedAlterTable flag is used to keep that information.
072: */
073: private boolean usedAlterTable;
074: /* renamingWhat will be set to 1 if user is renaming a table.
075: * Will be set to 2 if user is renaming a column and will be
076: * set to 3 if user is renaming an index
077: */
078: private int renamingWhat;
079:
080: // CONSTRUCTORS
081:
082: /**
083: * Make the ConstantAction for a RENAME TABLE/COLUMN/INDEX statement.
084: *
085: * @param fullTableName Fully qualified table name
086: * @param tableName Table name.
087: * @param oldObjectName This is either the name of column/index in case
088: * of rename column/index. For rename table, this is null.
089: * @param newObjectName This is new name for table/column/index
090: * @param sd Schema that table lives in.
091: * @param tableId UUID for table
092: * @param usedAlterTable True-Used Alter Table, False-Used Rename.
093: * For rename index, this will always be false because
094: * there is no alter table command to rename index
095: * @param renamingWhat Rename a 1 - table, 2 - column, 3 - index
096: *
097: */
098: public RenameConstantAction(String fullTableName, String tableName,
099: String oldObjectName, String newObjectName,
100: SchemaDescriptor sd, UUID tableId, boolean usedAlterTable,
101: int renamingWhat) {
102: super (tableId);
103: this .fullTableName = fullTableName;
104: this .tableName = tableName;
105: this .sd = sd;
106: this .usedAlterTable = usedAlterTable;
107: this .renamingWhat = renamingWhat;
108:
109: switch (this .renamingWhat) {
110: case StatementType.RENAME_TABLE:
111: this .newTableName = newObjectName;
112: this .oldObjectName = null;
113: this .newObjectName = newObjectName;
114: break;
115:
116: case StatementType.RENAME_COLUMN:
117: case StatementType.RENAME_INDEX:
118: this .oldObjectName = oldObjectName;
119: this .newObjectName = newObjectName;
120: break;
121:
122: default:
123: if (SanityManager.DEBUG) {
124: SanityManager
125: .THROWASSERT("Unexpected rename action in RenameConstantAction");
126: }
127: }
128: if (SanityManager.DEBUG) {
129: SanityManager
130: .ASSERT(sd != null, "SchemaDescriptor is null");
131: }
132: }
133:
134: // OBJECT METHODS
135:
136: public String toString() {
137: String renameString;
138: if (usedAlterTable)
139: renameString = "ALTER TABLE ";
140: else
141: renameString = "RENAME ";
142:
143: switch (this .renamingWhat) {
144: case StatementType.RENAME_TABLE:
145: if (usedAlterTable)
146: renameString = renameString + fullTableName
147: + " RENAME TO " + newTableName;
148: else
149: renameString = renameString + " TABLE " + fullTableName
150: + " TO " + newTableName;
151: break;
152:
153: case StatementType.RENAME_COLUMN:
154: if (usedAlterTable)
155: renameString = renameString + fullTableName
156: + " RENAME " + oldObjectName + " TO "
157: + newObjectName;
158: else
159: renameString = renameString + " COLUMN "
160: + fullTableName + "." + oldObjectName + " TO "
161: + newObjectName;
162: break;
163:
164: case StatementType.RENAME_INDEX:
165: renameString = renameString + " INDEX " + oldObjectName
166: + " TO " + newObjectName;
167: break;
168:
169: default:
170: if (SanityManager.DEBUG) {
171: SanityManager
172: .THROWASSERT("Unexpected rename action in RenameConstantAction");
173: }
174: break;
175: }
176:
177: return renameString;
178: }
179:
180: // INTERFACE METHODS
181:
182: /**
183: * The guts of the Execution-time logic for RENAME TABLE/COLUMN/INDEX.
184: *
185: * @see ConstantAction#executeConstantAction
186: *
187: * @exception StandardException Thrown on failure
188: */
189: public void executeConstantAction(Activation activation)
190: throws StandardException {
191: TableDescriptor td;
192: UUID tableID;
193:
194: LanguageConnectionContext lcc = activation
195: .getLanguageConnectionContext();
196: DataDictionary dd = lcc.getDataDictionary();
197: DependencyManager dm = dd.getDependencyManager();
198: TransactionController tc = lcc.getTransactionExecute();
199:
200: /*
201: ** Inform the data dictionary that we are about to write to it.
202: ** There are several calls to data dictionary "get" methods here
203: ** that might be done in "read" mode in the data dictionary, but
204: ** it seemed safer to do this whole operation in "write" mode.
205: **
206: ** We tell the data dictionary we're done writing at the end of
207: ** the transaction.
208: */
209: dd.startWriting(lcc);
210:
211: td = dd.getTableDescriptor(tableId);
212:
213: if (td == null) {
214: throw StandardException.newException(
215: SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION,
216: fullTableName);
217: }
218:
219: /*
220: ** If the schema descriptor is null, then
221: ** we must have just read ourselves in.
222: ** So we will get the corresponding schema
223: ** descriptor from the data dictionary.
224: */
225: if (sd == null) {
226: sd = getAndCheckSchemaDescriptor(dd, schemaId,
227: "RENAME TABLE");
228: }
229:
230: long heapId = td.getHeapConglomerateId();
231:
232: /* need to lock table, beetle 4271
233: */
234: lockTableForDDL(tc, heapId, true);
235:
236: /* need to get td again, in case it's changed before lock acquired
237: */
238: td = dd.getTableDescriptor(tableId);
239: if (td == null) {
240: throw StandardException.newException(
241: SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION,
242: fullTableName);
243: }
244:
245: switch (renamingWhat) {
246: case StatementType.RENAME_TABLE:
247: execGutsRenameTable(td, activation);
248: break;
249:
250: case StatementType.RENAME_COLUMN:
251: execGutsRenameColumn(td, activation);
252: break;
253:
254: case StatementType.RENAME_INDEX:
255: execGutsRenameIndex(td, activation);
256: break;
257:
258: default:
259: if (SanityManager.DEBUG) {
260: SanityManager
261: .THROWASSERT("Unexpected rename action in RenameConstantAction");
262: }
263: break;
264: }
265: }
266:
267: //do necessary work for rename table at execute time.
268: private void execGutsRenameTable(TableDescriptor td,
269: Activation activation) throws StandardException {
270: ConstraintDescriptorList constraintDescriptorList;
271: ConstraintDescriptor constraintDescriptor;
272:
273: LanguageConnectionContext lcc = activation
274: .getLanguageConnectionContext();
275: DataDictionary dd = lcc.getDataDictionary();
276: DependencyManager dm = dd.getDependencyManager();
277: TransactionController tc = lcc.getTransactionExecute();
278: dm.invalidateFor(td, DependencyManager.RENAME, lcc);
279:
280: /* look for foreign key dependency on the table. If found any,
281: use dependency manager to pass the rename action to the
282: dependents. */
283: constraintDescriptorList = dd.getConstraintDescriptors(td);
284: for (int index = 0; index < constraintDescriptorList.size(); index++) {
285: constraintDescriptor = constraintDescriptorList
286: .elementAt(index);
287: if (constraintDescriptor instanceof ReferencedKeyConstraintDescriptor)
288: dm.invalidateFor(constraintDescriptor,
289: DependencyManager.RENAME, lcc);
290: }
291:
292: // Drop the table
293: dd.dropTableDescriptor(td, sd, tc);
294: // Change the table name of the table descriptor
295: td.setTableName(newTableName);
296: // add the table descriptor with new name
297: dd.addDescriptor(td, sd, DataDictionary.SYSTABLES_CATALOG_NUM,
298: false, tc);
299: }
300:
301: //do necessary work for rename column at execute time.
302: private void execGutsRenameColumn(TableDescriptor td,
303: Activation activation) throws StandardException {
304: ColumnDescriptor columnDescriptor = null;
305: int columnPosition = 0;
306: ConstraintDescriptorList constraintDescriptorList;
307: ConstraintDescriptor constraintDescriptor;
308: LanguageConnectionContext lcc = activation
309: .getLanguageConnectionContext();
310: DataDictionary dd = lcc.getDataDictionary();
311: DependencyManager dm = dd.getDependencyManager();
312: TransactionController tc = lcc.getTransactionExecute();
313:
314: /* get the column descriptor for column to be renamed and
315: * using it's position in the table, set the referenced
316: * column map of the table indicating which column is being
317: * renamed. Dependency Manager uses this to find out the
318: * dependents on the column.
319: */
320: columnDescriptor = td.getColumnDescriptor(oldObjectName);
321: columnPosition = columnDescriptor.getPosition();
322: FormatableBitSet toRename = new FormatableBitSet(td
323: .getColumnDescriptorList().size() + 1);
324: toRename.set(columnPosition);
325: td.setReferencedColumnMap(toRename);
326:
327: dm.invalidateFor(td, DependencyManager.RENAME, lcc);
328:
329: //look for foreign key dependency on the column.
330: constraintDescriptorList = dd.getConstraintDescriptors(td);
331: for (int index = 0; index < constraintDescriptorList.size(); index++) {
332: constraintDescriptor = constraintDescriptorList
333: .elementAt(index);
334: int[] referencedColumns = constraintDescriptor
335: .getReferencedColumns();
336: int numRefCols = referencedColumns.length;
337: for (int j = 0; j < numRefCols; j++) {
338: if ((referencedColumns[j] == columnPosition)
339: && (constraintDescriptor instanceof ReferencedKeyConstraintDescriptor))
340: dm.invalidateFor(constraintDescriptor,
341: DependencyManager.RENAME, lcc);
342: }
343: }
344:
345: // Drop the column
346: dd.dropColumnDescriptor(td.getUUID(), oldObjectName, tc);
347: columnDescriptor.setColumnName(newObjectName);
348: dd.addDescriptor(columnDescriptor, td,
349: DataDictionary.SYSCOLUMNS_CATALOG_NUM, false, tc);
350:
351: //Need to do following to reload the cache so that table
352: //descriptor now has new column name
353: td = dd.getTableDescriptor(td.getObjectID());
354: }
355:
356: //do necessary work for rename index at execute time.
357: private void execGutsRenameIndex(TableDescriptor td,
358: Activation activation) throws StandardException {
359: LanguageConnectionContext lcc = activation
360: .getLanguageConnectionContext();
361: DataDictionary dd = lcc.getDataDictionary();
362: DependencyManager dm = dd.getDependencyManager();
363: TransactionController tc = lcc.getTransactionExecute();
364: //for indexes, we only invalidate sps, rest we ignore(ie views)
365: dm.invalidateFor(td, DependencyManager.RENAME_INDEX, lcc);
366:
367: ConglomerateDescriptor conglomerateDescriptor = dd
368: .getConglomerateDescriptor(oldObjectName, sd, true);
369:
370: if (conglomerateDescriptor == null)
371: throw StandardException.newException(
372: SQLState.LANG_INDEX_NOT_FOUND_DURING_EXECUTION,
373: oldObjectName);
374:
375: /* Drop the index descriptor */
376: dd.dropConglomerateDescriptor(conglomerateDescriptor, tc);
377: // Change the index name of the index descriptor
378: conglomerateDescriptor.setConglomerateName(newObjectName);
379: // add the index descriptor with new name
380: dd.addDescriptor(conglomerateDescriptor, sd,
381: DataDictionary.SYSCONGLOMERATES_CATALOG_NUM, false, tc);
382: }
383:
384: /* Following is used for error handling by repSourceCompilerUtilities
385: * in it's method checkIfRenameDependency */
386: public String getTableName() {
387: return tableName;
388: }
389:
390: }
|