001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.ReferencedKeyRIChecker
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: import org.apache.derby.iapi.error.StandardException;
026:
027: import org.apache.derby.iapi.sql.StatementUtil;
028: import org.apache.derby.iapi.sql.execute.ExecRow;
029: import org.apache.derby.iapi.sql.execute.ExecIndexRow;
030: import org.apache.derby.iapi.reference.SQLState;
031: import org.apache.derby.iapi.store.access.ScanController;
032: import org.apache.derby.iapi.store.access.TransactionController;
033: import org.apache.derby.iapi.sql.StatementType;
034:
035: /**
036: * A Referential Integrity checker for a change
037: * to a referenced key (primary or unique). Makes
038: * sure that all the referenced key row is not
039: * referenced by any of its foreign keys. see
040: * ForeignKeyRIChecker for the code that validates
041: * changes to foreign keys.
042: */
043: public class ReferencedKeyRIChecker extends GenericRIChecker {
044: /**
045: * @param tc the xact controller
046: * @param fkinfo the foreign key information
047: *
048: * @exception StandardException Thrown on failure
049: */
050: ReferencedKeyRIChecker(TransactionController tc, FKInfo fkinfo)
051: throws StandardException {
052: super (tc, fkinfo);
053:
054: if (SanityManager.DEBUG) {
055: if (fkInfo.type != FKInfo.REFERENCED_KEY) {
056: SanityManager.THROWASSERT("invalid type " + fkInfo.type
057: + " for a ReferencedKeyRIChecker");
058: }
059: }
060: }
061:
062: /**
063: * Check that the row either has a null column(s), or
064: * has no corresponding foreign keys.
065: * <p>
066: * If a foreign key is found, an exception is thrown.
067: * If not, the scan is closed.
068: *
069: * @param row the row to check
070: *
071: * @exception StandardException on unexpected error, or
072: * on a primary/unique key violation
073: */
074: void doCheck(ExecRow row, boolean restrictCheckOnly)
075: throws StandardException {
076: /*
077: ** If any of the columns are null, then the
078: ** check always succeeds.
079: */
080: if (isAnyFieldNull(row)) {
081: return;
082: }
083:
084: /*
085: ** Otherwise, should be no rows found.
086: ** Check each conglomerate.
087: */
088: ScanController scan;
089:
090: for (int i = 0; i < fkInfo.fkConglomNumbers.length; i++) {
091:
092: if (restrictCheckOnly) {
093: if (fkInfo.raRules[i] != StatementType.RA_RESTRICT)
094: continue;
095: }
096:
097: scan = getScanController(fkInfo.fkConglomNumbers[i],
098: fkScocis[i], fkDcocis[i], row);
099: if (scan.next()) {
100: close();
101: StandardException se = StandardException.newException(
102: SQLState.LANG_FK_VIOLATION,
103: fkInfo.fkConstraintNames[i], fkInfo.tableName,
104: StatementUtil.typeName(fkInfo.stmtType),
105: RowUtil.toString(row, fkInfo.colArray));
106:
107: throw se;
108: }
109: /*
110: ** Move off of the current row to release any locks.
111: */
112: scan.next();
113: }
114: }
115: }
|