]> source.dussan.org Git - jackcess.git/commitdiff
implement adding indexes for integ enforced relationships
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 30 Aug 2016 02:24:33 +0000 (02:24 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 30 Aug 2016 02:24:33 +0000 (02:24 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@1014 f203690c-595d-4dc9-a70b-905162fa7fd2

src/main/java/com/healthmarketscience/jackcess/impl/FKEnforcer.java
src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java
src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java

index d29836a2873a99fe08b6ea6b0b84b7bf623505dd..400446b7d4340fca2a0be4f4e2dd7493aac265d3 100644 (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());
index 8ea7ed8d52023b26b2fac383d9035e667629ba15..0cf07cf83d1a23be2bed5b27cbfac6d5af96fa03 100644 (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;
index 550d498a68a4868e6878af7287d0708a1762c1a0..64e5abb4221c0fc64a974e0151a0ccc8a43c93f4 100644 (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);
   }
   
index a6cbdea08a7a891fe4b4ac0d95e85abc4c24d5ec..43896be2dc04701f36c64740958212d38749110f 100644 (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()) {