Browse Source

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
tags/jackcess-2.1.5
James Ahlborn 7 years ago
parent
commit
6d1576e9f1

+ 1
- 0
src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java View File

@@ -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());

+ 1
- 1
src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java View File

@@ -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;

+ 64
- 6
src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java View File

@@ -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);
}

+ 12
- 2
src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java View File

@@ -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()) {

Loading…
Cancel
Save