001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.DropTableConstantAction
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.execute.ConstantAction;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027: import org.apache.derby.iapi.error.StandardException;
028: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
029: import org.apache.derby.iapi.sql.StatementType;
030:
031: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
032: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
033: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
034: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
035: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
036: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
037: import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
038: import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;
039: import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
040: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
041: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
042: import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
043:
044: import org.apache.derby.iapi.sql.depend.DependencyManager;
045:
046: import org.apache.derby.iapi.reference.SQLState;
047:
048: import org.apache.derby.iapi.sql.Activation;
049:
050: import org.apache.derby.iapi.store.access.TransactionController;
051:
052: import org.apache.derby.catalog.UUID;
053:
054: import java.util.Enumeration;
055:
056: /**
057: * This class describes actions that are ALWAYS performed for a
058: * DROP TABLE Statement at Execution time.
059: *
060: * @author Rick Hillegas Extracted code from DropTableResultSet.
061: */
062:
063: class DropTableConstantAction extends DDLSingleTableConstantAction {
064:
065: private final long conglomerateNumber;
066: private final String fullTableName;
067: private final String tableName;
068: private final SchemaDescriptor sd;
069: private final boolean cascade;
070:
071: // CONSTRUCTORS
072:
073: /**
074: * Make the ConstantAction for a DROP TABLE statement.
075: *
076: *
077: * @param fullTableName Fully qualified table name
078: * @param tableName Table name.
079: * @param sd Schema that table lives in.
080: * @param conglomerateNumber Conglomerate number for heap
081: * @param tableId UUID for table
082: * @param behavior drop behavior: RESTRICT, CASCADE or default
083: *
084: */
085: DropTableConstantAction(String fullTableName, String tableName,
086: SchemaDescriptor sd, long conglomerateNumber, UUID tableId,
087: int behavior) {
088: super (tableId);
089: this .fullTableName = fullTableName;
090: this .tableName = tableName;
091: this .sd = sd;
092: this .conglomerateNumber = conglomerateNumber;
093: this .cascade = (behavior == StatementType.DROP_CASCADE);
094:
095: if (SanityManager.DEBUG) {
096: SanityManager
097: .ASSERT(sd != null, "SchemaDescriptor is null");
098: }
099: }
100:
101: // OBJECT METHODS
102:
103: public String toString() {
104: // Do not put this under SanityManager.DEBUG - it is needed for
105: // error reporting.
106: return "DROP TABLE " + fullTableName;
107: }
108:
109: // INTERFACE METHODS
110:
111: /**
112: * This is the guts of the Execution-time logic for DROP TABLE.
113: *
114: * @see ConstantAction#executeConstantAction
115: *
116: * @exception StandardException Thrown on failure
117: */
118: public void executeConstantAction(Activation activation)
119: throws StandardException {
120: TableDescriptor td;
121: UUID tableID;
122: ConglomerateDescriptor[] cds;
123:
124: LanguageConnectionContext lcc = activation
125: .getLanguageConnectionContext();
126: DataDictionary dd = lcc.getDataDictionary();
127: DependencyManager dm = dd.getDependencyManager();
128: TransactionController tc = lcc.getTransactionExecute();
129:
130: if ((sd != null)
131: && sd
132: .getSchemaName()
133: .equals(
134: SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME)) {
135: td = lcc
136: .getTableDescriptorForDeclaredGlobalTempTable(tableName); //check if this is a temp table before checking data dictionary
137:
138: if (td == null) //td null here means it is not a temporary table. Look for table in physical SESSION schema
139: td = dd.getTableDescriptor(tableName, sd);
140:
141: if (td == null) //td null means tableName is not a temp table and it is not a physical table in SESSION schema
142: {
143: throw StandardException.newException(
144: SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION,
145: fullTableName);
146: }
147:
148: if (td.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
149: dm.invalidateFor(td, DependencyManager.DROP_TABLE, lcc);
150: tc.dropConglomerate(td.getHeapConglomerateId());
151: lcc.dropDeclaredGlobalTempTable(tableName);
152: return;
153: }
154: }
155:
156: /* Lock the table before we access the data dictionary
157: * to prevent deadlocks.
158: *
159: * Note that for DROP TABLE replayed at Targets during REFRESH,
160: * the conglomerateNumber will be 0. That's ok. During REFRESH,
161: * we don't need to lock the conglomerate.
162: */
163: if (conglomerateNumber != 0) {
164: lockTableForDDL(tc, conglomerateNumber, true);
165: }
166:
167: /*
168: ** Inform the data dictionary that we are about to write to it.
169: ** There are several calls to data dictionary "get" methods here
170: ** that might be done in "read" mode in the data dictionary, but
171: ** it seemed safer to do this whole operation in "write" mode.
172: **
173: ** We tell the data dictionary we're done writing at the end of
174: ** the transaction.
175: */
176: dd.startWriting(lcc);
177:
178: /* Get the table descriptor. */
179: td = dd.getTableDescriptor(tableId);
180:
181: if (td == null) {
182: throw StandardException.newException(
183: SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION,
184: fullTableName);
185: }
186:
187: /* Get an exclusive table lock on the table. */
188: long heapId = td.getHeapConglomerateId();
189: lockTableForDDL(tc, heapId, true);
190:
191: /* Drop the triggers */
192: GenericDescriptorList tdl = dd.getTriggerDescriptors(td);
193: Enumeration descs = tdl.elements();
194: while (descs.hasMoreElements()) {
195: TriggerDescriptor trd = (TriggerDescriptor) descs
196: .nextElement();
197: DropTriggerConstantAction.dropTriggerDescriptor(lcc, dm,
198: dd, tc, trd, activation);
199: }
200:
201: /* Drop all defaults */
202: ColumnDescriptorList cdl = td.getColumnDescriptorList();
203: int cdlSize = cdl.size();
204:
205: for (int index = 0; index < cdlSize; index++) {
206: ColumnDescriptor cd = (ColumnDescriptor) cdl
207: .elementAt(index);
208:
209: // If column has a default we drop the default and
210: // any dependencies
211: if (cd.getDefaultInfo() != null) {
212: DefaultDescriptor defaultDesc = cd
213: .getDefaultDescriptor(dd);
214: dm.clearDependencies(lcc, defaultDesc);
215: }
216: }
217:
218: /* Drop the columns */
219: dd.dropAllColumnDescriptors(tableId, tc);
220:
221: /* Drop all table and column permission descriptors */
222: dd.dropAllTableAndColPermDescriptors(tableId, tc);
223:
224: /* Drop the constraints */
225: dropAllConstraintDescriptors(td, activation);
226:
227: /*
228: ** Drop all the conglomerates. Drop the heap last, because the
229: ** store needs it for locking the indexes when they are dropped.
230: */
231: cds = td.getConglomerateDescriptors();
232:
233: long[] dropped = new long[cds.length - 1];
234: int numDropped = 0;
235: for (int index = 0; index < cds.length; index++) {
236: ConglomerateDescriptor cd = cds[index];
237:
238: /* if it's for an index, since similar indexes share one
239: * conglomerate, we only drop the conglomerate once
240: */
241: if (cd.getConglomerateNumber() != heapId) {
242: long this Conglom = cd.getConglomerateNumber();
243:
244: int i;
245: for (i = 0; i < numDropped; i++) {
246: if (dropped[i] == this Conglom)
247: break;
248: }
249: if (i == numDropped) // not dropped
250: {
251: dropped[numDropped++] = this Conglom;
252: tc.dropConglomerate(this Conglom);
253: dd.dropStatisticsDescriptors(td.getUUID(), cd
254: .getUUID(), tc);
255: }
256: }
257: }
258:
259: /* Prepare all dependents to invalidate. (This is there chance
260: * to say that they can't be invalidated. For example, an open
261: * cursor referencing a table/view that the user is attempting to
262: * drop.) If no one objects, then invalidate any dependent objects.
263: * We check for invalidation before we drop the table descriptor
264: * since the table descriptor may be looked up as part of
265: * decoding tuples in SYSDEPENDS.
266: */
267:
268: dm.invalidateFor(td, DependencyManager.DROP_TABLE, lcc);
269:
270: /* Drop the table */
271: dd.dropTableDescriptor(td, sd, tc);
272:
273: /* Drop the conglomerate descriptors */
274: dd.dropAllConglomerateDescriptors(td, tc);
275:
276: /* Drop the store element at last, to prevent dangling reference
277: * for open cursor, beetle 4393.
278: */
279: tc.dropConglomerate(heapId);
280:
281: }
282:
283: private void dropAllConstraintDescriptors(TableDescriptor td,
284: Activation activation) throws StandardException {
285: ConstraintDescriptor cd;
286: ConstraintDescriptorList cdl;
287: ConstraintDescriptor fkcd;
288: ConstraintDescriptorList fkcdl;
289: LanguageConnectionContext lcc = activation
290: .getLanguageConnectionContext();
291: DataDictionary dd = lcc.getDataDictionary();
292: DependencyManager dm = dd.getDependencyManager();
293: TransactionController tc = lcc.getTransactionExecute();
294:
295: cdl = dd.getConstraintDescriptors(td);
296:
297: /*
298: ** First go, don't drop unique or primary keys.
299: ** This will ensure that self-referential constraints
300: ** will work ok, even if not cascading.
301: */
302: /* The current element will be deleted underneath
303: * the loop, so we only increment the counter when
304: * skipping an element. (HACK!)
305: */
306: for (int index = 0; index < cdl.size();) {
307: cd = cdl.elementAt(index);
308: if (cd instanceof ReferencedKeyConstraintDescriptor) {
309: index++;
310: continue;
311: }
312:
313: dm
314: .invalidateFor(cd,
315: DependencyManager.DROP_CONSTRAINT, lcc);
316: DropConstraintConstantAction.dropConstraintAndIndex(dm, td,
317: dd, cd, tc, lcc, true);
318: }
319:
320: /*
321: ** Referenced keys (unique or pk) constraints only
322: */
323: /* The current element will be deleted underneath
324: * the loop. (HACK!)
325: */
326: while (cdl.size() > 0) {
327: cd = cdl.elementAt(0);
328: if (SanityManager.DEBUG) {
329: if (!(cd instanceof ReferencedKeyConstraintDescriptor)) {
330: SanityManager
331: .THROWASSERT("Constraint descriptor not an instance of "
332: + "ReferencedKeyConstraintDescriptor as expected. Is a "
333: + cd.getClass().getName());
334: }
335: }
336:
337: /*
338: ** Drop the referenced constraint (after we got
339: ** the primary keys) now. Do this prior to
340: ** droping the referenced keys to avoid performing
341: ** a lot of extra work updating the referencedcount
342: ** field of sys.sysconstraints.
343: **
344: ** Pass in false to dropConstraintsAndIndex so it
345: ** doesn't clear dependencies, we'll do that ourselves.
346: */
347: DropConstraintConstantAction.dropConstraintAndIndex(dm, td,
348: dd, cd, tc, lcc, false);
349:
350: /*
351: ** If we are going to cascade, get all the
352: ** referencing foreign keys and zap them first.
353: */
354: if (cascade) {
355: /*
356: ** Go to the system tables to get the foreign keys
357: ** to be safe
358: */
359:
360: fkcdl = dd.getForeignKeys(cd.getUUID());
361:
362: /*
363: ** For each FK that references this key, drop
364: ** it.
365: */
366: for (int inner = 0; inner < fkcdl.size(); inner++) {
367: fkcd = (ConstraintDescriptor) fkcdl
368: .elementAt(inner);
369: dm.invalidateFor(fkcd,
370: DependencyManager.DROP_CONSTRAINT, lcc);
371: DropConstraintConstantAction
372: .dropConstraintAndIndex(dm, fkcd
373: .getTableDescriptor(), dd, fkcd,
374: tc, lcc, true);
375: activation.addWarning(StandardException.newWarning(
376: SQLState.LANG_CONSTRAINT_DROPPED, fkcd
377: .getConstraintName(), fkcd
378: .getTableDescriptor().getName()));
379: }
380: }
381:
382: /*
383: ** Now that we got rid of the fks (if we were cascading), it is
384: ** ok to do an invalidate for.
385: */
386: dm
387: .invalidateFor(cd,
388: DependencyManager.DROP_CONSTRAINT, lcc);
389: dm.clearDependencies(lcc, cd);
390: }
391: }
392:
393: }
|