001: /*
002:
003: Derby - Class org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor
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.iapi.sql.dictionary;
023:
024: import org.apache.derby.iapi.error.StandardException;
025:
026: import org.apache.derby.iapi.reference.SQLState;
027: import org.apache.derby.iapi.services.sanity.SanityManager;
028: import org.apache.derby.iapi.sql.StatementType;
029: import org.apache.derby.iapi.services.io.StoredFormatIds;
030: import org.apache.derby.catalog.UUID;
031:
032: /**
033: * A ReferencedConstraintDeescriptor is a primary key or a unique
034: * key that is referenced by a foreign key.
035: *
036: * @author Jamie
037: */
038: public class ReferencedKeyConstraintDescriptor extends
039: KeyConstraintDescriptor {
040: /**
041: public interface to this descriptor:
042: <ol>
043: <li>public boolean hasSelfReferencingFK(ConstraintDescriptorList cdl, int type)
044: throws StandardException;</li>
045: <li>public ConstraintDescriptorList getForeignKeyConstraints(int type) throws StandardException;</li>
046: <li>public boolean isReferenced();</li>
047: <li>public int getReferenceCount();</li>
048: <li>public int incrementReferenceCount();</li>
049: <li>public int decrementReferenceCount();</li>
050: </ol>
051: */
052:
053: //Implementation
054: private final int constraintType;
055:
056: int referenceCount;
057:
058: // enabled foreign keys
059: private ConstraintDescriptorList fkEnabledConstraintList;
060: // all foreign keys
061: private ConstraintDescriptorList fkConstraintList;
062:
063: private boolean checkedSelfReferencing;
064: private boolean hasSelfReferencing;
065:
066: /**
067: * Constructor for a KeyConstraintDescriptorImpl
068: *
069: * @param constraintType The type of the constraint
070: * @param dataDictionary The data dictionary that this descriptor lives in
071: * @param table The descriptor of the table the constraint is on
072: * @param constraintName The name of the constraint.
073: * @param deferrable If the constraint can be deferred.
074: * @param initiallyDeferred If the constraint starts life deferred.
075: * @param columns columns involved in the constraint
076: * @param constraintId UUID of constraint
077: * @param indexId The UUID for the backing index
078: * @param schemaDesc The SchemaDescriptor for the constraint
079: * @param isEnabled is the constraint enabled?
080: * @param referenceCount number of FKs (enabled only)
081: */
082: protected ReferencedKeyConstraintDescriptor(int constraintType,
083: DataDictionary dataDictionary, TableDescriptor table,
084: String constraintName, boolean deferrable,
085: boolean initiallyDeferred, int[] columns,
086: UUID constraintId, UUID indexId,
087: SchemaDescriptor schemaDesc, boolean isEnabled,
088: int referenceCount) {
089: super (dataDictionary, table, constraintName, deferrable,
090: initiallyDeferred, columns, constraintId, indexId,
091: schemaDesc, isEnabled);
092: this .referenceCount = referenceCount;
093: this .constraintType = constraintType;
094: }
095:
096: public final int getConstraintType() {
097: return constraintType;
098: }
099:
100: /**
101: * Am I referenced by a FK on the same table?
102: *
103: * @param cdl ConstraintDescriptorList for the table
104: * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)
105: *
106: * @return true/false
107: *
108: * @exception StandardException on error
109: */
110: public boolean hasSelfReferencingFK(ConstraintDescriptorList cdl,
111: int type) throws StandardException {
112: if (SanityManager.DEBUG) {
113: checkType(type);
114: }
115:
116: if (checkedSelfReferencing) {
117: return hasSelfReferencing;
118: }
119:
120: ConstraintDescriptor cd;
121: ForeignKeyConstraintDescriptor fkcd;
122: /* Get a full list of referencing keys, if caller
123: * passed in null CDL.
124: */
125: if (cdl == null) {
126: cdl = getForeignKeyConstraints(type);
127: }
128: int cdlSize = cdl.size();
129:
130: for (int index = 0; index < cdlSize; index++) {
131: cd = (ConstraintDescriptor) cdl.elementAt(index);
132: if (!(cd instanceof ForeignKeyConstraintDescriptor)) {
133: continue;
134: }
135:
136: fkcd = (ForeignKeyConstraintDescriptor) cd;
137: if (fkcd.getReferencedConstraintId().equals(getUUID())) {
138: hasSelfReferencing = true;
139: break;
140: }
141: }
142: return hasSelfReferencing;
143: }
144:
145: /**
146: * Am I referenced by a FK on another table?
147: * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)
148: * @return true/false
149: * @exception StandardException on error
150: */
151: public boolean hasNonSelfReferencingFK(int type)
152: throws StandardException {
153:
154: boolean hasNonSelfReferenceFk = false;
155:
156: if (SanityManager.DEBUG) {
157: checkType(type);
158: }
159:
160: ConstraintDescriptor cd;
161: ForeignKeyConstraintDescriptor fkcd;
162: // Get a full list of referencing keys,
163: ConstraintDescriptorList cdl = getForeignKeyConstraints(type);
164: int cdlSize = cdl.size();
165:
166: for (int index = 0; index < cdlSize; index++) {
167: cd = (ConstraintDescriptor) cdl.elementAt(index);
168: if (!(cd instanceof ForeignKeyConstraintDescriptor)) {
169: continue;
170: }
171:
172: fkcd = (ForeignKeyConstraintDescriptor) cd;
173: if (!(fkcd.getTableId().equals(getTableId()))) {
174: hasNonSelfReferenceFk = true;
175: break;
176: }
177: }
178: return hasNonSelfReferenceFk;
179: }
180:
181: /**
182: * Get the referencing foreign key constraints
183: *
184: * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)
185: *
186: * @return the list of constraints (ConstraintDescriptorListImpl)
187: *
188: * @exception StandardException on error
189: */
190: public ConstraintDescriptorList getForeignKeyConstraints(int type)
191: throws StandardException {
192: if (SanityManager.DEBUG) {
193: checkType(type);
194: }
195:
196: // optimized for this case
197: if (type == ENABLED) {
198: // optimization to avoid any lookups if we know we
199: // aren't referenced.
200: if (!isReferenced()) {
201: return new ConstraintDescriptorList();
202: } else if (fkEnabledConstraintList != null) {
203: return fkEnabledConstraintList;
204: } else if (fkConstraintList == null) {
205: fkConstraintList = getDataDictionary().getForeignKeys(
206: constraintId);
207: }
208: fkEnabledConstraintList = fkConstraintList
209: .getConstraintDescriptorList(true);
210: return fkEnabledConstraintList;
211: }
212:
213: // not optimized for this case
214: else if (type == DISABLED) {
215: if (fkConstraintList == null) {
216: fkConstraintList = getDataDictionary().getForeignKeys(
217: constraintId);
218: }
219: return fkConstraintList.getConstraintDescriptorList(false);
220: } else {
221: if (fkConstraintList == null) {
222: fkConstraintList = getDataDictionary().getForeignKeys(
223: constraintId);
224: }
225: return fkConstraintList;
226: }
227: }
228:
229: /**
230: * Is this constraint referenced? Returns
231: * true if there are enabled fks that
232: * reference this constraint.
233: *
234: * @return false
235: */
236: public boolean isReferenced() {
237: return referenceCount != 0;
238: }
239:
240: /**
241: * Get the number of enabled fks that
242: * reference this key.
243: *
244: * @return the number of fks
245: */
246: public int getReferenceCount() {
247: return referenceCount;
248: }
249:
250: /**
251: * Bump the reference count by one.
252: *
253: * @return the number of fks
254: */
255: public int incrementReferenceCount() {
256: return referenceCount++;
257: }
258:
259: /**
260: * Decrement the reference count by one.
261: *
262: * @return the number of fks
263: */
264: public int decrementReferenceCount() {
265: return referenceCount--;
266: }
267:
268: /**
269: * Does this constraint need to fire on this type of
270: * DML? For referenced keys, fire if referenced by
271: * a fk, and stmt is delete or bulk insert replace,
272: * or stmt is update and columns intersect.
273: *
274: * @param stmtType the type of DML
275: * (StatementType.INSERT|StatementType.UPDATE|StatementType.DELETE)
276: * @param modifiedCols the columns modified, or null for all
277: *
278: * @return true/false
279: */
280: public boolean needsToFire(int stmtType, int[] modifiedCols) {
281: /*
282: ** If we are disabled, we never fire
283: */
284: if (!isEnabled) {
285: return false;
286: }
287:
288: if (!isReferenced() || (stmtType == StatementType.INSERT)) {
289: return false;
290: }
291:
292: if (stmtType == StatementType.DELETE
293: || stmtType == StatementType.BULK_INSERT_REPLACE) {
294: return true;
295: }
296:
297: // if update, only relevant if columns intersect
298: return doColumnsIntersect(modifiedCols, getReferencedColumns());
299: }
300:
301: private void checkType(int type) throws StandardException {
302: if (SanityManager.DEBUG) {
303: switch (type) {
304: case ENABLED:
305: case DISABLED:
306: case ALL:
307: break;
308: default:
309: SanityManager.THROWASSERT("constraint type " + type
310: + " is invalid");
311: }
312: }
313: }
314:
315: }
|