--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.sql.dictionary;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.sql.StatementType;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.catalog.UUID;\r
+/**\r
+ * A ReferencedConstraintDeescriptor is a primary key or a unique\r
+ * key that is referenced by a foreign key.\r
+ *\r
+ */\r
+public class ReferencedKeyConstraintDescriptor extends KeyConstraintDescriptor\r
+{\r
+ /**\r
+ public interface to this descriptor:\r
+ <ol>\r
+ <li>public boolean hasSelfReferencingFK(ConstraintDescriptorList cdl, int type) \r
+ throws StandardException;</li>\r
+ <li>public ConstraintDescriptorList getForeignKeyConstraints(int type) throws StandardException;</li>\r
+ <li>public boolean isReferenced();</li>\r
+ <li>public int getReferenceCount();</li>\r
+ <li>public int incrementReferenceCount();</li>\r
+ <li>public int decrementReferenceCount();</li>\r
+ </ol>\r
+ */\r
+\r
+ //Implementation\r
+ private final int constraintType;\r
+\r
+ int referenceCount;\r
+\r
+ // enabled foreign keys\r
+ private ConstraintDescriptorList fkEnabledConstraintList;\r
+ // all foreign keys\r
+ private ConstraintDescriptorList fkConstraintList;\r
+\r
+ private boolean checkedSelfReferencing;\r
+ private boolean hasSelfReferencing;\r
+\r
+ /**\r
+ * Constructor for a KeyConstraintDescriptorImpl\r
+ *\r
+ * @param constraintType The type of the constraint\r
+ * @param dataDictionary The data dictionary that this descriptor lives in\r
+ * @param table The descriptor of the table the constraint is on\r
+ * @param constraintName The name of the constraint.\r
+ * @param deferrable If the constraint can be deferred.\r
+ * @param initiallyDeferred If the constraint starts life deferred.\r
+ * @param columns columns involved in the constraint\r
+ * @param constraintId UUID of constraint\r
+ * @param indexId The UUID for the backing index\r
+ * @param schemaDesc The SchemaDescriptor for the constraint\r
+ * @param isEnabled is the constraint enabled?\r
+ * @param referenceCount number of FKs (enabled only)\r
+ */\r
+ protected ReferencedKeyConstraintDescriptor(int constraintType,\r
+ DataDictionary dataDictionary,\r
+ TableDescriptor table,\r
+ String constraintName,\r
+ boolean deferrable,\r
+ boolean initiallyDeferred,\r
+ int[] columns,\r
+ UUID constraintId,\r
+ UUID indexId,\r
+ SchemaDescriptor schemaDesc,\r
+ boolean isEnabled,\r
+ int referenceCount\r
+ ) \r
+ {\r
+ super(dataDictionary, table, constraintName, deferrable,\r
+ initiallyDeferred, columns, \r
+ constraintId, indexId, schemaDesc, isEnabled);\r
+ this.referenceCount = referenceCount;\r
+ this.constraintType = constraintType;\r
+ }\r
+\r
+ public final int getConstraintType() {\r
+ return constraintType;\r
+ }\r
+\r
+ /**\r
+ * Am I referenced by a FK on the same table?\r
+ *\r
+ * @param cdl ConstraintDescriptorList for the table\r
+ * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)\r
+ *\r
+ * @return true/false\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public boolean hasSelfReferencingFK(ConstraintDescriptorList cdl, int type) \r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ checkType(type);\r
+ }\r
+ \r
+ if (checkedSelfReferencing)\r
+ {\r
+ return hasSelfReferencing;\r
+ }\r
+ \r
+ ConstraintDescriptor cd;\r
+ ForeignKeyConstraintDescriptor fkcd;\r
+ /* Get a full list of referencing keys, if caller\r
+ * passed in null CDL.\r
+ */\r
+ if (cdl == null)\r
+ {\r
+ cdl = getForeignKeyConstraints(type);\r
+ }\r
+ int cdlSize = cdl.size();\r
+\r
+ for (int index = 0; index < cdlSize; index++)\r
+ {\r
+ cd = (ConstraintDescriptor) cdl.elementAt(index);\r
+ if (! (cd instanceof ForeignKeyConstraintDescriptor))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ fkcd = (ForeignKeyConstraintDescriptor) cd;\r
+ if (fkcd.getReferencedConstraintId().equals(getUUID()))\r
+ {\r
+ hasSelfReferencing = true;\r
+ break;\r
+ }\r
+ }\r
+ return hasSelfReferencing;\r
+ }\r
+\r
+\r
+ /**\r
+ * Am I referenced by a FK on another table?\r
+ * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)\r
+ * @return true/false\r
+ * @exception StandardException on error\r
+ */\r
+ public boolean hasNonSelfReferencingFK(int type) \r
+ throws StandardException\r
+ {\r
+\r
+ boolean hasNonSelfReferenceFk = false;\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ checkType(type);\r
+ }\r
+ \r
+ ConstraintDescriptor cd;\r
+ ForeignKeyConstraintDescriptor fkcd;\r
+ // Get a full list of referencing keys,\r
+ ConstraintDescriptorList cdl = getForeignKeyConstraints(type);\r
+ int cdlSize = cdl.size();\r
+\r
+ for (int index = 0; index < cdlSize; index++)\r
+ {\r
+ cd = (ConstraintDescriptor) cdl.elementAt(index);\r
+ if (! (cd instanceof ForeignKeyConstraintDescriptor))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ fkcd = (ForeignKeyConstraintDescriptor) cd;\r
+ if(!(fkcd.getTableId().equals(getTableId())))\r
+ {\r
+ hasNonSelfReferenceFk = true;\r
+ break;\r
+ }\r
+ }\r
+ return hasNonSelfReferenceFk;\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ * Get the referencing foreign key constraints\r
+ *\r
+ * @param type ConstraintDescriptor.(ENABLED|DISABLED|ALL)\r
+ *\r
+ * @return the list of constraints (ConstraintDescriptorListImpl)\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public ConstraintDescriptorList getForeignKeyConstraints(int type)\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ checkType(type);\r
+ }\r
+\r
+ // optimized for this case\r
+ if (type == ENABLED)\r
+ {\r
+ // optimization to avoid any lookups if we know we\r
+ // aren't referenced.\r
+ if (!isReferenced())\r
+ {\r
+ return new ConstraintDescriptorList();\r
+ }\r
+ else if (fkEnabledConstraintList != null)\r
+ {\r
+ return fkEnabledConstraintList;\r
+ }\r
+ else if (fkConstraintList == null)\r
+ {\r
+ fkConstraintList = getDataDictionary().getForeignKeys(constraintId);\r
+ }\r
+ fkEnabledConstraintList = fkConstraintList.getConstraintDescriptorList(true);\r
+ return fkEnabledConstraintList;\r
+ }\r
+\r
+ // not optimized for this case\r
+ else if (type == DISABLED)\r
+ {\r
+ if (fkConstraintList == null)\r
+ {\r
+ fkConstraintList = getDataDictionary().getForeignKeys(constraintId);\r
+ }\r
+ return fkConstraintList.getConstraintDescriptorList(false);\r
+ }\r
+ else\r
+ {\r
+ if (fkConstraintList == null)\r
+ {\r
+ fkConstraintList = getDataDictionary().getForeignKeys(constraintId);\r
+ }\r
+ return fkConstraintList;\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * Is this constraint referenced? Returns\r
+ * true if there are enabled fks that \r
+ * reference this constraint.\r
+ *\r
+ * @return false\r
+ */\r
+ public boolean isReferenced()\r
+ {\r
+ return referenceCount != 0;\r
+ }\r
+\r
+ /**\r
+ * Get the number of enabled fks that\r
+ * reference this key.\r
+ *\r
+ * @return the number of fks\r
+ */\r
+ public int getReferenceCount()\r
+ {\r
+ return referenceCount;\r
+ }\r
+\r
+ /**\r
+ * Bump the reference count by one.\r
+ *\r
+ * @return the number of fks\r
+ */\r
+ public int incrementReferenceCount()\r
+ {\r
+ return referenceCount++;\r
+ }\r
+\r
+ /**\r
+ * Decrement the reference count by one.\r
+ *\r
+ * @return the number of fks\r
+ */\r
+ public int decrementReferenceCount()\r
+ {\r
+ return referenceCount--;\r
+ }\r
+\r
+ /**\r
+ * Does this constraint need to fire on this type of\r
+ * DML? For referenced keys, fire if referenced by\r
+ * a fk, and stmt is delete or bulk insert replace, \r
+ * or stmt is update and columns intersect.\r
+ *\r
+ * @param stmtType the type of DML \r
+ * (StatementType.INSERT|StatementType.UPDATE|StatementType.DELETE)\r
+ * @param modifiedCols the columns modified, or null for all\r
+ *\r
+ * @return true/false\r
+ */\r
+ public boolean needsToFire(int stmtType, int[] modifiedCols)\r
+ {\r
+ /*\r
+ ** If we are disabled, we never fire\r
+ */\r
+ if (!isEnabled)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ if (!isReferenced() ||\r
+ (stmtType == StatementType.INSERT))\r
+ {\r
+ return false;\r
+ }\r
+\r
+ if (stmtType == StatementType.DELETE ||\r
+ stmtType == StatementType.BULK_INSERT_REPLACE)\r
+ {\r
+ return true;\r
+ }\r
+\r
+ // if update, only relevant if columns intersect\r
+ return doColumnsIntersect(modifiedCols, getReferencedColumns());\r
+ }\r
+\r
+ private void checkType(int type) throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ switch (type)\r
+ {\r
+ case ENABLED:\r
+ case DISABLED:\r
+ case ALL:\r
+ break;\r
+ default:\r
+ SanityManager.THROWASSERT("constraint type "+type+" is invalid");\r
+ }\r
+ }\r
+ }\r
+ \r
+}\r