diff --git a/pom.xml b/pom.xml
index bec721071..591f8b9e4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,7 +118,7 @@
io.ebean
ebean-annotation
- 6.3
+ 6.4
@@ -136,7 +136,7 @@
io.ebean
ebean-migration
- 12.1.3
+ 12.1.4
diff --git a/src/main/java/io/ebean/ScriptRunner.java b/src/main/java/io/ebean/ScriptRunner.java
index 2336d1628..15057741e 100644
--- a/src/main/java/io/ebean/ScriptRunner.java
+++ b/src/main/java/io/ebean/ScriptRunner.java
@@ -50,4 +50,13 @@ public interface ScriptRunner {
*/
void run(URL resource, Map placeholderMap);
+ /**
+ * Run the raw provided DDL or SQL script.
+ *
+ * @param name The name of the script for logging purposes
+ * @param content The SQL content
+ * @param useAutoCommit Set to true to use auto commit true and continue when any errors occur
+ */
+ void runScript(String name, String content, boolean useAutoCommit);
+
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
index ebc8b9ded..95ed4c942 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
@@ -182,7 +182,7 @@ public class DdlGenerator {
}
private DdlRunner createDdlRunner(boolean expectErrors, String scriptName) {
- return new DdlRunner(expectErrors, scriptName, DdlAutoCommit.forPlatform(platformName));
+ return new DdlRunner(expectErrors, scriptName, platformName);
}
protected void runDropSql(Connection connection) throws IOException {
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 3d7e74065..b7622de18 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(), false));
+ fkeyBuffer.appendStatement(platformDdl.createIndex(new WriteCreateIndex(request.indexName(), tableName, request.cols(), false)));
}
alterTableAddForeignKey(write.getOptions(), fkeyBuffer, request);
@@ -611,15 +611,15 @@ public class BaseTableDdl implements TableDdl {
@Override
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()));
+ writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index)));
+ writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent())));
}
}
@Override
public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException {
if (platformInclude(dropIndex.getPlatforms())) {
- writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName()));
+ writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent())));
}
}
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 ee3fe32eb..f9f943385 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/ClickHouseDdl.java
@@ -56,12 +56,12 @@ public class ClickHouseDdl extends PlatformDdl {
}
@Override
- public String dropIndex(String indexName, String tableName) {
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
return null;
}
@Override
- public String createIndex(String indexName, String tableName, String[] columns, boolean unique) {
+ public String createIndex(WriteCreateIndex create) {
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 39fee3dd3..872fc3930 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java
@@ -13,25 +13,24 @@ public class HanaColumnStoreDdl extends AbstractHanaDdl {
}
@Override
- public String createIndex(String indexName, String tableName, String[] columns, boolean unique) {
+ public String createIndex(WriteCreateIndex create) {
+ final String[] columns = create.getColumns();
if (columns == null || columns.length == 0) {
return "-- cannot create index: no columns given";
}
-
if (columns.length == 1) {
- return "-- explicit index \"" + indexName + "\" for single column \"" + columns[0] + "\" of table \"" + tableName
+ return "-- explicit index \"" + create.getIndexName() + "\" for single column \"" + columns[0] + "\" of table \"" + create.getTableName()
+ "\" is not necessary";
}
StringBuilder buffer = new StringBuilder();
- buffer.append("create inverted hash index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
+ buffer.append("create inverted hash index ").append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
appendColumns(columns, buffer);
-
return buffer.toString();
}
@Override
- public String dropIndex(String indexName, String tableName) {
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
DdlBuffer buffer = new BaseDdlBuffer(null);
try {
buffer.append("delimiter $$").newLine();
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java
index 4db6d6bff..d0009c0e4 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java
@@ -30,7 +30,7 @@ public class MySqlDdl extends PlatformDdl {
* Return the drop index statement.
*/
@Override
- public String dropIndex(String indexName, String tableName) {
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
return "drop index " + maxConstraintName(indexName) + " on " + tableName;
}
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 9d59faa5e..dc99cbed5 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java
@@ -110,6 +110,7 @@ public class PlatformDdl {
protected String addForeignKeySkipCheck = "";
protected String uniqueIndex = "unique";
+ protected String indexConcurrent = "";
/**
* Set false for MsSqlServer to allow multiple nulls for OneToOne mapping.
@@ -382,23 +383,34 @@ public class PlatformDdl {
}
/**
- * Return the drop index statement.
+ * Return the drop index statement for known non concurrent index.
*/
public String dropIndex(String indexName, String tableName) {
- return dropIndexIfExists + maxConstraintName(indexName);
+ return dropIndex(indexName, tableName, false);
}
/**
- * Return the create index statement.
+ * Return the drop index statement.
*/
- public String createIndex(String indexName, String tableName, String[] columns, boolean unique) {
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
+ return dropIndexIfExists + maxConstraintName(indexName);
+ }
+
+ public String createIndex(WriteCreateIndex create) {
+ if (create.useDefinition()) {
+ return create.getDefinition();
+ }
StringBuilder buffer = new StringBuilder();
buffer.append("create ");
- if (unique) {
+ if (create.isUnique()) {
buffer.append(uniqueIndex).append(" ");
}
- buffer.append("index ").append(maxConstraintName(indexName)).append(" on ").append(tableName);
- appendColumns(columns, buffer);
+ buffer.append("index ");
+ if (create.isConcurrent()) {
+ buffer.append(indexConcurrent);
+ }
+ buffer.append(maxConstraintName(create.getIndexName())).append(" on ").append(create.getTableName());
+ appendColumns(create.getColumns(), buffer);
return buffer.toString();
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java
index 017f8f4fb..8a36b57b7 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java
@@ -10,6 +10,8 @@ import java.io.IOException;
*/
public class PostgresDdl extends PlatformDdl {
+ private static final String dropIndexConcurrentlyIfExists = "drop index concurrently if exists ";
+
public PostgresDdl(DatabasePlatform platform) {
super(platform);
this.historyDdl = new PostgresHistoryDdl();
@@ -18,6 +20,7 @@ public class PostgresDdl extends PlatformDdl {
this.alterTableIfExists = "if exists ";
this.columnSetNull = "drop not null";
this.addForeignKeySkipCheck = " not valid";
+ this.indexConcurrent = "concurrently ";
}
public String setLockTimeout(int lockTimeoutSeconds) {
@@ -39,7 +42,6 @@ public class PostgresDdl extends PlatformDdl {
*/
@Override
public String asIdentityColumn(String columnDefn) {
-
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "bigserial";
}
@@ -56,4 +58,9 @@ public class PostgresDdl extends PlatformDdl {
public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException {
apply.append(" partition by range (").append(partitionColumn).append(")");
}
+
+ @Override
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
+ return (concurrent ? dropIndexConcurrentlyIfExists : dropIndexIfExists) + maxConstraintName(indexName);
+ }
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java
index 0db74278f..7dc2a2fba 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java
@@ -58,7 +58,7 @@ public class SqlServerDdl extends PlatformDdl {
}
@Override
- public String dropIndex(String indexName, String tableName) {
+ public String dropIndex(String indexName, String tableName, boolean concurrent) {
return "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('" + tableName + "','U') AND name = '"
+ maxConstraintName(indexName) + "') drop index " + maxConstraintName(indexName) + " ON " + tableName;
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java
new file mode 100644
index 000000000..c743c979c
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteCreateIndex.java
@@ -0,0 +1,61 @@
+package io.ebeaninternal.dbmigration.ddlgeneration.platform;
+
+import io.ebeaninternal.dbmigration.migration.CreateIndex;
+
+import static io.ebeaninternal.dbmigration.ddlgeneration.platform.SplitColumns.split;
+
+class WriteCreateIndex {
+
+ private final String indexName;
+ private final String tableName;
+ private final String[] columns;
+ private final boolean unique;
+ private final boolean concurrent;
+ private final String definition;
+
+ WriteCreateIndex(String indexName, String tableName, String[] columns, boolean unique) {
+ this.indexName = indexName;
+ this.tableName = tableName;
+ this.columns = columns;
+ this.unique = unique;
+ this.concurrent = false;
+ this.definition = null;
+ }
+
+ public WriteCreateIndex(CreateIndex index) {
+ this.indexName = index.getIndexName();
+ this.tableName = index.getTableName();
+ this.columns = split(index.getColumns());
+ this.unique = Boolean.TRUE.equals(index.isUnique());
+ this.concurrent = Boolean.TRUE.equals(index.isConcurrent());
+ this.definition = index.getDefinition();
+ }
+
+ public String getIndexName() {
+ return indexName;
+ }
+
+ public String getTableName() {
+ return tableName;
+ }
+
+ public String[] getColumns() {
+ return columns;
+ }
+
+ public boolean isUnique() {
+ return unique;
+ }
+
+ public boolean isConcurrent() {
+ return concurrent;
+ }
+
+ public String getDefinition() {
+ return definition;
+ }
+
+ public boolean useDefinition() {
+ return definition != null && !definition.isEmpty();
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/AddUniqueConstraint.java b/src/main/java/io/ebeaninternal/dbmigration/migration/AddUniqueConstraint.java
index c98c28b59..5041a194e 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/migration/AddUniqueConstraint.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/migration/AddUniqueConstraint.java
@@ -146,16 +146,23 @@ public class AddUniqueConstraint {
}
/**
- * Return the platforms.
+ * Gets the value of the platforms property.
+ *
+ * @return possible object is
+ * {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
- * Set the platforms.
+ * Sets the value of the platforms property.
+ *
+ * @param value allowed object is
+ * {@link String }
*/
- public void setPlatforms(String platforms) {
- this.platforms = platforms;
+ public void setPlatforms(String value) {
+ this.platforms = value;
}
+
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java
index de0cdb0e3..d3c796c8c 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateIndex.java
@@ -20,6 +20,8 @@ import javax.xml.bind.annotation.XmlType;
* <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="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="definition" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
@@ -39,6 +41,10 @@ public class CreateIndex {
protected String columns;
@XmlAttribute(name = "unique")
protected Boolean unique;
+ @XmlAttribute(name = "concurrent")
+ protected Boolean concurrent;
+ @XmlAttribute(name = "definition")
+ protected String definition;
@XmlAttribute(name = "platforms")
protected String platforms;
@@ -103,30 +109,83 @@ public class CreateIndex {
}
/**
- * Return the unique property.
+ * Gets the value of the unique property.
+ *
+ * @return possible object is
+ * {@link Boolean }
*/
public Boolean isUnique() {
return unique;
}
/**
- * Set the unique property.
+ * Sets the value of the unique property.
+ *
+ * @param value allowed object is
+ * {@link Boolean }
*/
- public void setUnique(Boolean unique) {
- this.unique = unique;
+ public void setUnique(Boolean value) {
+ this.unique = value;
}
/**
- * Return the platforms.
+ * Gets the value of the concurrent property.
+ *
+ * @return possible object is
+ * {@link Boolean }
+ */
+ public Boolean isConcurrent() {
+ return concurrent;
+ }
+
+ /**
+ * Sets the value of the concurrent property.
+ *
+ * @param value allowed object is
+ * {@link Boolean }
+ */
+ public void setConcurrent(Boolean value) {
+ this.concurrent = value;
+ }
+
+ /**
+ * Gets the value of the definition property.
+ *
+ * @return possible object is
+ * {@link String }
+ */
+ public String getDefinition() {
+ return definition;
+ }
+
+ /**
+ * Sets the value of the definition property.
+ *
+ * @param value allowed object is
+ * {@link String }
+ */
+ public void setDefinition(String value) {
+ this.definition = value;
+ }
+
+ /**
+ * Gets the value of the platforms property.
+ *
+ * @return possible object is
+ * {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
- * Set the platforms.
+ * Sets the value of the platforms property.
+ *
+ * @param value allowed object is
+ * {@link String }
*/
- public void setPlatforms(String platforms) {
- this.platforms = platforms;
+ public void setPlatforms(String value) {
+ this.platforms = value;
}
+
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateTable.java b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateTable.java
index c088ffc09..3e52db4a1 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/migration/CreateTable.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/migration/CreateTable.java
@@ -37,6 +37,7 @@ import java.util.List;
* <attribute name="sequenceInitial" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
* <attribute name="sequenceAllocate" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
* <attribute name="pkName" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="storageEngine" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
* </complexType>
diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/DropIndex.java b/src/main/java/io/ebeaninternal/dbmigration/migration/DropIndex.java
index c05b92a78..201634741 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/migration/DropIndex.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/migration/DropIndex.java
@@ -18,6 +18,7 @@ import javax.xml.bind.annotation.XmlType;
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <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="concurrent" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* <attribute name="platforms" type="{http://www.w3.org/2001/XMLSchema}string" />
* </restriction>
* </complexContent>
@@ -33,6 +34,8 @@ public class DropIndex {
protected String indexName;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
+ @XmlAttribute(name = "concurrent")
+ protected Boolean concurrent;
@XmlAttribute(name = "platforms")
protected String platforms;
@@ -77,16 +80,43 @@ public class DropIndex {
}
/**
- * Return the platforms.
+ * Gets the value of the concurrent property.
+ *
+ * @return possible object is
+ * {@link Boolean }
+ */
+ public Boolean isConcurrent() {
+ return concurrent;
+ }
+
+ /**
+ * Sets the value of the concurrent property.
+ *
+ * @param value allowed object is
+ * {@link Boolean }
+ */
+ public void setConcurrent(Boolean value) {
+ this.concurrent = value;
+ }
+
+ /**
+ * Gets the value of the platforms property.
+ *
+ * @return possible object is
+ * {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
- * Set the platforms.
+ * Sets the value of the platforms property.
+ *
+ * @param value allowed object is
+ * {@link String }
*/
- public void setPlatforms(String platforms) {
- this.platforms = platforms;
+ public void setPlatforms(String value) {
+ this.platforms = value;
}
+
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/UniqueConstraint.java b/src/main/java/io/ebeaninternal/dbmigration/migration/UniqueConstraint.java
index 7f7de32f3..f4abbe7b7 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/migration/UniqueConstraint.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/migration/UniqueConstraint.java
@@ -123,16 +123,23 @@ public class UniqueConstraint {
}
/**
- * Return the platforms.
+ * Gets the value of the platforms property.
+ *
+ * @return possible object is
+ * {@link String }
*/
public String getPlatforms() {
return platforms;
}
/**
- * Set the platforms.
+ * Sets the value of the platforms property.
+ *
+ * @param value allowed object is
+ * {@link String }
*/
- public void setPlatforms(String platforms) {
- this.platforms = platforms;
+ public void setPlatforms(String value) {
+ this.platforms = value;
}
+
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java b/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java
index 08556c414..976bde5f3 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/model/MIndex.java
@@ -6,6 +6,7 @@ import io.ebeaninternal.dbmigration.migration.DropIndex;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* Index as part of the logical model.
@@ -13,14 +14,12 @@ import java.util.List;
public class MIndex {
private String tableName;
-
private String indexName;
-
private String platforms;
-
private List columns = new ArrayList<>();
-
private boolean unique;
+ private boolean concurrent;
+ private String definition;
/**
* Create a single column non unique index.
@@ -31,12 +30,6 @@ public class MIndex {
this.columns.add(columnName);
}
- public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique) {
- this(indexName, tableName, columnNames);
- this.platforms = platforms;
- this.unique = unique;
- }
-
/**
* Create a multi column non unique index.
*/
@@ -46,12 +39,22 @@ public class MIndex {
Collections.addAll(this.columns, columnNames);
}
+ public MIndex(String indexName, String tableName, String[] columnNames, String platforms, boolean unique, boolean concurrent, String definition) {
+ this(indexName, tableName, columnNames);
+ this.platforms = platforms;
+ this.unique = unique;
+ this.concurrent = concurrent;
+ this.definition = emptyToNull(definition);
+ }
+
public MIndex(CreateIndex createIndex) {
this.indexName = createIndex.getIndexName();
this.tableName = createIndex.getTableName();
this.columns = split(createIndex.getColumns());
this.platforms = createIndex.getPlatforms();
this.unique = Boolean.TRUE.equals(createIndex.isUnique());
+ this.concurrent = Boolean.TRUE.equals(createIndex.isConcurrent());
+ this.definition = emptyToNull(createIndex.getDefinition());
}
public String getKey() {
@@ -92,9 +95,20 @@ public class MIndex {
if (Boolean.TRUE.equals(unique)) {
create.setUnique(Boolean.TRUE);
}
+ if (Boolean.TRUE.equals(concurrent)) {
+ create.setConcurrent(Boolean.TRUE);
+ }
+ create.setDefinition(emptyToNull(definition));
return create;
}
+ private String emptyToNull(String val) {
+ if (val == null || val.isEmpty()) {
+ return null;
+ }
+ return val;
+ }
+
/**
* Create a DropIndex migration for this index.
*/
@@ -103,6 +117,9 @@ public class MIndex {
dropIndex.setIndexName(indexName);
dropIndex.setTableName(tableName);
dropIndex.setPlatforms(platforms);
+ if (Boolean.TRUE.equals(concurrent)) {
+ dropIndex.setConcurrent(Boolean.TRUE);
+ }
return dropIndex;
}
@@ -127,6 +144,9 @@ public class MIndex {
if (unique != newIndex.unique) {
return true;
}
+ if (!Objects.equals(definition, newIndex.definition)) {
+ return true;
+ }
List newColumns = newIndex.getColumns();
if (columns.size() != newColumns.size()) {
return true;
@@ -141,6 +161,9 @@ public class MIndex {
private List split(String columns) {
+ if (columns.isEmpty()) {
+ return Collections.emptyList();
+ }
String[] cols = columns.split(",");
List colList = new ArrayList<>(cols.length);
Collections.addAll(colList, cols);
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 969a7cf23..2d474883b 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java
@@ -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()), index.isUnique());
+ return new MIndex(indexName, tableName, index.getColumns(), platforms(index.getPlatforms()), index.isUnique(), index.isConcurrent(), index.getDefinition());
}
private String platforms(Platform[] platforms) {
diff --git a/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java b/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java
index 5fdea4a9a..171f66724 100644
--- a/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java
+++ b/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java
@@ -22,9 +22,11 @@ class DScriptRunner implements ScriptRunner {
private static final String NEWLINE = "\n";
private final SpiEbeanServer server;
+ private final String platformName;
DScriptRunner(SpiEbeanServer server) {
this.server = server;
+ this.platformName = this.server.getDatabasePlatform().getPlatform().base().name();
}
@Override
@@ -56,7 +58,7 @@ class DScriptRunner implements ScriptRunner {
}
String content = content(resource);
- runScript(content, scriptName, placeholderMap);
+ runScript(content, scriptName, placeholderMap, false);
}
private String content(URL resource) {
@@ -72,21 +74,25 @@ class DScriptRunner implements ScriptRunner {
}
}
+ @Override
+ public void runScript(String name, String content, boolean useAutoCommit) {
+ runScript(content, name, null, useAutoCommit);
+ }
/**
* Execute all the DDL statements in the script.
*/
- private void runScript(String content, String scriptName, Map placeholderMap) {
-
+ private void runScript(String content, String scriptName, Map placeholderMap, boolean useAutoCommit) {
try {
if (placeholderMap != null) {
content = ScriptTransform.build(null, placeholderMap).transform(content);
}
try (Connection connection = obtainConnection()) {
- DdlRunner runner = new DdlRunner(false, scriptName);
+ DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName);
runner.runAll(content, connection);
connection.commit();
+ runner.runNonTransactional(connection);
}
} catch (SQLException e) {
diff --git a/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java b/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java
index 65bf62665..3fec7ecf4 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/IndexDefinition.java
@@ -8,21 +8,22 @@ import io.ebean.annotation.Platform;
public class IndexDefinition {
private final String[] columns;
-
private final String name;
-
private final Platform[] platforms;
-
private final boolean unique;
+ private final boolean concurrent;
+ private final String definition;
/**
* Create from Index annotation.
*/
- public IndexDefinition(String[] columns, String name, boolean unique, Platform[] platforms) {
+ public IndexDefinition(String[] columns, String name, boolean unique, Platform[] platforms, boolean concurrent, String definition) {
this.columns = columns;
this.unique = unique;
this.name = name;
this.platforms = platforms;
+ this.concurrent = concurrent;
+ this.definition = definition;
}
/**
@@ -33,13 +34,19 @@ public class IndexDefinition {
this.unique = true;
this.name = null;
this.platforms = null;
+ this.concurrent = false;
+ this.definition = null;
}
/**
* Return true if this can be used as a unique constraint.
*/
public boolean isUniqueConstraint() {
- return unique && noColumnFormulas();
+ return unique && !concurrent && noDefinition() && noColumnFormulas();
+ }
+
+ private boolean noDefinition() {
+ return definition == null || definition.isEmpty();
}
private boolean noColumnFormulas() {
@@ -78,4 +85,18 @@ public class IndexDefinition {
public Platform[] getPlatforms() {
return platforms;
}
+
+ /**
+ * Return true if this index has the concurrent flag.
+ */
+ public boolean isConcurrent() {
+ return concurrent;
+ }
+
+ /**
+ * Return the raw definition of the index if supplied.
+ */
+ public String getDefinition() {
+ return definition;
+ }
}
diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java
index 3281b258a..a20943388 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java
@@ -134,7 +134,8 @@ public class AnnotationClass extends AnnotationParser {
}
for (Index index : findAnnotationsRecursive(cls, Index.class)) {
- descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(), index.unique(), index.platforms()));
+ descriptor.addIndex(new IndexDefinition(convertColumnNames(index.columnNames()), index.name(),
+ index.unique(), index.platforms(), index.concurrent(), index.definition()));
}
UniqueConstraint uc = findAnnotationRecursive(cls, UniqueConstraint.class);
diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java
index 73e34f9df..3def9df45 100644
--- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java
+++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java
@@ -416,7 +416,7 @@ public class AnnotationFields extends AnnotationParser {
if (columnNames.length == 1 && hasRelationshipItem(prop)) {
throw new RuntimeException("Can't use Index on foreign key relationships.");
}
- descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique(), index.platforms()));
+ descriptor.addIndex(new IndexDefinition(columnNames, index.name(), index.unique(), index.platforms(), index.concurrent(), index.definition()));
}
private void readJsonAnnotations(DeployBeanProperty prop) {
diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd
index 73d7e91ef..16489724a 100644
--- a/src/main/resources/ebean-dbmigration-1.0.xsd
+++ b/src/main/resources/ebean-dbmigration-1.0.xsd
@@ -291,6 +291,8 @@
+
+
@@ -299,6 +301,7 @@
+
diff --git a/src/test/ddl-review/pg-create-all.sql b/src/test/ddl-review/pg-create-all.sql
index d0fd6457c..996afc929 100644
--- a/src/test/ddl-review/pg-create-all.sql
+++ b/src/test/ddl-review/pg-create-all.sql
@@ -1,4 +1,4 @@
--- Generated by ebean unknown at 2020-01-29T03:48:48.954541Z
+-- Generated by ebean unknown at 2020-01-29T03:58:42.859353Z
create table asimple_bean (
id bigserial not null,
name varchar(255),
@@ -3980,6 +3980,8 @@ create index ix_e_basic_name on e_basic (name);
create index ix_efile2_no_fk_owner_id on efile2_no_fk (owner_id);
create index ix_ecsm_values_host_id on ecsm_values (host_id);
create index ix_organization_node_kind on organization_node (kind);
+create unique index concurrently ix_t_detail_with_other_namexxxyy_lowername on t_detail_with_other_namexxxyy (lower(name));
+create index ix_t_detail_with_other_namexxxyy_defn on t_detail_with_other_namexxxyy using hash (lower(name)) where lower(name) like 'r%';
create index ix_bar_foo_id on bar (foo_id);
alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict;
diff --git a/src/test/ddl-review/pg-drop-all.sql b/src/test/ddl-review/pg-drop-all.sql
index 6fb3709bb..df6f5815b 100644
--- a/src/test/ddl-review/pg-drop-all.sql
+++ b/src/test/ddl-review/pg-drop-all.sql
@@ -1,4 +1,4 @@
--- Generated by ebean unknown at 2020-01-29T03:48:48.954541Z
+-- Generated by ebean unknown at 2020-01-29T03:58:42.859353Z
alter table if exists bar drop constraint if exists fk_bar_foo_id;
drop index if exists ix_bar_foo_id;
@@ -1876,3 +1876,5 @@ drop index if exists ix_e_basic_name;
drop index if exists ix_efile2_no_fk_owner_id;
drop index if exists ix_ecsm_values_host_id;
drop index if exists ix_organization_node_kind;
+drop index concurrently if exists ix_t_detail_with_other_namexxxyy_lowername;
+drop index if exists ix_t_detail_with_other_namexxxyy_defn;
diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
index 4be34902a..53c477266 100644
--- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
+++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
@@ -3,17 +3,12 @@ package io.ebeaninternal.dbmigration;
import io.ebean.BaseTestCase;
import io.ebean.SqlRow;
import io.ebean.SqlUpdate;
-import io.ebean.Transaction;
import io.ebean.annotation.IgnorePlatform;
import io.ebean.annotation.Platform;
-import io.ebean.migration.ddl.DdlRunner;
import io.ebeaninternal.dbmigration.ddlgeneration.Helper;
import org.junit.Test;
-import javax.persistence.PersistenceException;
import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -25,28 +20,8 @@ public class DbMigrationTest extends BaseTestCase {
runScript(expectErrors, ddl, scriptName);
}
- private void runScript(boolean expectErrors, String content, String scriptName) {
-
- DdlRunner runner = new DdlRunner(expectErrors, scriptName);
-
- Transaction transaction = server().createTransaction();
- Connection connection = transaction.getConnection();
- try {
- if (expectErrors) {
- connection.setAutoCommit(true);
- }
- runner.runAll(content, connection);
- if (expectErrors) {
- connection.setAutoCommit(false);
- }
- transaction.commit();
-
- } catch (SQLException e) {
- throw new PersistenceException("Failed to run script", e);
-
- } finally {
- transaction.end();
- }
+ private void runScript(boolean useAutoCommit, String content, String scriptName) {
+ server().script().runScript(scriptName, content, useAutoCommit);
}
@IgnorePlatform({Platform.ORACLE, Platform.NUODB})
@@ -188,21 +163,29 @@ public class DbMigrationTest extends BaseTestCase {
}
private void cleanup(String ... tables) {
+
+ final boolean sqlServer = isSqlServer();
+ final boolean postgres = isPostgres();
+
StringBuilder sb = new StringBuilder();
for (String table : tables) {
// simple and stupid try to execute all commands on all dialects.
- sb.append("alter table ").append(table).append(" set ( system_versioning = OFF );\n");
- sb.append("alter table ").append(table).append(" drop system versioning;\n");
- sb.append("drop table ").append(table).append(";\n");
- sb.append("drop table ").append(table).append(" cascade;\n");
- sb.append("drop table ").append(table).append("_history;\n");
- sb.append("drop table ").append(table).append("_history cascade;\n");
+ if (sqlServer) {
+ sb.append("alter table ").append(table).append(" set ( system_versioning = OFF );\n");
+ sb.append("alter table ").append(table).append(" drop system versioning;\n");
+ }
+ if (postgres) {
+ sb.append("drop table ").append(table).append(" cascade;\n");
+ sb.append("drop table ").append(table).append("_history cascade;\n");
+ } else {
+ sb.append("drop table ").append(table).append(";\n");
+ sb.append("drop table ").append(table).append("_history;\n");
+ }
sb.append("drop view ").append(table).append("_with_history;\n");
sb.append("drop sequence ").append(table).append("_seq;\n");
}
runScript(true, sb.toString(), "cleanup");
runScript(true, sb.toString(), "cleanup");
-
}
}
diff --git a/src/test/java/io/ebeaninternal/server/deploy/IndexDefinitionTest.java b/src/test/java/io/ebeaninternal/server/deploy/IndexDefinitionTest.java
new file mode 100644
index 000000000..cf206edaf
--- /dev/null
+++ b/src/test/java/io/ebeaninternal/server/deploy/IndexDefinitionTest.java
@@ -0,0 +1,41 @@
+package io.ebeaninternal.server.deploy;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class IndexDefinitionTest {
+
+ private static final String[] simpleCol1 = new String[]{"one"};
+ private static final String[] simpleCol2 = new String[]{"one","two"};
+ private static final String[] formulaCol1 = new String[]{"lower(one)"};
+ private static final String[] formulaCol2 = new String[]{"one","lower(two)"};
+
+ @Test
+ public void isUniqueConstraint_TRUE_when_simpleMultiColumn() {
+ assertTrue(new IndexDefinition(simpleCol1).isUniqueConstraint());
+ assertTrue(new IndexDefinition(simpleCol2).isUniqueConstraint());
+ }
+
+ @Test
+ public void isUniqueConstraint_NOT_when_columnWithFormula() {
+ assertFalse(new IndexDefinition(formulaCol1).isUniqueConstraint());
+ assertFalse(new IndexDefinition(formulaCol2).isUniqueConstraint());
+ }
+
+ @Test
+ public void isUniqueConstraint_NOT_when_concurrentTrue() {
+ assertFalse(new IndexDefinition(simpleCol1, "name", true, null, true, null).isUniqueConstraint());
+ }
+
+ @Test
+ public void isUniqueConstraint_NOT_when_definitionNotEmpty() {
+ assertFalse(new IndexDefinition(simpleCol1, "name", true, null, false, "create index foo").isUniqueConstraint());
+ }
+
+ @Test
+ public void isUniqueConstraint_TRUE_otherwise() {
+ assertTrue(new IndexDefinition(simpleCol1, "name", true, null, false, "").isUniqueConstraint());
+ assertTrue(new IndexDefinition(simpleCol1, "name", true, null, false, null).isUniqueConstraint());
+ }
+}
diff --git a/src/test/java/misc/migration/v1_0/OtoChild.java b/src/test/java/misc/migration/v1_0/OtoChild.java
index f6d23ca9e..23bc8f569 100644
--- a/src/test/java/misc/migration/v1_0/OtoChild.java
+++ b/src/test/java/misc/migration/v1_0/OtoChild.java
@@ -8,7 +8,9 @@ import javax.persistence.Table;
import static io.ebean.annotation.Platform.POSTGRES;
-@Index(columnNames = "lower(name)", platforms = POSTGRES)
+@Index(platforms = POSTGRES, name = "idxd_migtest_0", definition = "create index idxd_migtest_0 on migtest_oto_child using hash (upper(name)) where upper(name) = 'JIM'")
+@Index(platforms = POSTGRES, columnNames = {"lower(name)","id"}, concurrent = true)
+@Index(platforms = POSTGRES, columnNames = "lower(name)")
@Entity
@Table(name = "migtest_oto_child")
public class OtoChild {
diff --git a/src/test/java/org/tests/model/basic/TSDetail.java b/src/test/java/org/tests/model/basic/TSDetail.java
index 0d9de6d1b..2898ad07e 100644
--- a/src/test/java/org/tests/model/basic/TSDetail.java
+++ b/src/test/java/org/tests/model/basic/TSDetail.java
@@ -1,6 +1,7 @@
package org.tests.model.basic;
import io.ebean.annotation.Index;
+import io.ebean.annotation.Platform;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
@@ -13,7 +14,8 @@ import javax.validation.constraints.Size;
/**
* A basic entity to test simple things.
*/
-//@Index(name = "t_detail_foo_name", unique = true, columnNames = "lower(name)")
+@Index(name = "ix_t_detail_with_other_namexxxyy_lowername", unique = true, columnNames = "lower(name)", concurrent = true, platforms = Platform.POSTGRES)
+@Index(name = "ix_t_detail_with_other_namexxxyy_defn", platforms = Platform.POSTGRES, definition = "create index ix_t_detail_with_other_namexxxyy_defn on t_detail_with_other_namexxxyy using hash (lower(name)) where lower(name) like 'r%'")
@Entity
@Table(name = "t_detail_with_other_namexxxyy")
public class TSDetail {
diff --git a/src/test/java/org/tests/saveassociation/TestSaveSamePK.java b/src/test/java/org/tests/saveassociation/TestSaveSamePK.java
index fc9efabeb..e2a21562d 100644
--- a/src/test/java/org/tests/saveassociation/TestSaveSamePK.java
+++ b/src/test/java/org/tests/saveassociation/TestSaveSamePK.java
@@ -1,11 +1,12 @@
package org.tests.saveassociation;
import io.ebean.BaseTestCase;
-import io.ebean.Ebean;
+import io.ebean.DB;
+import org.junit.Test;
import org.tests.model.basic.TSDetail;
import org.tests.model.basic.TSMaster;
-import org.junit.Assert;
-import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
public class TestSaveSamePK extends BaseTestCase {
@@ -13,22 +14,22 @@ public class TestSaveSamePK extends BaseTestCase {
public void test() {
// delete in case we are running multiple times without full db drop
- Ebean.delete(TSMaster.class, 10000);
+ DB.delete(TSMaster.class, 10000);
TSMaster m0 = new TSMaster();
m0.setId(10000);
m0.setName("master1");
- Ebean.save(m0);
+ DB.save(m0);
- TSDetail tsDetail = new TSDetail("master1 detail1");
+ TSDetail tsDetail = new TSDetail("m4 d1");
tsDetail.setId(10000);
tsDetail.setMaster(m0);
- Ebean.save(tsDetail);
+ DB.save(tsDetail);
- TSDetail fetchedDetail = Ebean.find(TSDetail.class).setId(10000).fetch("master").findOne();
+ TSDetail fetchedDetail = DB.find(TSDetail.class).setId(10000).fetch("master").findOne();
- Assert.assertNotNull(fetchedDetail);
+ assertNotNull(fetchedDetail);
}
}
diff --git a/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml
index 15c6708fc..68661ce4c 100644
--- a/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml
+++ b/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml
@@ -115,6 +115,8 @@
+
+
\ No newline at end of file
diff --git a/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml
index 55116e4ec..e165e05d8 100644
--- a/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml
+++ b/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml
@@ -89,6 +89,8 @@
+
+
diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql
index 22f1bae2d..fa4d80c2c 100644
--- a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql
+++ b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql
@@ -163,6 +163,8 @@ create table migtest_oto_master (
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 idxd_migtest_0 on migtest_oto_child using hash (upper(name)) where upper(name) = 'JIM';
+create index concurrently ix_migtest_oto_child_lowername_id on migtest_oto_child (lower(name),id);
create index ix_migtest_oto_child_lowername on migtest_oto_child (lower(name));
create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id);
alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade;
diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql
index e6f801cf5..34ec2956d 100644
--- a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql
+++ b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql
@@ -105,6 +105,8 @@ create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6);
create index ix_migtest_oto_child_name on migtest_oto_child (name);
drop index if exists ix_migtest_e_basic_indextest1;
drop index if exists ix_migtest_e_basic_indextest5;
+drop index if exists idxd_migtest_0;
+drop index concurrently if exists ix_migtest_oto_child_lowername_id;
drop index if exists ix_migtest_oto_child_lowername;
create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id);
alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict;