001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.execute.ForeignKeyRIChecker
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:
034: /**
035: * A Referential Integrity checker for a foreign
036: * key constraint. It makes sure the foreign key is
037: * intact. This is used for a change to a foreign
038: * key column. see ReferencedKeyRIChecker for the code
039: * that validates changes to referenced keys.
040: */
041: public class ForeignKeyRIChecker extends GenericRIChecker {
042: /**
043: * @param tc the xact controller
044: * @param fkinfo the foreign key information
045: *
046: * @exception StandardException Thrown on failure
047: */
048: ForeignKeyRIChecker(TransactionController tc, FKInfo fkinfo)
049: throws StandardException {
050: super (tc, fkinfo);
051:
052: if (SanityManager.DEBUG) {
053: if (fkInfo.type != FKInfo.FOREIGN_KEY) {
054: SanityManager.THROWASSERT("invalid type " + fkInfo.type
055: + " for a ForeignKeyRIChecker");
056: }
057: }
058: }
059:
060: /**
061: * Check that the row either has a null column(s), or
062: * corresponds to a row in the referenced key.
063: * <p>
064: * If the referenced key is found, then it is locked
065: * when this method returns. The lock is held until
066: * the next call to doCheck() or close().
067: *
068: * @param row the row to check
069: *
070: * @exception StandardException on unexped error, or
071: * on a foreign key violation
072: */
073: void doCheck(ExecRow row, boolean restrictCheckOnly)
074: throws StandardException {
075:
076: if (restrictCheckOnly) //RESTRICT rule checks are not valid here.
077: return;
078:
079: /*
080: ** If any of the columns are null, then the
081: ** check always succeeds.
082: */
083: if (isAnyFieldNull(row)) {
084: return;
085: }
086:
087: /*
088: ** Otherwise, we had better find this row in the
089: ** referenced key
090: */
091: ScanController scan = getScanController(
092: fkInfo.refConglomNumber, refScoci, refDcoci, row);
093: if (!scan.next()) {
094: close();
095: StandardException se = StandardException.newException(
096: SQLState.LANG_FK_VIOLATION,
097: fkInfo.fkConstraintNames[0], fkInfo.tableName,
098: StatementUtil.typeName(fkInfo.stmtType), RowUtil
099: .toString(row, fkInfo.colArray));
100:
101: throw se;
102: }
103:
104: /*
105: ** If we found the row, we are currently positioned on
106: ** the row when we leave this method. So we hold the
107: ** lock on the referenced key, which is very important.
108: */
109: }
110:
111: /**
112: * Get the isolation level for the scan for
113: * the RI check.
114: *
115: * NOTE: The level will eventually be instantaneous
116: * locking once the implemenation changes.
117: *
118: * @return The isolation level for the scan for
119: * the RI check.
120: */
121: int getRICheckIsolationLevel() {
122: return TransactionController.ISOLATION_READ_COMMITTED;
123: }
124: }
|