mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Support duplicate index detection, max constraint names - Internal changes for DB Migration / DDL generation #369
This commit is contained in:
+124
-10
@@ -23,11 +23,38 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
protected final PlatformDdl platformDdl;
|
||||
|
||||
/**
|
||||
* Used to check that indexes on foreign keys should be skipped as a unique index on the columns
|
||||
* already exists.
|
||||
*/
|
||||
protected IndexSet indexSet = new IndexSet();
|
||||
|
||||
// counters used when constraint names are truncated due to maximum length
|
||||
// and these counters are used to keep the constraint name unique
|
||||
protected int countCheck;
|
||||
protected int countUnique;
|
||||
protected int countForeignKey;
|
||||
protected int countIndex;
|
||||
|
||||
/**
|
||||
* Construct with a naming convention and platform specific DDL.
|
||||
*/
|
||||
public BaseTableDdl(DdlNamingConvention namingConvention, PlatformDdl platformDdl) {
|
||||
this.namingConvention = namingConvention;
|
||||
this.platformDdl = platformDdl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset counters and index set for each table.
|
||||
*/
|
||||
protected void reset() {
|
||||
indexSet.clear();
|
||||
countCheck = 0;
|
||||
countUnique = 0;
|
||||
countForeignKey = 0;
|
||||
countIndex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the appropriate 'create table' and matching 'drop table' statements
|
||||
* and add them to the 'apply' and 'rollback' buffers.
|
||||
@@ -35,6 +62,8 @@ public class BaseTableDdl implements TableDdl {
|
||||
@Override
|
||||
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
|
||||
|
||||
reset();
|
||||
|
||||
String tableName = lowerName(createTable.getName());
|
||||
List<Column> columns = createTable.getColumn();
|
||||
List<Column> pk = determinePrimaryKeyColumns(columns);
|
||||
@@ -176,15 +205,21 @@ public class BaseTableDdl implements TableDdl {
|
||||
|
||||
String indexName = determineForeignKeyIndexName(tableName, columns);
|
||||
|
||||
fkeyBuffer.append("create index ").append(indexName).append(" on ").append(tableName);
|
||||
appendColumns(columns, fkeyBuffer);
|
||||
fkeyBuffer.endOfStatement();
|
||||
boolean addIndex = indexSet.add(columns);
|
||||
if (addIndex) {
|
||||
// no matching unique constraint so add the index
|
||||
fkeyBuffer.append("create index ").append(indexName).append(" on ").append(tableName);
|
||||
appendColumns(columns, fkeyBuffer);
|
||||
fkeyBuffer.endOfStatement();
|
||||
}
|
||||
|
||||
fkeyBuffer.end();
|
||||
|
||||
write.rollbackForeignKeys()
|
||||
.append("drop index ").append(indexName)
|
||||
.endOfStatement();
|
||||
if (addIndex) {
|
||||
write.rollbackForeignKeys()
|
||||
.append("drop index ").append(indexName)
|
||||
.endOfStatement();
|
||||
}
|
||||
|
||||
write.rollbackForeignKeys()
|
||||
.append("alter table ").append(tableName).append(" drop constraint ").append(fkName)
|
||||
@@ -253,6 +288,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
for (Column column : columns) {
|
||||
if (isTrue(column.isUnique())) {
|
||||
inlineUniqueConstraintSingle(apply, createTable.getName(), column);
|
||||
indexSet.add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,7 +405,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
protected String determineForeignKeyConstraintName(String tableName, String columnName) {
|
||||
|
||||
return namingConvention.foreignKeyConstraintName(tableName, columnName);
|
||||
return namingConvention.foreignKeyConstraintName(tableName, columnName, ++countForeignKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -377,7 +413,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
protected String determineForeignKeyIndexName(String tableName, String[] columns) {
|
||||
|
||||
return namingConvention.foreignKeyIndexName(tableName, columns);
|
||||
return namingConvention.foreignKeyIndexName(tableName, columns, ++countIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +421,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
protected String determineUniqueConstraintName(String tableName, String columnName) {
|
||||
|
||||
return namingConvention.uniqueConstraintName(tableName, columnName);
|
||||
return namingConvention.uniqueConstraintName(tableName, columnName, ++countUnique);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,7 +429,7 @@ public class BaseTableDdl implements TableDdl {
|
||||
*/
|
||||
protected String determineCheckConstraintName(String tableName, String columnName) {
|
||||
|
||||
return namingConvention.checkConstraintName(tableName, columnName);
|
||||
return namingConvention.checkConstraintName(tableName, columnName, ++countCheck);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,4 +463,82 @@ public class BaseTableDdl implements TableDdl {
|
||||
return (value == null) ? 0 : value.intValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The indexes held on the table.
|
||||
* <p>
|
||||
* Used to detect when we don't need to add an index on the foreign key columns
|
||||
* when there is an existing unique constraint with the same columns.
|
||||
*/
|
||||
protected static class IndexSet {
|
||||
|
||||
private List<IndexColumns> indexes = new ArrayList<IndexColumns>();
|
||||
|
||||
/**
|
||||
* Clear the indexes (for each table).
|
||||
*/
|
||||
public void clear() {
|
||||
indexes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an index for the given column.
|
||||
*/
|
||||
public void add(Column column) {
|
||||
indexes.add(new IndexColumns(column));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if an index should be added for the given columns.
|
||||
* <p>
|
||||
* Returning false indicates there is an existing index (unique constraint) with these columns
|
||||
* and that an extra index should not be added.
|
||||
* </p>
|
||||
*/
|
||||
public boolean add(String[] columns) {
|
||||
IndexColumns newIndex = new IndexColumns(columns);
|
||||
for (int i = 0; i <indexes.size() ; i++) {
|
||||
if (indexes.get(i).isMatch(newIndex)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
indexes.add(newIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of columns making up a particular index (column order is important).
|
||||
*/
|
||||
protected static class IndexColumns {
|
||||
|
||||
List<String> columns = new ArrayList<String>(4);
|
||||
|
||||
/**
|
||||
* Construct representing as a single column index.
|
||||
*/
|
||||
public IndexColumns(Column column) {
|
||||
columns.add(column.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct representing index.
|
||||
*/
|
||||
public IndexColumns(String[] columnNames) {
|
||||
for (int i = 0; i <columnNames.length; i++) {
|
||||
columns.add(columnNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there this index match (same columns same order).
|
||||
*/
|
||||
public boolean isMatch(IndexColumns other) {
|
||||
return columns.equals(other.columns);
|
||||
}
|
||||
|
||||
protected void add(String column) {
|
||||
columns.add(column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+23
-10
@@ -22,6 +22,8 @@ public class DdlNamingConvention {
|
||||
protected String ckPrefix = "ck_";
|
||||
protected String ckSuffix = "";
|
||||
|
||||
protected int maxConstraintNameLength = 32;
|
||||
|
||||
protected boolean lowerCaseNames = true;
|
||||
|
||||
protected DdlNameNormalise normalise = new DdlNameNormalise();
|
||||
@@ -34,20 +36,20 @@ public class DdlNamingConvention {
|
||||
*/
|
||||
public String primaryKeyName(String tableName) {
|
||||
|
||||
return pkPrefix + normaliseTable(tableName) + pkSuffix;
|
||||
return maxLength(pkPrefix + normaliseTable(tableName) + pkSuffix, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the foreign key constraint name given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyConstraintName(String tableName, String columnName) {
|
||||
return fkPrefix + normaliseTable(tableName) + fkMiddle + normaliseColumn(columnName) + fkSuffix;
|
||||
public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) {
|
||||
return maxLength(fkPrefix + normaliseTable(tableName) + fkMiddle + normaliseColumn(columnName) + fkSuffix, foreignKeyCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index name associated with a foreign key constraint given a single column foreign key.
|
||||
*/
|
||||
public String foreignKeyIndexName(String tableName, String[] columns) {
|
||||
public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) {
|
||||
|
||||
String colPart;
|
||||
if (columns.length == 1) {
|
||||
@@ -62,24 +64,23 @@ public class DdlNamingConvention {
|
||||
}
|
||||
colPart = sb.toString();
|
||||
}
|
||||
//FIXME: apply max length
|
||||
return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix;
|
||||
return maxLength(fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix, indexCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unique constraint name.
|
||||
*/
|
||||
public String uniqueConstraintName(String tableName, String columnName) {
|
||||
public String uniqueConstraintName(String tableName, String columnName, int indexCount) {
|
||||
|
||||
return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix;
|
||||
return maxLength(uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix, indexCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the check constraint name.
|
||||
*/
|
||||
public String checkConstraintName(String tableName, String columnName) {
|
||||
public String checkConstraintName(String tableName, String columnName, int checkCount) {
|
||||
|
||||
return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix;
|
||||
return maxLength(ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix, checkCount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +96,18 @@ public class DdlNamingConvention {
|
||||
return (sequenceName != null) ? lowerName(sequenceName) : normaliseTable(tableName) + "_seq";
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a maximum length to the constraint name.
|
||||
*/
|
||||
protected String maxLength(String constraintName, int count) {
|
||||
if (constraintName.length() < maxConstraintNameLength) {
|
||||
return constraintName;
|
||||
}
|
||||
// add the count to ensure the constraint name is unique
|
||||
// (relying on the prefix having the table name to be globally unique)
|
||||
return constraintName.substring(0,maxConstraintNameLength-3)+"_"+count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise the table name by trimming catalog and schema and removing any
|
||||
* quoted identifier characters (",',[,] etc).
|
||||
|
||||
@@ -30,6 +30,8 @@ public class PlatformDdl {
|
||||
*/
|
||||
protected String dropTableIfExists = "drop table if exists ";
|
||||
|
||||
protected String dropTableCascade = "";
|
||||
|
||||
/**
|
||||
* Default assumes if exists is supported.
|
||||
*/
|
||||
@@ -107,7 +109,7 @@ public class PlatformDdl {
|
||||
}
|
||||
|
||||
public String dropTable(String tableName) {
|
||||
return dropTableIfExists + tableName;
|
||||
return dropTableIfExists + tableName + dropTableCascade;
|
||||
}
|
||||
|
||||
public String lowerName(String name) {
|
||||
|
||||
Reference in New Issue
Block a user