diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java index f1b344090..98d86a097 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -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 columns = createTable.getColumn(); List 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. + *

+ * 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 indexes = new ArrayList(); + + /** + * 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. + *

+ * Returning false indicates there is an existing index (unique constraint) with these columns + * and that an extra index should not be added. + *

+ */ + public boolean add(String[] columns) { + IndexColumns newIndex = new IndexColumns(columns); + for (int i = 0; i columns = new ArrayList(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