diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index cdfc96feb..3d7e74065 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -451,7 +451,7 @@ public class BaseTableDdl implements TableDdl { String tableName = lowerTableName(request.table()); if (request.indexName() != null) { // no matching unique constraint so add the index - fkeyBuffer.appendStatement(platformDdl.createIndex(request.indexName(), tableName, request.cols())); + fkeyBuffer.appendStatement(platformDdl.createIndex(request.indexName(), tableName, request.cols(), false)); } alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request); @@ -609,10 +609,10 @@ public class BaseTableDdl implements TableDdl { } @Override - public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException { - if (platformInclude(createIndex.getPlatforms())) { - writer.apply().appendStatement(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), split(createIndex.getColumns()))); - writer.dropAll().appendStatement(platformDdl.dropIndex(createIndex.getIndexName(), createIndex.getTableName())); + public void generate(DdlWrite writer, CreateIndex index) throws IOException { + if (platformInclude(index.getPlatforms())) { + writer.apply().appendStatement(platformDdl.createIndex(index.getIndexName(), index.getTableName(), split(index.getColumns()), Boolean.TRUE.equals(index.isUnique()))); + writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName())); } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java index 3f4c46d71..ee3fe32eb 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java @@ -61,7 +61,7 @@ public class ClickHouseDdl extends PlatformDdl { } @Override - public String createIndex(String indexName, String tableName, String[] columns) { + public String createIndex(String indexName, String tableName, String[] columns, boolean unique) { return null; } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java index da679d9a5..39fee3dd3 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java @@ -13,7 +13,7 @@ public class HanaColumnStoreDdl extends AbstractHanaDdl { } @Override - public String createIndex(String indexName, String tableName, String[] columns) { + public String createIndex(String indexName, String tableName, String[] columns, boolean unique) { if (columns == null || columns.length == 0) { return "-- cannot create index: no columns given"; } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index a78a80b58..9d59faa5e 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -109,6 +109,8 @@ public class PlatformDdl { protected String addForeignKeySkipCheck = ""; + protected String uniqueIndex = "unique"; + /** * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. */ @@ -389,12 +391,14 @@ public class PlatformDdl { /** * Return the create index statement. */ - public String createIndex(String indexName, String tableName, String[] columns) { - + public String createIndex(String indexName, String tableName, String[] columns, boolean unique) { StringBuilder buffer = new StringBuilder(); - buffer.append("create index ").append(maxConstraintName(indexName)).append(" on ").append(tableName); + buffer.append("create "); + if (unique) { + buffer.append(uniqueIndex).append(" "); + } + buffer.append("index ").append(maxConstraintName(indexName)).append(" on ").append(tableName); appendColumns(columns, buffer); - return buffer.toString(); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java index f47bc6997..de0cdb0e3 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java +++ b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java @@ -19,6 +19,7 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="indexName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="columns" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> @@ -36,6 +37,8 @@ public class CreateIndex { protected String tableName; @XmlAttribute(name = "columns", required = true) protected String columns; + @XmlAttribute(name = "unique") + protected Boolean unique; @XmlAttribute(name = "platforms") protected String platforms; @@ -99,6 +102,20 @@ public class CreateIndex { this.columns = value; } + /** + * Return the unique property. + */ + public Boolean isUnique() { + return unique; + } + + /** + * Set the unique property. + */ + public void setUnique(Boolean unique) { + this.unique = unique; + } + /** * Return the platforms. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java b/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java index e47a4e326..08556c414 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java @@ -20,6 +20,8 @@ public class MIndex { private List columns = new ArrayList<>(); + private boolean unique; + /** * Create a single column non unique index. */ @@ -29,9 +31,10 @@ public class MIndex { this.columns.add(columnName); } - public MIndex(String indexName, String tableName, String[] columnNames, String platforms) { + public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique) { this(indexName, tableName, columnNames); this.platforms = platforms; + this.unique = unique; } /** @@ -48,6 +51,7 @@ public class MIndex { this.tableName = createIndex.getTableName(); this.columns = split(createIndex.getColumns()); this.platforms = createIndex.getPlatforms(); + this.unique = Boolean.TRUE.equals(createIndex.isUnique()); } public String getKey() { @@ -85,6 +89,9 @@ public class MIndex { create.setTableName(tableName); create.setColumns(join()); create.setPlatforms(platforms); + if (Boolean.TRUE.equals(unique)) { + create.setUnique(Boolean.TRUE); + } return create; } @@ -117,6 +124,9 @@ public class MIndex { if (!tableName.equals(newIndex.getTableName())) { return true; } + if (unique != newIndex.unique) { + return true; + } List newColumns = newIndex.getColumns(); if (columns.size() != newColumns.size()) { return true; diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index 3df275ccc..969a7cf23 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -61,7 +61,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { for (IndexDefinition index : indexes) { String[] columns = index.getColumns(); indexSet.add(columns); - if (index.isUnique()) { + if (index.isUniqueConstraint()) { table.addUniqueConstraint(createMUniqueConstraint(index, columns)); } else { // 'just' an index (not a unique constraint) @@ -92,7 +92,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { } private MIndex createMIndex(String indexName, String tableName, IndexDefinition index) { - return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms())); + return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms()), index.isUnique()); } private String platforms(Platform[] platforms) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java b/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java index b5fb5c757..65bf62665 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java +++ b/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java @@ -35,6 +35,22 @@ public class IndexDefinition { this.platforms = null; } + /** + * Return true if this can be used as a unique constraint. + */ + public boolean isUniqueConstraint() { + return unique && noColumnFormulas(); + } + + private boolean noColumnFormulas() { + for (String column : columns) { + if (column.contains("(")) { + return false; + } + } + return true; + } + /** * Return true if this is a unique constraint. */ diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd index 02b496645..73d7e91ef 100644 --- a/src/main/resources/ebean-dbmigration-1.0.xsd +++ b/src/main/resources/ebean-dbmigration-1.0.xsd @@ -283,13 +283,14 @@ - + + diff --git a/src/test/java/misc/migration/v1_2/OtoChild.java b/src/test/java/misc/migration/v1_2/OtoChild.java index c72e5fab6..39b298d8b 100644 --- a/src/test/java/misc/migration/v1_2/OtoChild.java +++ b/src/test/java/misc/migration/v1_2/OtoChild.java @@ -9,10 +9,10 @@ import javax.persistence.Table; import static io.ebean.annotation.Platform.MYSQL; import static io.ebean.annotation.Platform.POSTGRES; -@Index(name = "ix_m12_otoc71", columnNames = "foo(name)", platforms = {POSTGRES}) -@Index(name = "ix_m12_otoc72", columnNames = "bar(name)", platforms = {MYSQL}) -@Index(unique = true, name = "uq_m12_otoc71", columnNames = "uqFoo(name)", platforms = {POSTGRES}) -@Index(unique = true, name = "uq_m12_otoc72", columnNames = "uqBar(name)", platforms = {MYSQL}) +@Index(name = "ix_m12_otoc71", columnNames = "name", platforms = {POSTGRES}) +@Index(name = "ix_m12_otoc72", columnNames = "name", platforms = {MYSQL}) +@Index(unique = true, name = "uq_m12_otoc71", columnNames = "lower(name)", platforms = {POSTGRES}) +@Index(unique = true, name = "uq_m12_otoc72", columnNames = "name", platforms = {MYSQL}) @Index(columnNames = "name", platforms = POSTGRES) @Entity @Table(name = "migtest_oto_child") diff --git a/src/test/java/misc/migration/v1_2/OtoMaster.java b/src/test/java/misc/migration/v1_2/OtoMaster.java index 956975a3a..ef7f78cba 100644 --- a/src/test/java/misc/migration/v1_2/OtoMaster.java +++ b/src/test/java/misc/migration/v1_2/OtoMaster.java @@ -9,10 +9,9 @@ import javax.persistence.Table; import static io.ebean.annotation.Platform.MYSQL; import static io.ebean.annotation.Platform.POSTGRES; -@Index(columnNames = "foo(name)", platforms = {POSTGRES}) -@Index(columnNames = "bar(name)", platforms = {MYSQL}) -@Index(unique = true, columnNames = "foo(name)", platforms = {POSTGRES}) -@Index(unique = true, columnNames = "bar(name)", platforms = {MYSQL}) +@Index(columnNames = "name", platforms = {MYSQL}) +@Index(unique = true, columnNames = "lower(name)", platforms = {POSTGRES}) +@Index(unique = true, columnNames = "name", platforms = {MYSQL}) @Entity @Table(name = "migtest_oto_master") public class OtoMaster { diff --git a/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml index 40a65505b..77171547d 100644 --- a/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml +++ b/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml @@ -38,16 +38,15 @@ - - - - + + - - - - + + + + + diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql index e6136deca..593f0f3c0 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql @@ -58,12 +58,12 @@ alter table migtest_e_history6 modify test_number1 integer; update migtest_e_history6 set test_number2 = 7 where test_number2 is null; alter table migtest_e_history6 alter test_number2 set default 7; alter table migtest_e_history6 modify test_number2 integer not null; -alter table migtest_oto_child add constraint uq_m12_otoc72 unique (uqbar(name)); -alter table migtest_oto_master add constraint uq_migtest_oto_master_barname unique (bar(name)); +alter table migtest_oto_child add constraint uq_m12_otoc72 unique (name); +alter table migtest_oto_master add constraint uq_migtest_oto_master_name unique (name); create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -create index ix_m12_otoc72 on migtest_oto_child (bar(name)); -create index ix_migtest_oto_master_barname on migtest_oto_master (bar(name)); +create index ix_m12_otoc72 on migtest_oto_child (name); +create index ix_migtest_oto_master_name on migtest_oto_master (name); drop index ix_migtest_e_basic_indextest3 on migtest_e_basic; drop index ix_migtest_e_basic_indextest6 on migtest_e_basic; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql index 492c619e3..d3e5a0b37 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql @@ -66,12 +66,11 @@ alter table migtest_e_history6 alter column test_number1 drop not null; update migtest_e_history6 set test_number2 = 7 where test_number2 is null; alter table migtest_e_history6 alter column test_number2 set default 7; alter table migtest_e_history6 alter column test_number2 set not null; -alter table migtest_oto_child add constraint uq_m12_otoc71 unique (uqfoo(name)); -alter table migtest_oto_master add constraint uq_migtest_oto_master_fooname unique (foo(name)); create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -create index ix_m12_otoc71 on migtest_oto_child (foo(name)); -create index ix_migtest_oto_master_fooname on migtest_oto_master (foo(name)); +create index ix_m12_otoc71 on migtest_oto_child (name); +create unique index uq_m12_otoc71 on migtest_oto_child (lower(name)); +create unique index ix_migtest_oto_master_lowername on migtest_oto_master (lower(name)); drop index if exists ix_migtest_e_basic_indextest3; drop index if exists ix_migtest_e_basic_indextest6; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id);