aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Ahlborn <jtahlborn@yahoo.com>2016-08-30 02:24:33 +0000
committerJames Ahlborn <jtahlborn@yahoo.com>2016-08-30 02:24:33 +0000
commit6d1576e9f100a3a96c6c3f1321e3c8bf72c46cb9 (patch)
treed389c9cde6a6d7a9c4830a943abecfbf411d254a
parentfceec0358a905c36b75ee4b27197d4b270394089 (diff)
downloadjackcess-6d1576e9f100a3a96c6c3f1321e3c8bf72c46cb9.tar.gz
jackcess-6d1576e9f100a3a96c6c3f1321e3c8bf72c46cb9.zip
implement adding indexes for integ enforced relationships
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@1014 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java1
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java2
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java70
-rw-r--r--src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java14
4 files changed, 78 insertions, 9 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java b/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
index d29836a..400446b 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
@@ -251,6 +251,7 @@ final class FKEnforcer
// ensure that the relevant rows exist in the primary tables for which
// this table is a secondary table. however, null values are allowed
if(!areNull(joiner, row) && !joiner.hasRows(row)) {
+ // FIXME, add error context here?
throw new ConstraintViolationException(
"Adding new row " + Arrays.asList(row) + " violates constraint " +
joiner.toFKString());
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
index 8ea7ed8..0cf07cf 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
@@ -54,7 +54,7 @@ public class IndexImpl implements Index, Comparable<IndexImpl>
private static final byte CASCADE_NULL_FLAG = (byte)2;
/** index table type for the "primary" table in a foreign key index */
- private static final byte PRIMARY_TABLE_TYPE = (byte)1;
+ static final byte PRIMARY_TABLE_TYPE = (byte)1;
/** indicate an invalid index number for foreign key field */
private static final int INVALID_INDEX_NUMBER = -1;
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java
index 550d498..64e5abb 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java
@@ -23,8 +23,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import com.healthmarketscience.jackcess.ConstraintViolationException;
import com.healthmarketscience.jackcess.IndexBuilder;
+import com.healthmarketscience.jackcess.IndexCursor;
import com.healthmarketscience.jackcess.RelationshipBuilder;
+import com.healthmarketscience.jackcess.Row;
/**
*
@@ -94,9 +97,10 @@ public class RelationshipCreator extends DBMutator
RelationshipImpl newRel = getDatabase().writeRelationship(this);
- // FIXME, handle indexes
-
- // FIXME, enforce ref integ before adding indexes!
+ if(_relationship.hasReferentialIntegrity()) {
+ addPrimaryIndex();
+ addSecondaryIndex();
+ }
return newRel;
@@ -105,6 +109,39 @@ public class RelationshipCreator extends DBMutator
}
}
+ private void addPrimaryIndex() throws IOException {
+ TableUpdater updater = new TableUpdater(_primaryTable);
+ updater.setForeignKey(createFKReference(true));
+ updater.addIndex(createPrimaryIndex(), true);
+ }
+
+ private void addSecondaryIndex() throws IOException {
+ TableUpdater updater = new TableUpdater(_secondaryTable);
+ updater.setForeignKey(createFKReference(false));
+ updater.addIndex(createSecondaryIndex(), true);
+ }
+
+ private IndexImpl.ForeignKeyReference createFKReference(boolean isPrimary) {
+ byte tableType = 0;
+ int otherTableNum = 0;
+ int otherIdxNum = 0;
+ if(isPrimary) {
+ tableType = IndexImpl.PRIMARY_TABLE_TYPE;
+ otherTableNum = _secondaryTable.getTableDefPageNumber();
+ otherIdxNum = _secondaryTable.getLogicalIndexCount();
+ } else {
+ otherTableNum = _primaryTable.getTableDefPageNumber();
+ otherIdxNum = _primaryTable.getLogicalIndexCount();
+ }
+ boolean cascadeUpdates = ((_flags & RelationshipImpl.CASCADE_UPDATES_FLAG) != 0);
+ boolean cascadeDeletes = ((_flags & RelationshipImpl.CASCADE_DELETES_FLAG) != 0);
+ boolean cascadeNull = ((_flags & RelationshipImpl.CASCADE_NULL_FLAG) != 0);
+
+ return new IndexImpl.ForeignKeyReference(
+ tableType, otherIdxNum, otherTableNum, cascadeUpdates, cascadeDeletes,
+ cascadeNull);
+ }
+
private void validate() throws IOException {
_primaryTable = getDatabase().getTable(_relationship.getToTable());
@@ -167,10 +204,31 @@ public class RelationshipCreator extends DBMutator
"Cannot have duplicate columns in an integrity enforced relationship"));
}
+ // TODO: future, check for enforce cycles?
+
// check referential integrity
- // FIXME
+ IndexCursor primaryCursor = primaryIdx.newCursor().toIndexCursor();
+ Object[] entryValues = new Object[_secondaryCols.size()];
+ for(Row row : _secondaryTable.newCursor().toCursor()
+ .newIterable().addColumns(_secondaryCols)) {
+ // grab the from table values
+ boolean hasValues = false;
+ for(int i = 0; i < _secondaryCols.size(); ++i) {
+ entryValues[i] = _secondaryCols.get(i).getRowValue(row);
+ hasValues = hasValues || (entryValues[i] != null);
+ }
+
+ if(!hasValues) {
+ // we can ignore null entries
+ continue;
+ }
+
+ if(!primaryCursor.findFirstRowByEntry(entryValues)) {
+ throw new ConstraintViolationException(withErrorContext(
+ "Integrity constraint violation found for relationship"));
+ }
+ }
- // TODO: future, check for enforce cycles?
}
private IndexBuilder createPrimaryIndex() {
@@ -185,7 +243,7 @@ public class RelationshipCreator extends DBMutator
String name = getUniqueIndexName(_secondaryTable);
// FIXME?
- return createIndex(name, _primaryCols)
+ return createIndex(name, _secondaryCols)
.setType(IndexImpl.FOREIGN_KEY_INDEX_TYPE);
}
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java
index a6cbdea..43896be 100644
--- a/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java
+++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java
@@ -145,10 +145,16 @@ public class TableUpdater extends TableMutator
}
public IndexImpl addIndex(IndexBuilder index) throws IOException {
+ return addIndex(index, false);
+ }
+
+ IndexImpl addIndex(IndexBuilder index, boolean isInternal) throws IOException {
_index = index;
- validateAddIndex();
+ if(!isInternal) {
+ validateAddIndex();
+ }
// assign index number and do some assorted index bookkeeping
int indexNumber = _table.getLogicalIndexCount();
@@ -157,7 +163,11 @@ public class TableUpdater extends TableMutator
// initialize backing index state
initIndexDataState();
- getPageChannel().startExclusiveWrite();
+ if(!isInternal) {
+ getPageChannel().startExclusiveWrite();
+ } else {
+ getPageChannel().startWrite();
+ }
try {
if(_idxDataState.getIndexDataNumber() == _table.getIndexCount()) {