001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.DropConstraintConstantAction
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.services.sanity.SanityManager;
025:
026: import org.apache.derby.iapi.services.io.FormatableHashtable;
027:
028: import org.apache.derby.catalog.UUID;
029: import org.apache.derby.iapi.services.uuid.UUIDFactory;
030:
031: import org.apache.derby.iapi.error.StandardException;
032:
033: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
034:
035: import org.apache.derby.iapi.sql.StatementType;
036:
037: import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
038: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
039: import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
040: import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
041: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
042: import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
043: import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
044: import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
045: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
046:
047: import org.apache.derby.iapi.types.DataValueFactory;
048:
049: import org.apache.derby.iapi.sql.depend.DependencyManager;
050:
051: import org.apache.derby.iapi.reference.SQLState;
052:
053: import org.apache.derby.iapi.sql.execute.ConstantAction;
054:
055: import org.apache.derby.iapi.sql.Activation;
056:
057: import org.apache.derby.iapi.store.access.TransactionController;
058:
059: import org.apache.derby.catalog.UUID;
060:
061: /**
062: * This class describes actions that are ALWAYS performed for a
063: * drop constraint at Execution time.
064: *
065: * @version 0.1
066: * @author Jerry Brenner
067: */
068:
069: public class DropConstraintConstantAction extends
070: ConstraintConstantAction {
071:
072: private boolean cascade; // default false
073: private String constraintSchemaName;
074: private int verifyType;
075:
076: // CONSTRUCTORS
077:
078: /**
079: * Make one of these puppies.
080: *
081: * @param constraintName Constraint name.
082: * @param constraintSchemaName the schema that constraint lives in.
083: * @param tableName Table name.
084: * @param tableId UUID of table.
085: * @param tableSchemaName the schema that table lives in.
086: * @param indexAction IndexConstantAction for constraint (if necessary)
087: * @param behavior the drop behavior (e.g. StatementType.DROP_CASCADE)
088: */
089: DropConstraintConstantAction(String constraintName,
090: String constraintSchemaName, String tableName,
091: UUID tableId, String tableSchemaName,
092: IndexConstantAction indexAction, int behavior,
093: int verifyType) {
094: super (constraintName, DataDictionary.DROP_CONSTRAINT,
095: tableName, tableId, tableSchemaName, indexAction);
096:
097: cascade = (behavior == StatementType.DROP_CASCADE);
098: this .constraintSchemaName = constraintSchemaName;
099: this .verifyType = verifyType;
100: }
101:
102: // OBJECT METHODS
103:
104: public String toString() {
105: // Do not put this under SanityManager.DEBUG - it is needed for
106: // error reporting.
107: if (constraintName == null)
108: return "DROP PRIMARY KEY";
109:
110: String ss = constraintSchemaName == null ? schemaName
111: : constraintSchemaName;
112: return "DROP CONSTRAINT " + ss + "." + constraintName;
113: }
114:
115: // INTERFACE METHODS
116:
117: /**
118: * This is the guts of the Execution-time logic for DROP CONSTRAINT.
119: *
120: * @see ConstantAction#executeConstantAction
121: *
122: * @exception StandardException Thrown on failure
123: */
124: public void executeConstantAction(Activation activation)
125: throws StandardException {
126: ConstraintDescriptor conDesc = null;
127: TableDescriptor td;
128: UUID indexId = null;
129: String indexUUIDString;
130:
131: LanguageConnectionContext lcc = activation
132: .getLanguageConnectionContext();
133: DataDictionary dd = lcc.getDataDictionary();
134: DependencyManager dm = dd.getDependencyManager();
135: TransactionController tc = lcc.getTransactionExecute();
136:
137: /*
138: ** Inform the data dictionary that we are about to write to it.
139: ** There are several calls to data dictionary "get" methods here
140: ** that might be done in "read" mode in the data dictionary, but
141: ** it seemed safer to do this whole operation in "write" mode.
142: **
143: ** We tell the data dictionary we're done writing at the end of
144: ** the transaction.
145: */
146: dd.startWriting(lcc);
147:
148: td = dd.getTableDescriptor(tableId);
149:
150: if (td == null) {
151: throw StandardException.newException(
152: SQLState.LANG_TABLE_NOT_FOUND_DURING_EXECUTION,
153: tableName);
154: }
155:
156: /* Table gets locked in AlterTableConstantAction */
157:
158: /*
159: ** If the schema descriptor is null, then
160: ** we must have just read ourselves in.
161: ** So we will get the corresponding schema
162: ** descriptor from the data dictionary.
163: */
164:
165: SchemaDescriptor tdSd = td.getSchemaDescriptor();
166: SchemaDescriptor constraintSd = constraintSchemaName == null ? tdSd
167: : dd
168: .getSchemaDescriptor(constraintSchemaName, tc,
169: true);
170:
171: /* Get the constraint descriptor for the index, along
172: * with an exclusive row lock on the row in sys.sysconstraints
173: * in order to ensure that no one else compiles against the
174: * index.
175: */
176: if (constraintName == null) // this means "alter table drop primary key"
177: conDesc = dd.getConstraintDescriptors(td).getPrimaryKey();
178: else
179: conDesc = dd.getConstraintDescriptorByName(td,
180: constraintSd, constraintName, true);
181:
182: // Error if constraint doesn't exist
183: if (conDesc == null) {
184: String errorName = constraintName == null ? "PRIMARY KEY"
185: : (constraintSd.getSchemaName() + "." + constraintName);
186:
187: throw StandardException.newException(
188: SQLState.LANG_DROP_NON_EXISTENT_CONSTRAINT,
189: errorName, td.getQualifiedName());
190: }
191: switch (verifyType) {
192: case DataDictionary.UNIQUE_CONSTRAINT:
193: if (conDesc.getConstraintType() != verifyType)
194: throw StandardException.newException(
195: SQLState.LANG_DROP_CONSTRAINT_TYPE,
196: constraintName, "UNIQUE");
197: break;
198:
199: case DataDictionary.CHECK_CONSTRAINT:
200: if (conDesc.getConstraintType() != verifyType)
201: throw StandardException.newException(
202: SQLState.LANG_DROP_CONSTRAINT_TYPE,
203: constraintName, "CHECK");
204: break;
205:
206: case DataDictionary.FOREIGNKEY_CONSTRAINT:
207: if (conDesc.getConstraintType() != verifyType)
208: throw StandardException.newException(
209: SQLState.LANG_DROP_CONSTRAINT_TYPE,
210: constraintName, "FOREIGN KEY");
211: break;
212: }
213:
214: boolean cascadeOnRefKey = (cascade && conDesc instanceof ReferencedKeyConstraintDescriptor);
215: if (!cascadeOnRefKey) {
216: dm.invalidateFor(conDesc,
217: DependencyManager.DROP_CONSTRAINT, lcc);
218: }
219:
220: /*
221: ** If we had a primary/unique key and it is drop cascade,
222: ** drop all the referencing keys now. We MUST do this AFTER
223: ** dropping the referenced key because otherwise we would
224: ** be repeatedly changing the reference count of the referenced
225: ** key and generating unnecessary I/O.
226: */
227: dropConstraintAndIndex(dm, td, dd, conDesc, tc, lcc,
228: !cascadeOnRefKey);
229:
230: if (cascadeOnRefKey) {
231: ForeignKeyConstraintDescriptor fkcd;
232: ReferencedKeyConstraintDescriptor cd;
233: ConstraintDescriptorList cdl;
234:
235: cd = (ReferencedKeyConstraintDescriptor) conDesc;
236: cdl = cd
237: .getForeignKeyConstraints(ReferencedKeyConstraintDescriptor.ALL);
238: int cdlSize = cdl.size();
239:
240: for (int index = 0; index < cdlSize; index++) {
241: fkcd = (ForeignKeyConstraintDescriptor) cdl
242: .elementAt(index);
243: dm.invalidateFor(fkcd,
244: DependencyManager.DROP_CONSTRAINT, lcc);
245: dropConstraintAndIndex(dm, fkcd.getTableDescriptor(),
246: dd, fkcd, tc, lcc, true);
247: }
248:
249: /*
250: ** We told dropConstraintAndIndex not to
251: ** remove our dependencies, so send an invalidate,
252: ** and drop the dependencies.
253: */
254: dm.invalidateFor(conDesc,
255: DependencyManager.DROP_CONSTRAINT, lcc);
256: dm.clearDependencies(lcc, conDesc);
257: }
258: }
259:
260: /*
261: * Drop the constraint. Clears dependencies, drops
262: * the backing index and removes the constraint
263: * from the list on the table descriptor. Does NOT
264: * do an dm.invalidateFor()
265: */
266: public static void dropConstraintAndIndex(DependencyManager dm,
267: TableDescriptor td, DataDictionary dd,
268: ConstraintDescriptor conDesc, TransactionController tc,
269: LanguageConnectionContext lcc, boolean clearDependencies)
270: throws StandardException {
271: if (SanityManager.DEBUG) {
272: SanityManager.ASSERT(tc != null, "tc is null");
273: SanityManager.ASSERT(td != null, "td is null");
274: }
275:
276: if (clearDependencies) {
277: dm.clearDependencies(lcc, conDesc);
278: }
279:
280: /* Drop the constraint.
281: * NOTE: This must occur before dropping any backing index, since
282: * a user is not allowed to drop a backing index without dropping
283: * the constraint.
284: */
285: dd.dropConstraintDescriptor(td, conDesc, tc);
286:
287: /* Drop the index, if there's one for this constraint.
288: * NOTE: There will always be an indexAction. We don't
289: * force the constraint to exist at bind time, so we always
290: * generate one.
291: */
292: if (conDesc.hasBackingIndex()) {
293: ConglomerateDescriptor[] conglomDescs;
294:
295: // it may have duplicates, and we drop a backing index
296: // Bug 4307
297: // We need to get the conglomerate descriptors from the
298: // dd in case we dropped other constraints in a cascade operation.
299: conglomDescs = dd.getConglomerateDescriptors(conDesc
300: .getConglomerateId());
301:
302: if (conglomDescs.length != 0) {
303: for (int i = 0; i < conglomDescs.length; i++) {
304: if (conglomDescs[i].isConstraint()) {
305: DropIndexConstantAction.dropIndex(dm, dd, tc,
306: conglomDescs[i], td, lcc);
307: break;
308: }
309: }
310: }
311: }
312:
313: td.removeConstraintDescriptor(conDesc);
314: }
315: }
|