Use unique index rather than constraint when using formula [like lower(column)]

This commit is contained in:
rob bygrave
2020-01-15 16:58:55 +13:00
parent 099adcf6cd
commit bb56725b12
14 changed files with 84 additions and 39 deletions
@@ -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()));
}
}
@@ -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;
}
@@ -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";
}
@@ -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();
}
@@ -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.
*/
@@ -20,6 +20,8 @@ public class MIndex {
private List<String> 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<String> newColumns = newIndex.getColumns();
if (columns.size() != newColumns.size()) {
return true;
@@ -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) {
@@ -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.
*/
+2 -1
View File
@@ -283,13 +283,14 @@
</xsd:complexType>
</xsd:element>
<!-- INDEXES (Non unique) -->
<!-- INDEXES -->
<xsd:element name="createIndex">
<xsd:complexType>
<xsd:attribute name="indexName" type="xsd:string" use="required"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="columns" type="xsd:string" use="required"/>
<xsd:attribute name="unique" type="xsd:boolean"/>
<xsd:attribute name="platforms" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
@@ -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")
@@ -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 {
@@ -38,16 +38,15 @@
<column name="name" type="varchar(127)" notnull="true"/>
<uniqueConstraint name="uq_migtest_e_ref_name" columnNames="name" oneToOne="false" nullableColumns=""/>
</createTable>
<addUniqueConstraint constraintName="uq_m12_otoc71" tableName="migtest_oto_child" columnNames="uqFoo(name)" oneToOne="false" nullableColumns="" platforms="POSTGRES"/>
<addUniqueConstraint constraintName="uq_m12_otoc72" tableName="migtest_oto_child" columnNames="uqBar(name)" oneToOne="false" nullableColumns="" platforms="MYSQL"/>
<addUniqueConstraint constraintName="uq_migtest_oto_master_fooname" tableName="migtest_oto_master" columnNames="foo(name)" oneToOne="false" nullableColumns="" platforms="POSTGRES"/>
<addUniqueConstraint constraintName="uq_migtest_oto_master_barname" tableName="migtest_oto_master" columnNames="bar(name)" oneToOne="false" nullableColumns="" platforms="MYSQL"/>
<addUniqueConstraint constraintName="uq_m12_otoc72" tableName="migtest_oto_child" columnNames="name" oneToOne="false" nullableColumns="name" platforms="MYSQL"/>
<addUniqueConstraint constraintName="uq_migtest_oto_master_name" tableName="migtest_oto_master" columnNames="name" oneToOne="false" nullableColumns="name" platforms="MYSQL"/>
<createIndex indexName="ix_migtest_e_basic_indextest1" tableName="migtest_e_basic" columns="indextest1"/>
<createIndex indexName="ix_migtest_e_basic_indextest5" tableName="migtest_e_basic" columns="indextest5"/>
<createIndex indexName="ix_m12_otoc71" tableName="migtest_oto_child" columns="foo(name)" platforms="POSTGRES"/>
<createIndex indexName="ix_m12_otoc72" tableName="migtest_oto_child" columns="bar(name)" platforms="MYSQL"/>
<createIndex indexName="ix_migtest_oto_master_fooname" tableName="migtest_oto_master" columns="foo(name)" platforms="POSTGRES"/>
<createIndex indexName="ix_migtest_oto_master_barname" tableName="migtest_oto_master" columns="bar(name)" platforms="MYSQL"/>
<createIndex indexName="ix_m12_otoc71" tableName="migtest_oto_child" columns="name" platforms="POSTGRES"/>
<createIndex indexName="ix_m12_otoc72" tableName="migtest_oto_child" columns="name" platforms="MYSQL"/>
<createIndex indexName="uq_m12_otoc71" tableName="migtest_oto_child" columns="lower(name)" unique="true" platforms="POSTGRES"/>
<createIndex indexName="ix_migtest_oto_master_name" tableName="migtest_oto_master" columns="name" platforms="MYSQL"/>
<createIndex indexName="ix_migtest_oto_master_lowername" tableName="migtest_oto_master" columns="lower(name)" unique="true" platforms="POSTGRES"/>
<dropIndex indexName="ix_migtest_e_basic_indextest3" tableName="migtest_e_basic"/>
<dropIndex indexName="ix_migtest_e_basic_indextest6" tableName="migtest_e_basic"/>
</changeSet>
@@ -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);
@@ -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);