git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@1027 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-2.1.5
@@ -53,6 +53,7 @@ import com.healthmarketscience.jackcess.CursorBuilder; | |||
import com.healthmarketscience.jackcess.DataType; | |||
import com.healthmarketscience.jackcess.Database; | |||
import com.healthmarketscience.jackcess.DatabaseBuilder; | |||
import com.healthmarketscience.jackcess.Index; | |||
import com.healthmarketscience.jackcess.IndexBuilder; | |||
import com.healthmarketscience.jackcess.IndexCursor; | |||
import com.healthmarketscience.jackcess.PropertyMap; | |||
@@ -1171,9 +1172,7 @@ public class DatabaseImpl implements Database | |||
{ | |||
initRelationships(); | |||
String name = findUniqueRelationshipName( | |||
creator.getPrimaryTable().getName() + | |||
creator.getSecondaryTable().getName()); | |||
String name = createRelationshipName(creator); | |||
RelationshipImpl newRel = creator.createRelationshipImpl(name); | |||
ColumnImpl ccol = _relationships.getColumn(REL_COL_COLUMN_COUNT); | |||
@@ -1226,9 +1225,28 @@ public class DatabaseImpl implements Database | |||
} | |||
} | |||
private String findUniqueRelationshipName(String origName) throws IOException { | |||
private String createRelationshipName(RelationshipCreator creator) | |||
throws IOException | |||
{ | |||
// ensure that the final identifier name does not get too long | |||
// - the primary name is limited to ((max / 2) - 3) | |||
// - the total name is limited to (max - 3) | |||
int maxIdLen = getFormat().MAX_INDEX_NAME_LENGTH; | |||
int limit = (maxIdLen / 2) - 3; | |||
String origName = creator.getPrimaryTable().getName(); | |||
if(origName.length() > limit) { | |||
origName = origName.substring(0, limit); | |||
} | |||
limit = maxIdLen - 3; | |||
origName += creator.getSecondaryTable().getName(); | |||
if(origName.length() > limit) { | |||
origName = origName.substring(0, limit); | |||
} | |||
// now ensure name is unique | |||
Set<String> names = new HashSet<String>(); | |||
// collect the names of all relationships for uniqueness check | |||
for(Row row : | |||
CursorImpl.createCursor(_systemCatalog).newIterable().setColumnNames( | |||
SYSTEM_CATALOG_COLUMNS)) | |||
@@ -1239,6 +1257,14 @@ public class DatabaseImpl implements Database | |||
} | |||
} | |||
if(creator.hasReferentialIntegrity()) { | |||
// relationship name will also be index name in secondary table, so must | |||
// check those names as well | |||
for(Index idx : creator.getSecondaryTable().getIndexes()) { | |||
names.add(toLookupName(idx.getName())); | |||
} | |||
} | |||
String baseName = toLookupName(origName); | |||
String name = baseName; | |||
int i = 0; | |||
@@ -1246,8 +1272,6 @@ public class DatabaseImpl implements Database | |||
name = baseName + (++i); | |||
} | |||
// FIXME, truncate to max identifier length | |||
return ((i == 0) ? origName : (origName + i)); | |||
} | |||
@@ -54,10 +54,9 @@ 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 */ | |||
static final byte PRIMARY_TABLE_TYPE = (byte)1; | |||
static final byte FK_PRIMARY_TABLE_TYPE = (byte)1; | |||
/** index table type for the "secondary" table in a foreign key index */ | |||
static final byte SECONDARY_TABLE_TYPE = (byte)2; | |||
static final byte FK_SECONDARY_TABLE_TYPE = (byte)2; | |||
/** indicate an invalid index number for foreign key field */ | |||
private static final int INVALID_INDEX_NUMBER = -1; | |||
@@ -434,7 +433,7 @@ public class IndexImpl implements Index, Comparable<IndexImpl> | |||
} | |||
public boolean isPrimaryTable() { | |||
return(getTableType() == PRIMARY_TABLE_TYPE); | |||
return(getTableType() == FK_PRIMARY_TABLE_TYPE); | |||
} | |||
public int getOtherIndexNumber() { |
@@ -53,16 +53,8 @@ public class RelationshipCreator extends DBMutator | |||
private List<ColumnImpl> _primaryCols; | |||
private List<ColumnImpl> _secondaryCols; | |||
private int _flags; | |||
private String _name; | |||
// - primary table must have unique index | |||
// - primary table index name ".rC", ".rD"... | |||
// - secondary index name "<PTable><STable>" | |||
// - add <name>1, <name>2 after names to make unique (index names and | |||
// relationship names) | |||
// - enforcing rel integrity can't have dupe cols | |||
// FIXME | |||
// - what about index name clashes? | |||
public RelationshipCreator(DatabaseImpl database) | |||
{ | |||
super(database); | |||
@@ -76,7 +68,12 @@ public class RelationshipCreator extends DBMutator | |||
return _secondaryTable; | |||
} | |||
public boolean hasReferentialIntegrity() { | |||
return _relationship.hasReferentialIntegrity(); | |||
} | |||
public RelationshipImpl createRelationshipImpl(String name) { | |||
_name = name; | |||
RelationshipImpl newRel = new RelationshipImpl( | |||
name, _primaryTable, _secondaryTable, _flags, | |||
_primaryCols, _secondaryCols); | |||
@@ -105,7 +102,7 @@ public class RelationshipCreator extends DBMutator | |||
RelationshipImpl newRel = getDatabase().writeRelationship(this); | |||
if(_relationship.hasReferentialIntegrity()) { | |||
if(hasReferentialIntegrity()) { | |||
addPrimaryIndex(); | |||
addSecondaryIndex(); | |||
} | |||
@@ -136,13 +133,13 @@ public class RelationshipCreator extends DBMutator | |||
int otherTableNum = 0; | |||
int otherIdxNum = 0; | |||
if(isPrimary) { | |||
tableType = IndexImpl.PRIMARY_TABLE_TYPE; | |||
tableType = IndexImpl.FK_PRIMARY_TABLE_TYPE; | |||
otherTableNum = _secondaryTable.getTableDefPageNumber(); | |||
// we create the primary index first, so the secondary index does not | |||
// exist yet | |||
otherIdxNum = _secondaryTable.getLogicalIndexCount(); | |||
} else { | |||
tableType = IndexImpl.SECONDARY_TABLE_TYPE; | |||
tableType = IndexImpl.FK_SECONDARY_TABLE_TYPE; | |||
otherTableNum = _primaryTable.getTableDefPageNumber(); | |||
// at this point, we've already created the primary index, it's the last | |||
// one on the primary table | |||
@@ -191,7 +188,7 @@ public class RelationshipCreator extends DBMutator | |||
} | |||
} | |||
if(!_relationship.hasReferentialIntegrity()) { | |||
if(!hasReferentialIntegrity()) { | |||
if((_relationship.getFlags() & CASCADE_FLAGS) != 0) { | |||
throw new IllegalArgumentException(withErrorContext( | |||
@@ -248,18 +245,15 @@ public class RelationshipCreator extends DBMutator | |||
} | |||
private IndexBuilder createPrimaryIndex() { | |||
String name = getUniqueIndexName(_primaryTable); | |||
// FIXME? | |||
String name = createPrimaryIndexName(); | |||
return createIndex(name, _primaryCols) | |||
.setUnique() | |||
.setType(IndexImpl.FOREIGN_KEY_INDEX_TYPE); | |||
} | |||
private IndexBuilder createSecondaryIndex() { | |||
String name = getUniqueIndexName(_secondaryTable); | |||
// FIXME? | |||
return createIndex(name, _secondaryCols) | |||
// secondary index uses relationship name | |||
return createIndex(_name, _secondaryCols) | |||
.setType(IndexImpl.FOREIGN_KEY_INDEX_TYPE); | |||
} | |||
@@ -271,45 +265,29 @@ public class RelationshipCreator extends DBMutator | |||
return idx; | |||
} | |||
private String getUniqueIndexName(TableImpl table) { | |||
Set<String> idxNames = TableUpdater.getIndexNames(table, null); | |||
private String createPrimaryIndexName() { | |||
Set<String> idxNames = TableUpdater.getIndexNames(_primaryTable, null); | |||
boolean isPrimary = (table == _primaryTable); | |||
String baseName = null; | |||
String suffix = null; | |||
if(isPrimary) { | |||
// primary naming scheme: ".rB", .rC", ".rD", "rE" ... | |||
baseName = ".r"; | |||
suffix = "B"; | |||
} else { | |||
// secondary naming scheme: "<t1><t2>", "<t1><t2>1", "<t1><t2>2" | |||
baseName = _primaryTable.getName() + _secondaryTable.getName(); | |||
suffix = ""; | |||
} | |||
// primary naming scheme: ".rB", .rC", ".rD", "rE" ... | |||
String baseName = ".r"; | |||
String suffix = "B"; | |||
int count = 0; | |||
while(true) { | |||
String idxName = baseName + suffix; | |||
if(!idxNames.contains(idxName.toUpperCase())) { | |||
if(!idxNames.contains(DatabaseImpl.toLookupName(idxName))) { | |||
return idxName; | |||
} | |||
++count; | |||
if(isPrimary) { | |||
char c = (char)(suffix.charAt(0) + 1); | |||
if(c == '[') { | |||
c = 'a'; | |||
} | |||
suffix = "" + c; | |||
} else { | |||
suffix = "" + count; | |||
} | |||
char c = (char)(suffix.charAt(0) + 1); | |||
if(c == '[') { | |||
c = 'a'; | |||
} | |||
suffix = "" + c; | |||
} | |||
// FIXME, truncate to max index name length | |||
} | |||
private static List<ColumnImpl> getColumns(TableImpl table, List<String> colNames) { | |||
private static List<ColumnImpl> getColumns(TableImpl table, | |||
List<String> colNames) { | |||
List<ColumnImpl> cols = new ArrayList<ColumnImpl>(); | |||
for(String colName : colNames) { | |||
cols.add(table.getColumn(colName)); |
@@ -63,7 +63,7 @@ public abstract class TableMutator extends DBMutator | |||
} | |||
column.validate(getFormat()); | |||
if(!colNames.add(column.getName().toUpperCase())) { | |||
if(!colNames.add(DatabaseImpl.toLookupName(column.getName()))) { | |||
throw new IllegalArgumentException(withErrorContext( | |||
"duplicate column name: " + column.getName())); | |||
} | |||
@@ -75,7 +75,7 @@ public abstract class TableMutator extends DBMutator | |||
boolean[] foundPk, IndexBuilder index) { | |||
index.validate(colNames, getFormat()); | |||
if(!idxNames.add(index.getName().toUpperCase())) { | |||
if(!idxNames.add(DatabaseImpl.toLookupName(index.getName()))) { | |||
throw new IllegalArgumentException(withErrorContext( | |||
"duplicate index name: " + index.getName())); | |||
} |
@@ -240,7 +240,7 @@ public class TableUpdater extends TableMutator | |||
private Set<String> getColumnNames() { | |||
Set<String> colNames = new HashSet<String>(); | |||
for(ColumnImpl column : _table.getColumns()) { | |||
colNames.add(column.getName().toUpperCase()); | |||
colNames.add(DatabaseImpl.toLookupName(column.getName())); | |||
} | |||
return colNames; | |||
} | |||
@@ -248,7 +248,7 @@ public class TableUpdater extends TableMutator | |||
static Set<String> getIndexNames(TableImpl table, boolean[] foundPk) { | |||
Set<String> idxNames = new HashSet<String>(); | |||
for(IndexImpl index : table.getIndexes()) { | |||
idxNames.add(index.getName().toUpperCase()); | |||
idxNames.add(DatabaseImpl.toLookupName(index.getName())); | |||
if(index.isPrimaryKey() && (foundPk != null)) { | |||
foundPk[0] = true; | |||
} |