diff options
Diffstat (limited to 'src/main/java/com')
7 files changed, 108 insertions, 29 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java index 7822b2d..472740e 100644 --- a/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java +++ b/src/main/java/com/healthmarketscience/jackcess/IndexBuilder.java @@ -124,6 +124,14 @@ public class IndexBuilder } /** + * @usage _advanced_method_ + */ + public IndexBuilder setType(byte type) { + _type = type; + return this; + } + + /** * Sets this index to enforce uniqueness. */ public IndexBuilder setUnique() { diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index fb1120c..5bfac3c 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -1170,8 +1170,9 @@ public class DatabaseImpl implements Database { initRelationships(); - String name = creator.getPrimaryTable().getName() + - creator.getSecondaryTable().getName(); // FIXME make unique + String name = findUniqueRelationshipName( + creator.getPrimaryTable().getName() + + creator.getSecondaryTable().getName()); RelationshipImpl newRel = creator.createRelationshipImpl(name); ColumnImpl ccol = _relationships.getColumn(REL_COL_COLUMN_COUNT); @@ -1222,6 +1223,29 @@ public class DatabaseImpl implements Database _relationships = getRequiredSystemTable(TABLE_SYSTEM_RELATIONSHIPS); } } + + private String findUniqueRelationshipName(String origName) throws IOException { + Set<String> names = new HashSet<String>(); + + for(Row row : + CursorImpl.createCursor(_systemCatalog).newIterable().setColumnNames( + SYSTEM_CATALOG_COLUMNS)) + { + String name = row.getString(CAT_COL_NAME); + if (name != null && TYPE_RELATIONSHIP.equals(row.get(CAT_COL_TYPE))) { + names.add(toLookupName(name)); + } + } + + String baseName = toLookupName(origName); + String name = baseName; + int i = 0; + while(names.contains(name)) { + name = baseName + (++i); + } + + return ((i == 0) ? origName : (origName + i)); + } public List<Query> getQueries() throws IOException { diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java index 833ee98..8ea7ed8 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/IndexImpl.java @@ -360,12 +360,34 @@ public class IndexImpl implements Index, Comparable<IndexImpl> buffer.putInt(TableImpl.MAGIC_TABLE_NUMBER); // seemingly constant magic value which matches the table def buffer.putInt(idx.getIndexNumber()); // index num buffer.putInt(idxDataState.getIndexDataNumber()); // index data num - buffer.put((byte)0); // related table type - buffer.putInt(INVALID_INDEX_NUMBER); // related index num - buffer.putInt(0); // related table definition page number - buffer.put((byte)0); // cascade updates flag - buffer.put((byte)0); // cascade deletes flag - buffer.put(idx.getType()); // index type flags + + byte idxType = idx.getType(); + if(idxType != FOREIGN_KEY_INDEX_TYPE) { + buffer.put((byte)0); // related table type + buffer.putInt(INVALID_INDEX_NUMBER); // related index num + buffer.putInt(0); // related table definition page number + buffer.put((byte)0); // cascade updates flag + buffer.put((byte)0); // cascade deletes flag + } else { + ForeignKeyReference reference = mutator.getForeignKey(idx); + buffer.put(reference.getTableType()); // related table type + buffer.putInt(reference.getOtherIndexNumber()); // related index num + buffer.putInt(reference.getOtherTablePageNumber()); // related table definition page number + byte updateFlags = 0; + if(reference.isCascadeUpdates()) { + updateFlags |= CASCADE_UPDATES_FLAG; + } + byte deleteFlags = 0; + if(reference.isCascadeDeletes()) { + deleteFlags |= CASCADE_DELETES_FLAG; + } + if(reference.isCascadeNullOnDelete()) { + deleteFlags |= CASCADE_NULL_FLAG; + } + buffer.put(updateFlags); // cascade updates flag + buffer.put(deleteFlags); // cascade deletes flag + } + buffer.put(idxType); // index type flags buffer.putInt(0); // unknown } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java index 0d6fe26..c137f7f 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/RelationshipCreator.java @@ -50,8 +50,7 @@ public class RelationshipCreator extends DBMutator // - secondary index name "<PTable><STable>" // - add <name>1, <name>2 after names to make unique (index names and // relationship names) - // FIXME - // - relationships also have entry in MSysObjects table + // - enforcing rel integrity can't have dupe cols public RelationshipCreator(DatabaseImpl database) { @@ -148,6 +147,9 @@ public class RelationshipCreator extends DBMutator return; } + // for now, we will require the unique index on the primary table (just + // like access does). we could just create it auto-magically... + // FIXME // - same number cols @@ -227,8 +229,8 @@ public class RelationshipCreator extends DBMutator return cols; } - private static Collection<String> getColumnNames( - List<ColumnImpl> cols, Collection<String> colNames) { + private static List<String> getColumnNames(List<ColumnImpl> cols) { + List<String> colNames = new ArrayList<String>(); for(ColumnImpl col : cols) { colNames.add(col.getName()); } @@ -239,12 +241,12 @@ public class RelationshipCreator extends DBMutator // a relationship is one to one if the two sides of the relationship have // unique indexes on the relevant columns IndexImpl idx = _primaryTable.findIndexForColumns( - getColumnNames(_primaryCols, new HashSet<String>()), true); + getColumnNames(_primaryCols), true); if(idx == null) { return false; } idx = _secondaryTable.findIndexForColumns( - getColumnNames(_secondaryCols, new HashSet<String>()), true); + getColumnNames(_secondaryCols), true); return (idx != null); } @@ -255,7 +257,7 @@ public class RelationshipCreator extends DBMutator tableName = table.getName(); } if(cols != null) { - colNames = getColumnNames(cols, new ArrayList<String>()); + colNames = getColumnNames(cols); } return CustomToStringStyle.valueBuilder(tableName) diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java index 36c866d..df6076a 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableCreator.java @@ -333,7 +333,8 @@ public class TableCreator extends TableMutator (col1.getFlags() == col2.getFlags())); } - private String withErrorContext(String msg) { + @Override + protected String withErrorContext(String msg) { return msg + "(Table=" + getName() + ")"; } } diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java index 494bfb7..5bc7e11 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java @@ -50,18 +50,22 @@ public abstract class TableMutator extends DBMutator return _colOffsets; } + public IndexImpl.ForeignKeyReference getForeignKey(IndexBuilder idx) { + return null; + } + protected void validateColumn(Set<String> colNames, ColumnBuilder column) { // FIXME for now, we can't create complex columns if(column.getType() == DataType.COMPLEX_TYPE) { - throw new UnsupportedOperationException( - "Complex column creation is not yet implemented"); + throw new UnsupportedOperationException(withErrorContext( + "Complex column creation is not yet implemented")); } column.validate(getFormat()); if(!colNames.add(column.getName().toUpperCase())) { - throw new IllegalArgumentException("duplicate column name: " + - column.getName()); + throw new IllegalArgumentException(withErrorContext( + "duplicate column name: " + column.getName())); } setColumnSortOrder(column); @@ -72,26 +76,31 @@ public abstract class TableMutator extends DBMutator index.validate(colNames, getFormat()); if(!idxNames.add(index.getName().toUpperCase())) { - throw new IllegalArgumentException("duplicate index name: " + - index.getName()); + throw new IllegalArgumentException(withErrorContext( + "duplicate index name: " + index.getName())); } if(index.isPrimaryKey()) { if(foundPk[0]) { - throw new IllegalArgumentException( - "found second primary key index: " + index.getName()); + throw new IllegalArgumentException(withErrorContext( + "found second primary key index: " + index.getName())); } foundPk[0] = true; + } else if(index.getType() == IndexImpl.FOREIGN_KEY_INDEX_TYPE) { + if(getForeignKey(index) == null) { + throw new IllegalArgumentException(withErrorContext( + "missing foreign key info for " + index.getName())); + } } } - protected static void validateAutoNumberColumn(Set<DataType> autoTypes, - ColumnBuilder column) + protected void validateAutoNumberColumn(Set<DataType> autoTypes, + ColumnBuilder column) { if(!column.getType().isMultipleAutoNumberAllowed() && !autoTypes.add(column.getType())) { - throw new IllegalArgumentException( + throw new IllegalArgumentException(withErrorContext( "Can have at most one AutoNumber column of type " + column.getType() + - " per table"); + " per table")); } } @@ -112,6 +121,8 @@ public abstract class TableMutator extends DBMutator public abstract IndexDataState getIndexDataState(IndexBuilder idx); + protected abstract String withErrorContext(String msg); + /** * Maintains additional state used during column writing. * @usage _advanced_class_ diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java b/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java index 54bfd68..a6cbdea 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/TableUpdater.java @@ -45,6 +45,7 @@ public class TableUpdater extends TableMutator private List<Integer> _nextPages = new ArrayList<Integer>(1); private ColumnState _colState; private IndexDataState _idxDataState; + private IndexImpl.ForeignKeyReference _fkReference; public TableUpdater(TableImpl table) { super(table.getDatabase()); @@ -89,6 +90,15 @@ public class TableUpdater extends TableMutator return ((idx == _index) ? _idxDataState : null); } + void setForeignKey(IndexImpl.ForeignKeyReference fkReference) { + _fkReference = fkReference; + } + + @Override + public IndexImpl.ForeignKeyReference getForeignKey(IndexBuilder idx) { + return ((idx == _index) ? _fkReference : null); + } + int getAddedTdefLen() { return _addedTdefLen; } @@ -294,7 +304,8 @@ public class TableUpdater extends TableMutator (col2.getFlags() | ignoreColFlags))); } - private String withErrorContext(String msg) { + @Override + protected String withErrorContext(String msg) { String objStr = ""; if(_column != null) { objStr = ";Column=" + _column.getName(); |