KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > sql > execute > DropTableConstantAction


1 /*
2
3    Derby - Class org.apache.derby.impl.sql.execute.DropTableConstantAction
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.sql.execute;
23
24 import org.apache.derby.iapi.sql.execute.ConstantAction;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.error.StandardException;
28 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
29 import org.apache.derby.iapi.sql.StatementType;
30
31 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
32 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
33 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
34 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
35 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
36 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
37 import org.apache.derby.iapi.sql.dictionary.DefaultDescriptor;
38 import org.apache.derby.iapi.sql.dictionary.GenericDescriptorList;
39 import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
40 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
41 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
42 import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
43
44 import org.apache.derby.iapi.sql.depend.DependencyManager;
45
46 import org.apache.derby.iapi.reference.SQLState;
47
48 import org.apache.derby.iapi.sql.Activation;
49
50 import org.apache.derby.iapi.store.access.TransactionController;
51
52 import org.apache.derby.catalog.UUID;
53
54 import java.util.Enumeration JavaDoc;
55
56 /**
57  * This class describes actions that are ALWAYS performed for a
58  * DROP TABLE Statement at Execution time.
59  *
60  * @author Rick Hillegas Extracted code from DropTableResultSet.
61  */

62
63 class DropTableConstantAction extends DDLSingleTableConstantAction
64 {
65
66     private final long conglomerateNumber;
67     private final String JavaDoc fullTableName;
68     private final String JavaDoc tableName;
69     private final SchemaDescriptor sd;
70     private final boolean cascade;
71
72     // CONSTRUCTORS
73

74
75     /**
76      * Make the ConstantAction for a DROP TABLE statement.
77      *
78      *
79      * @param fullTableName Fully qualified table name
80      * @param tableName Table name.
81      * @param sd Schema that table lives in.
82      * @param conglomerateNumber Conglomerate number for heap
83      * @param tableId UUID for table
84      * @param behavior drop behavior: RESTRICT, CASCADE or default
85      *
86      */

87     DropTableConstantAction(
88                                 String JavaDoc fullTableName,
89                                 String JavaDoc tableName,
90                                 SchemaDescriptor sd,
91                                 long conglomerateNumber,
92                                 UUID tableId,
93                                 int behavior)
94     {
95         super(tableId);
96         this.fullTableName = fullTableName;
97         this.tableName = tableName;
98         this.sd = sd;
99         this.conglomerateNumber = conglomerateNumber;
100         this.cascade = (behavior == StatementType.DROP_CASCADE);
101
102         if (SanityManager.DEBUG)
103         {
104             SanityManager.ASSERT(sd != null, "SchemaDescriptor is null");
105         }
106     }
107
108     // OBJECT METHODS
109

110     public String JavaDoc toString()
111     {
112         // Do not put this under SanityManager.DEBUG - it is needed for
113
// error reporting.
114
return "DROP TABLE " + fullTableName;
115     }
116
117     // INTERFACE METHODS
118

119
120     /**
121      * This is the guts of the Execution-time logic for DROP TABLE.
122      *
123      * @see ConstantAction#executeConstantAction
124      *
125      * @exception StandardException Thrown on failure
126      */

127     public void executeConstantAction( Activation activation )
128                         throws StandardException
129     {
130         TableDescriptor td;
131         UUID tableID;
132         ConglomerateDescriptor[] cds;
133
134         LanguageConnectionContext lcc = activation.getLanguageConnectionContext();
135         DataDictionary dd = lcc.getDataDictionary();
136         DependencyManager dm = dd.getDependencyManager();
137         TransactionController tc = lcc.getTransactionExecute();
138
139         if ((sd != null) && sd.getSchemaName().equals(SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME)) {
140             td = lcc.getTableDescriptorForDeclaredGlobalTempTable(tableName); //check if this is a temp table before checking data dictionary
141

142             if (td == null) //td null here means it is not a temporary table. Look for table in physical SESSION schema
143
td = dd.getTableDescriptor(tableName, sd);
144
145             if (td == null) //td null means tableName is not a temp table and it is not a physical table in SESSION schema
146
{
147                 throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, fullTableName);
148             }
149
150             if (td.getTableType() == TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE) {
151                 dm.invalidateFor(td, DependencyManager.DROP_TABLE, lcc);
152                 tc.dropConglomerate(td.getHeapConglomerateId());
153                 lcc.dropDeclaredGlobalTempTable(tableName);
154                 return;
155             }
156     }
157
158         /* Lock the table before we access the data dictionary
159          * to prevent deadlocks.
160          *
161          * Note that for DROP TABLE replayed at Targets during REFRESH,
162          * the conglomerateNumber will be 0. That's ok. During REFRESH,
163          * we don't need to lock the conglomerate.
164          */

165         if ( conglomerateNumber != 0 ) { lockTableForDDL(tc, conglomerateNumber, true); }
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         {
183             throw StandardException.newException(SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION, fullTableName);
184         }
185
186         /* Get an exclusive table lock on the table. */
187         long heapId = td.getHeapConglomerateId();
188         lockTableForDDL(tc, heapId, true);
189
190         /* Drop the triggers */
191         GenericDescriptorList tdl = dd.getTriggerDescriptors(td);
192         Enumeration JavaDoc descs = tdl.elements();
193         while (descs.hasMoreElements())
194         {
195             TriggerDescriptor trd = (TriggerDescriptor) descs.nextElement();
196             DropTriggerConstantAction.dropTriggerDescriptor(lcc, dm, dd, tc, trd, activation);
197         }
198
199         /* Drop all defaults */
200         ColumnDescriptorList cdl = td.getColumnDescriptorList();
201         int cdlSize = cdl.size();
202         
203         for (int index = 0; index < cdlSize; index++)
204         {
205             ColumnDescriptor cd = (ColumnDescriptor) cdl.elementAt(index);
206
207             // If column has a default we drop the default and
208
// any dependencies
209
if (cd.getDefaultInfo() != null)
210             {
211                 DefaultDescriptor defaultDesc = cd.getDefaultDescriptor(dd);
212                 dm.clearDependencies(lcc, defaultDesc);
213             }
214         }
215
216         /* Drop the columns */
217         dd.dropAllColumnDescriptors(tableId, tc);
218
219         /* Drop all table and column permission descriptors */
220         dd.dropAllTableAndColPermDescriptors(tableId, tc);
221
222         /* Drop the constraints */
223         dropAllConstraintDescriptors(td, activation);
224
225         /*
226         ** Drop all the conglomerates. Drop the heap last, because the
227         ** store needs it for locking the indexes when they are dropped.
228         */

229         cds = td.getConglomerateDescriptors();
230
231         long[] dropped = new long[cds.length - 1];
232         int numDropped = 0;
233         for (int index = 0; index < cds.length; index++)
234         {
235             ConglomerateDescriptor cd = cds[index];
236
237             /* if it's for an index, since similar indexes share one
238              * conglomerate, we only drop the conglomerate once
239              */

240             if (cd.getConglomerateNumber() != heapId)
241             {
242                 long thisConglom = cd.getConglomerateNumber();
243
244                 int i;
245                 for (i = 0; i < numDropped; i++)
246                 {
247                     if (dropped[i] == thisConglom)
248                         break;
249                 }
250                 if (i == numDropped) // not dropped
251
{
252                     dropped[numDropped++] = thisConglom;
253                     tc.dropConglomerate(thisConglom);
254                     dd.dropStatisticsDescriptors(td.getUUID(), cd.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, Activation activation)
284         throws StandardException
285     {
286         ConstraintDescriptor cd;
287         ConstraintDescriptorList cdl;
288         ConstraintDescriptor fkcd;
289         ConstraintDescriptorList fkcdl;
290         LanguageConnectionContext lcc = activation.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         {
308             cd = cdl.elementAt(index);
309             if (cd instanceof ReferencedKeyConstraintDescriptor)
310             {
311                 index++;
312                 continue;
313             }
314
315             dm.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
316             DropConstraintConstantAction.dropConstraintAndIndex(dm, td, dd, cd,
317                         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         {
328             cd = cdl.elementAt(0);
329             if (SanityManager.DEBUG)
330             {
331                 if (!(cd instanceof ReferencedKeyConstraintDescriptor))
332                 {
333                     SanityManager.THROWASSERT("Constraint descriptor not an instance of " +
334                     "ReferencedKeyConstraintDescriptor as expected. Is a "+ cd.getClass().getName());
335                 }
336             }
337
338             /*
339             ** Drop the referenced constraint (after we got
340             ** the primary keys) now. Do this prior to
341             ** droping the referenced keys to avoid performing
342             ** a lot of extra work updating the referencedcount
343             ** field of sys.sysconstraints.
344             **
345             ** Pass in false to dropConstraintsAndIndex so it
346             ** doesn't clear dependencies, we'll do that ourselves.
347             */

348             DropConstraintConstantAction.dropConstraintAndIndex(dm, td, dd, cd,
349                         tc, lcc, false);
350
351             /*
352             ** If we are going to cascade, get all the
353             ** referencing foreign keys and zap them first.
354             */

355             if (cascade)
356             {
357                 /*
358                 ** Go to the system tables to get the foreign keys
359                 ** to be safe
360                 */

361
362                 fkcdl = dd.getForeignKeys(cd.getUUID());
363
364                 /*
365                 ** For each FK that references this key, drop
366                 ** it.
367                 */

368                 for(int inner = 0; inner < fkcdl.size(); inner++)
369                 {
370                     fkcd = (ConstraintDescriptor) fkcdl.elementAt(inner);
371                     dm.invalidateFor(fkcd, DependencyManager.DROP_CONSTRAINT, lcc);
372                     DropConstraintConstantAction.dropConstraintAndIndex(
373                             dm, fkcd.getTableDescriptor(), dd, fkcd,
374                             tc, lcc, true);
375                     activation.addWarning(
376                         StandardException.newWarning(SQLState.LANG_CONSTRAINT_DROPPED,
377                             fkcd.getConstraintName(),
378                             fkcd.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.invalidateFor(cd, DependencyManager.DROP_CONSTRAINT, lcc);
387             dm.clearDependencies(lcc, cd);
388         }
389     }
390
391 }
392
Popular Tags