📄 constraint.java
字号:
* Returns true if an index is part this constraint and the constraint is set for
* a unique constraint. Used for tests before dropping an index.
*/
boolean isIndexUnique(Index index) {
return (constType == UNIQUE && core.mainIndex == index);
}
/**
* Only for check constraints
*/
boolean hasColumn(Table table, String colname) {
if (constType != CHECK) {
return false;
}
Expression.Collector coll = new Expression.Collector();
coll.addAll(core.check, Expression.COLUMN);
Iterator it = coll.iterator();
for (; it.hasNext(); ) {
Expression e = (Expression) it.next();
if (e.getColumnName().equals(colname)
&& table.tableName.name.equals(e.getTableName())) {
return true;
}
}
return false;
}
boolean hasColumn(int colIndex) {
if (constType == MAIN) {
return ArrayUtil.find(core.mainColArray, colIndex) != -1;
} else if (constType == FOREIGN_KEY) {
return ArrayUtil.find(core.refColArray, colIndex) != -1;
}
return false;
}
// fredt@users 20020225 - patch 1.7.0 by fredt - duplicate constraints
/**
* Compares this with another constraint column set. This implementation
* only checks UNIQUE constraints.
*/
boolean isEquivalent(int[] col, int type) {
if (type != constType || constType != UNIQUE
|| core.colLen != col.length) {
return false;
}
return ArrayUtil.haveEqualSets(core.mainColArray, col, core.colLen);
}
/**
* Compares this with another constraint column set. This implementation
* only checks FOREIGN KEY constraints.
*/
boolean isEquivalent(Table tablemain, int[] colmain, Table tableref,
int[] colref) {
if (constType != Constraint.MAIN
&& constType != Constraint.FOREIGN_KEY) {
return false;
}
if (tablemain != core.mainTable || tableref != core.refTable) {
return false;
}
return ArrayUtil.areEqualSets(core.mainColArray, colmain)
&& ArrayUtil.areEqualSets(core.refColArray, colref);
}
/**
* Used to update constrains to reflect structural changes in a table.
* Prior checks must ensure that this method does not throw.
*
* @param oldt reference to the old version of the table
* @param newt referenct to the new version of the table
* @param colindex index at which table column is added or removed
* @param adjust -1, 0, +1 to indicate if column is added or removed
* @throws HsqlException
*/
void replaceTable(Table oldt, Table newt, int colindex,
int adjust) throws HsqlException {
if (oldt == core.mainTable) {
core.mainTable = newt;
// exclude CHECK
if (core.mainIndex != null) {
core.mainIndex =
core.mainTable.getIndex(core.mainIndex.getName().name);
core.mainColArray =
ArrayUtil.toAdjustedColumnArray(core.mainColArray,
colindex, adjust);
}
}
if (oldt == core.refTable) {
core.refTable = newt;
if (core.refIndex != null) {
core.refIndex =
core.refTable.getIndex(core.refIndex.getName().name);
if (core.refIndex != core.mainIndex) {
core.refColArray =
ArrayUtil.toAdjustedColumnArray(core.refColArray,
colindex, adjust);
}
}
}
}
/**
* Checks for foreign key or check constraint violation when
* inserting a row into the child table.
*/
void checkInsert(Session session, Object[] row) throws HsqlException {
if (constType == Constraint.MAIN || constType == Constraint.UNIQUE
|| constType == Constraint.PRIMARY_KEY) {
// inserts in the main table are never a problem
// unique constraints are checked by the unique index
return;
}
if (constType == Constraint.CHECK) {
checkCheckConstraint(session, row);
return;
}
if (Index.isNull(row, core.refColArray)) {
return;
}
// a record must exist in the main table
boolean exists = core.mainIndex.exists(session, row,
core.refColArray);
if (!exists) {
// special case: self referencing table and self referencing row
if (core.mainTable == core.refTable) {
boolean match = true;
for (int i = 0; i < core.colLen; i++) {
if (!row[core.refColArray[i]].equals(
row[core.mainColArray[i]])) {
match = false;
break;
}
}
if (match) {
return;
}
}
throw Trace.error(Trace.INTEGRITY_CONSTRAINT_VIOLATION_NOPARENT,
Trace.Constraint_violation, new Object[] {
core.fkName.name, core.mainTable.getName().name
});
}
}
/*
* Tests a row against this CHECK constraint.
*/
void checkCheckConstraint(Session session,
Object[] row) throws HsqlException {
core.checkFilter.currentData = row;
boolean nomatch = Boolean.FALSE.equals(core.check.test(session));
core.checkFilter.currentData = null;
if (nomatch) {
throw Trace.error(Trace.CHECK_CONSTRAINT_VIOLATION,
Trace.Constraint_violation, new Object[] {
constName.name, core.mainTable.tableName.name
});
}
}
// fredt@users 20020225 - patch 1.7.0 - cascading deletes
/**
* New method to find any referencing row for a
* foreign key (finds row in child table). If ON DELETE CASCADE is
* supported by this constraint, then the method finds the first row
* among the rows of the table ordered by the index and doesn't throw.
* Without ON DELETE CASCADE, the method attempts to finds any row that
* exists, in which case it throws an exception. If no row is found,
* null is returned.
* (fredt@users)
*
* @param row array of objects for a database row
* @param forDelete should we allow 'ON DELETE CASCADE' or 'ON UPDATE CASCADE'
* @return Node object or null
* @throws HsqlException
*/
RowIterator findFkRef(Session session, Object[] row,
boolean delete) throws HsqlException {
if (row == null || Index.isNull(row, core.mainColArray)) {
return core.refIndex.emptyIterator();
}
return delete
? core.refIndex.findFirstRowForDelete(session, row,
core.mainColArray)
: core.refIndex.findFirstRow(session, row, core.mainColArray);
}
/**
* For the candidate table row, finds any referring node in the main table.
* This is used to check referential integrity when updating a node. We
* have to make sure that the main table still holds a valid main record.
* If a valid row is found the corresponding <code>Node</code> is returned.
* Otherwise a 'INTEGRITY VIOLATION' Exception gets thrown.
*/
boolean hasMainRef(Session session, Object[] row) throws HsqlException {
if (Index.isNull(row, core.refColArray)) {
return false;
}
boolean exists = core.mainIndex.exists(session, row,
core.refColArray);
// -- there has to be a valid node in the main table
// --
if (!exists) {
throw Trace.error(Trace.INTEGRITY_CONSTRAINT_VIOLATION_NOPARENT,
Trace.Constraint_violation, new Object[] {
core.fkName.name, core.refTable.getName().name
});
}
return exists;
}
/**
* Test used before adding a new foreign key constraint. This method
* returns true if the given row has a corresponding row in the main
* table. Also returns true if any column covered by the foreign key
* constraint has a null value.
*/
private static boolean hasReferencedRow(Session session,
Object[] rowdata, int[] rowColArray,
Index mainIndex) throws HsqlException {
if (Index.isNull(rowdata, rowColArray)) {
return true;
}
// else a record must exist in the main index
return mainIndex.exists(session, rowdata, rowColArray);
}
/**
* Check used before creating a new foreign key cosntraint, this method
* checks all rows of a table to ensure they all have a corresponding
* row in the main table.
*/
static void checkReferencedRows(Session session, Table table,
int[] rowColArray,
Index mainIndex) throws HsqlException {
RowIterator it = table.getPrimaryIndex().firstRow(session);
while (true) {
Row row = it.next();
if (row == null) {
break;
}
Object[] rowdata = row.getData();
if (!Constraint.hasReferencedRow(session, rowdata, rowColArray,
mainIndex)) {
String colvalues = "";
for (int i = 0; i < rowColArray.length; i++) {
Object o = rowdata[rowColArray[i]];
colvalues += o;
colvalues += ",";
}
throw Trace.error(
Trace.INTEGRITY_CONSTRAINT_VIOLATION_NOPARENT,
Trace.Constraint_violation, new Object[] {
colvalues, table.getName().name
});
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -