diff --git a/dbmigration-test/resources/dbmigration/myapp/migration-current.xml b/dbmigration-test/resources/dbmigration/myapp/migration-current.xml index bda435bc4..b84a2864e 100644 --- a/dbmigration-test/resources/dbmigration/myapp/migration-current.xml +++ b/dbmigration-test/resources/dbmigration/myapp/migration-current.xml @@ -1,243 +1,243 @@ - - + + - + - - + + - - + + - - + + - + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - + - - + + - - + + - - - + + + - - + + - - + + - + - - + + - - + + - - + + - + - + - + - - + + - - + + - + - + - + - + - - + + - - + + - + - + - + - + - - + + - - + + - - + + - - + + - - - + + + - - + + - + - + - - - + + + - - + + - - + + - - + + @@ -246,149 +246,149 @@ - - + + - - - + + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - + + + - - + + - + - - + + - - + + @@ -404,11 +404,11 @@ - - + + - - + + @@ -417,46 +417,46 @@ - - + + - - + + - - - + + + - - + + - + - - + + - + - - + + - - + + @@ -464,31 +464,31 @@ - + - - + + - - + + - - + + - - - + + + - - + + @@ -496,102 +496,102 @@ - - + + - - + + - + - + - + - - + + - - + + - - + + - + - + - - + + - - + + - - + + - + - + - + - + - - + + - - + + - + - - + + - + - - + + - + - + - + - + @@ -603,449 +603,449 @@ - - + + - - + + - + - - + + - + - - + + - - + + - + - - + + - - + + - - + + - - + + - + - - + + - + - + - - - + + + - - + + - - - - - + + + + + - - + + - + - - - + + + - - + + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - + - - + + - - - + + + - - + + - - + + - - + + - + - + - - + + - + - - + + - - - + + + - - + + - + - + - + - + - - - + + + - + - - - + + + - + - + - + - + - - - + + + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - + - + - + - + - - + + - - + + - - - + + + - + - - + + - - - + + + - - + + - - - + + + - - - - + + + + - - + + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - - + + - - - + + + - - - - + + + + - - + + - + - - + + - + - - + + - + - - - + + + - - + + - - - - + + + + @@ -1057,254 +1057,254 @@ - - + + - + - - + + - - - + + + - + - - + + - + - + - + - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + - - - - - - - + - - - + + + - - + + - + - + - + - + - - - + + + - + - - + + - + - + - - - + + + - - + + - + - + - + - - + + - - + + - - + + - + - - + + - + - - - + + + - + - + - + - + - - + + - - + + - - - + + + - + - - + + - + - - + + - + - + - - + + - + - - + + - + - + - + - + diff --git a/h2-migration.xml b/h2-migration.xml index bda435bc4..7fe81141f 100644 --- a/h2-migration.xml +++ b/h2-migration.xml @@ -1,52 +1,52 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -54,189 +54,189 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - - + + - + - + @@ -246,44 +246,44 @@ - + - + - + - + - + - + - + - + @@ -291,103 +291,103 @@ - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -404,11 +404,11 @@ - + - - + + @@ -417,45 +417,45 @@ - + - + - + - + - + - + - + - + - + - + @@ -464,30 +464,30 @@ - + - + - + - + - + - + - + @@ -496,50 +496,50 @@ - + - + - + - + - + - + - + - + - + - + - + @@ -547,51 +547,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -603,191 +603,191 @@ - - + + - + - + - - + + - + - - + + - + - + - - + + - + - + - + - + - - + + - + - + - + - + - - - - - + + + + + - + - + - + - + - + - + - + - - + + - + - + - + - + - + - + - - + + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - + - + @@ -795,257 +795,257 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - + - + - + - + - + - + - - + + - + - - - + + + - + - + - + - + - + - + - + - + - - + + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - - + + - + - + - + - + - - + + - + - + - + - + - + - + - + - + - + - + - - + + @@ -1057,7 +1057,7 @@ - + @@ -1065,183 +1065,183 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + + + - + @@ -1249,60 +1249,60 @@ - + - + - + - - + + - + - + - + - - + + - + - - + + - + - + - + - + - + - + - + - + diff --git a/h2autocommit-migration.xml b/h2autocommit-migration.xml index a8b0c72f7..06e212902 100644 --- a/h2autocommit-migration.xml +++ b/h2autocommit-migration.xml @@ -1,7 +1,7 @@ - + diff --git a/h2ebasicver-migration.xml b/h2ebasicver-migration.xml index e50d3011d..4f7cc9812 100644 --- a/h2ebasicver-migration.xml +++ b/h2ebasicver-migration.xml @@ -1,7 +1,7 @@ - + diff --git a/h2other-migration.xml b/h2other-migration.xml index 9757856af..ee196535f 100644 --- a/h2other-migration.xml +++ b/h2other-migration.xml @@ -1,9 +1,9 @@ - + - + diff --git a/mysql-migration.xml b/mysql-migration.xml index a676629fb..36909edef 100644 --- a/mysql-migration.xml +++ b/mysql-migration.xml @@ -1,243 +1,243 @@ - - + + - - - - - + + + + + - - + + - - - + + + - - + + - - + + - - + + - + - - - - - + + + + + - - + + - + - - + + - - - + + + - - - - - - - + + + + + + + - - - - - + + + + + - - + + - - + + - + - - + + - - + + - - - - + + + + - - + + - - - + + + - - + + - - - - - + + + + + - - + + - - + + - + - - - + + + - - + + - - + + - - + + - - - + + + - + - - - + + + - - - + + + - - - - - + + + + + - - + + - - - - + + + + - - - + + + - + - - + + - - + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - + + - - - - + + + + - - + + - - - - + + + + - - - - - + + + + + - - + + - + - - + + @@ -246,354 +246,354 @@ - - + + - - - + + + - - + + - + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - + + - + - - + + - + - - - + + + - + - - + + - - + + - - + + - + - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - - + + - + - - + + - + - - + + - - - + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - + + + - - + + - + - - + + - - + + - - + + - - + + - - - + + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - - + + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - - + + + - - + + - + - - - + + + - + - + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - - - - + + + + - - - + + + @@ -602,450 +602,450 @@ - - - + + + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - - - - - + + + + + - - + + - - + + - - + + - - - + + + - - - - - + + + + + - - - + + + - - - + + + - - + + - - - - - - - + + + + + + + - - + + - - + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - - - - + + + + + - - - + + + - - + + - - + + - - + + - + - + - + - - + + - - - - - + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + - - - + + + - - - + + + - + - + - - + + - - + + - + - - - + + + - - - + + + - - + + - + - - + + - - + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - - + + + + - - + + - - + + - + - - - + + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - + + - - + + - - + + - + - - - - - + + + + + - - - + + + - - - + + + - + - - - + + + - + - - - - + + + + - - + + - - + + - - - - - + + + + + - - + + - - - + + + - - - - + + + + - - - + + + - - + + - - + + - - + + - + - - - - + + + + - - - + + + - - + + - + - - - - + + + + @@ -1055,256 +1055,256 @@ - + - - + + - + - - - - + + + + - - - + + + - - - + + + - - + + - + - - + + - - - + + + - - - + + + - - + + - - + + - + - - + + - - + + - + - - + + - + - - + + - - + + - - + + - - - + + + - - - + + + - - + + - + - - - + + + - - - - + + + + - - - + + + - + - - - + + + - - + + - - - + + + - - + + - - - + + + - + - - + + - + - - + + - - + + - + - - + + - - + + - - + + - - - - + + + + - - + + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - + - - + + - - + + - - - + + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - + + + - - + + - - + + - - + + - - - + + + - - - + + + diff --git a/pg-migration.xml b/pg-migration.xml index faea84ba5..b84a2864e 100644 --- a/pg-migration.xml +++ b/pg-migration.xml @@ -1,243 +1,243 @@ - - + + - - - - - + + + + + - - + + - - - + + + - - + + - - + + - - + + - + - - - - - + + + + + - - + + - + - - + + - - - + + + - - - - - - - + + + + + + + - - - - - + + + + + - - + + - - + + - + - - + + - - + + - - - - + + + + - - + + - - - + + + - - + + - - - - - + + + + + - - + + - - + + - + - - - + + + - - + + - - + + - - + + - - - + + + - + - - - + + + - - - + + + - - - - - + + + + + - - + + - - - - + + + + - - - + + + - + - - + + - - + + - - - - + + + + - - + + - - - + + + - - - + + + - - - + + + - - + + - - - - + + + + - - + + - - - - + + + + - - - - - + + + + + - - + + - + - - + + @@ -246,354 +246,354 @@ - - + + - - - + + + - - + + - + - - + + - + - - + + - - + + - - + + - + - - + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - + + - + - - + + - + - - - + + + - + - - + + - - + + - - + + - + - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - - + + - + - - + + - + - - + + - - - + + + - - + + - - - - + + + + - - + + - - - - + + + + - - + + - - - + + + - - + + - + - - + + - - + + - - + + - - + + - - - + + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - - + + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - - + + + - - + + - + - - - + + + - + - + - - + + - + - - + + - - + + - - + + - - + + - - + + - + - - - - + + + + - - - + + + @@ -602,450 +602,450 @@ - - - + + + - - + + - - - - - + + + + + - - - - - + + + + + - - + + - - - - - + + + + + - - + + - - + + - - + + - - - + + + - - - - - + + + + + - - - + + + - - - + + + - - + + - - - - - - - + + + + + + + - - + + - - + + - - - + + + - - + + - - + + - - - - - + + + + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - - - - + + + + + - - + + - + - - + + - + - - - - - + + + + + - - - + + + - - + + - - + + - - + + - + - + - + - - + + - - - - - + + + + + - - - + + + - - + + - - - + + + - - + + - - + + - - + + - - + + - - - + + + - - - + + + - - - + + + - + - + - - + + - - + + - + - - - + + + - - - + + + - - + + - + - - + + - - + + - - - - - + + + + + - - + + - - - + + + - - - + + + - - - - + + + + - - + + - - + + - + - - - + + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - + + - - + + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - - + + + + - - - - + + + + - - + + - - + + - - + + - + - - - - - + + + + + - - - + + + - - - + + + - + - - - + + + - + - - - - + + + + - - + + - - + + - - - - - + + + + + - - + + - - - + + + - - - - + + + + - - - + + + - - + + - - + + - - + + - + - - - - + + + + - - - + + + - - + + - + - - - - + + + + @@ -1055,256 +1055,256 @@ - + - - + + - + - - - - + + + + - - - + + + - - - + + + - - + + - + - - + + - - - + + + - - - + + + - - + + - - + + - + - - + + - - + + - + - - + + - + - - + + - - + + - - + + - - - + + + - - - + + + - - + + - + - - - + + + - - - - + + + + - - - + + + - + - - - + + + - - + + - - - + + + - - + + - - - + + + - + - - + + - + - - + + - - + + - + - - + + - - + + - - + + - - - - + + + + - - + + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - + - - + + - - + + - - - + + + - - - + + + - - - - - + + + + + - - - - - + + + + + - - - + + + - - - + + + - - + + - - + + - - + + - - - + + + - - - + + + diff --git a/src/main/java/com/avaje/ebean/config/AbstractNamingConvention.java b/src/main/java/com/avaje/ebean/config/AbstractNamingConvention.java index 9c5872766..733702fd7 100644 --- a/src/main/java/com/avaje/ebean/config/AbstractNamingConvention.java +++ b/src/main/java/com/avaje/ebean/config/AbstractNamingConvention.java @@ -1,12 +1,10 @@ package com.avaje.ebean.config; +import com.avaje.ebean.config.dbplatform.DatabasePlatform; + import javax.persistence.Inheritance; import javax.persistence.Table; -import com.avaje.ebean.config.dbplatform.DatabasePlatform; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Provides some base implementation for NamingConventions. * @@ -14,28 +12,39 @@ import org.slf4j.LoggerFactory; */ public abstract class AbstractNamingConvention implements NamingConvention { - /** The Constant logger. */ - private static final Logger logger = LoggerFactory.getLogger(AbstractNamingConvention.class); - - /** The Constant DEFAULT_SEQ_FORMAT. */ + /** + * The Constant DEFAULT_SEQ_FORMAT. + */ public static final String DEFAULT_SEQ_FORMAT = "{table}_seq"; - /** Sequence Format that includes the Primary Key column */ + /** + * Sequence Format that includes the Primary Key column + */ public static final String TABLE_PKCOLUMN_SEQ_FORMAT = "{table}_{column}_seq"; - /** The catalog. */ + /** + * The catalog. + */ private String catalog; - /** The schema. */ + /** + * The schema. + */ private String schema; - /** The sequence format. */ + /** + * The sequence format. + */ private String sequenceFormat; - /** The database platform. */ + /** + * The database platform. + */ protected DatabasePlatform databasePlatform; - /** Used to trim off extra prefix for M2M. */ + /** + * Used to trim off extra prefix for M2M. + */ protected int rhsPrefixLength = 3; protected boolean useForeignKeyPrefix; @@ -59,8 +68,7 @@ public abstract class AbstractNamingConvention implements NamingConvention { } /** - * Construct with the default sequence format ("{table}_seq") and - * useForeignKeyPrefix as true. + * Construct with the default sequence format ("{table}_seq") and useForeignKeyPrefix as true. */ public AbstractNamingConvention() { this(DEFAULT_SEQ_FORMAT); @@ -233,7 +241,7 @@ public abstract class AbstractNamingConvention implements NamingConvention { if (t != null && !isEmpty(t.name())) { // Note: empty catalog and schema are converted to null // Only need to convert quoted identifiers from annotations - return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name())); + return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name())); } // No annotation diff --git a/src/main/java/com/avaje/ebean/config/DbConstraintNaming.java b/src/main/java/com/avaje/ebean/config/DbConstraintNaming.java new file mode 100644 index 000000000..e46827c3a --- /dev/null +++ b/src/main/java/com/avaje/ebean/config/DbConstraintNaming.java @@ -0,0 +1,136 @@ +package com.avaje.ebean.config; + +/** + * Naming convention used for constraint names. + *

+ * Note that these constraint names are trimmed in the PlatformDdl which can be overridden + * but provides a decent default implementation. + *

+ */ +public class DbConstraintNaming { + + protected String pkPrefix = "pk_"; + protected String pkSuffix = ""; + + protected String fkPrefix = "fk_"; + protected String fkMiddle = "_"; + protected String fkSuffix = ""; + + protected String fkIndexPrefix = "ix_"; + protected String fkIndexMiddle = "_"; + protected String fkIndexSuffix = ""; + + protected String uqPrefix = "uq_"; + protected String uqSuffix = ""; + + protected String ckPrefix = "ck_"; + protected String ckSuffix = ""; + + protected boolean lowerCaseNames = true; + + protected DbConstraintNormalise normalise = new DbConstraintNormalise(); + + public DbConstraintNaming() { + } + + /** + * Return the primary key constraint name. + */ + public String primaryKeyName(String tableName) { + + return pkPrefix + normaliseTable(tableName) + pkSuffix; + } + + /** + * 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; + } + + /** + * Return the index name associated with a foreign key constraint given a single column foreign key. + */ + public String foreignKeyIndexName(String tableName, String[] columns) { + + String colPart = joinColumnNames(columns); + return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix; + } + + public String foreignKeyIndexName(String tableName, String column) { + + String colPart = normaliseTable(column); + return fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix; + } + + /** + * Join the column names together with underscores. + */ + protected String joinColumnNames(String[] columns) { + + if (columns.length == 1) { + return normaliseColumn(columns[0]); + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < columns.length; i++) { + if (i > 0) { + sb.append("_"); + } + sb.append(normaliseColumn(columns[i])); + } + return sb.toString(); + } + + /** + * Return the unique constraint name. + */ + public String uniqueConstraintName(String tableName, String columnName) { + + return uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix; + } + + /** + * Return the unique constraint name. + */ + public String uniqueConstraintName(String tableName, String[] columns) { + + String colPart = joinColumnNames(columns); + return uqPrefix + normaliseTable(tableName) + "_" + colPart + uqSuffix; + } + + /** + * Return the check constraint name. + */ + public String checkConstraintName(String tableName, String columnName) { + + return ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix; + } + + /** + * Normalise the table name by trimming catalog and schema and removing any + * quoted identifier characters (",',[,] etc). + */ + public String normaliseTable(String tableName) { + + return normalise.normaliseTable(tableName); + } + + /** + * Normalise the column name by removing any quoted identifier characters (",',[,] etc). + */ + public String normaliseColumn(String tableName) { + + return normalise.normaliseColumn(tableName); + } + + /** + * Lower case the table or column name checking for quoted identifiers. + */ + public String lowerName(String tableName) { + if (lowerCaseNames && normalise.notQuoted(tableName)) { + return tableName.toLowerCase(); + } + return tableName; + } + +} diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNameNormalise.java b/src/main/java/com/avaje/ebean/config/DbConstraintNormalise.java similarity index 59% rename from src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNameNormalise.java rename to src/main/java/com/avaje/ebean/config/DbConstraintNormalise.java index fd3f7c719..90a9ff1ff 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNameNormalise.java +++ b/src/main/java/com/avaje/ebean/config/DbConstraintNormalise.java @@ -1,24 +1,19 @@ -package com.avaje.ebean.dbmigration.ddlgeneration.platform; - -import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.DbQuotes; +package com.avaje.ebean.config; /** * Used to normalise table and column names which means stripping out * quoted identifier characters and any catalog or schema prefix. */ -public class DdlNameNormalise { +public class DbConstraintNormalise { + + protected final String[] quotedIdentifiers; protected boolean lowerCaseTables = true; protected boolean lowerCaseColumns = true; - protected DbQuotes quotes = new DbQuotes(); - - public DdlNameNormalise() { - } - - public boolean notQuoted(String tableName) { - return quotes.notQuoted(tableName); + public DbConstraintNormalise() { + this.quotedIdentifiers = new String[]{"\"", "'", "[", "]", "`"}; } /** @@ -54,9 +49,31 @@ public class DdlNameNormalise { /** * Trim off the platform quoted identifier quotes like [ ' and ". */ - protected String trimQuotes(String tableName) { + public boolean notQuoted(String tableName) { - return quotes.trimQuotes(tableName); + // remove quoted identifier characters + for (int i = 0; i < quotedIdentifiers.length; i++) { + if (tableName.contains(quotedIdentifiers[i])) { + return false; + } + } + return true; } + /** + * Trim off the platform quoted identifier quotes like [ ' and ". + */ + public String trimQuotes(String tableName) { + + if (tableName == null) { + return ""; + } + // remove quoted identifier characters + for (int i = 0; i < quotedIdentifiers.length; i++) { + tableName = tableName.replace(quotedIdentifiers[i], ""); + } + return tableName; + } + + } diff --git a/src/main/java/com/avaje/ebean/config/NamingConvention.java b/src/main/java/com/avaje/ebean/config/NamingConvention.java index 51bef545c..c20854cb3 100644 --- a/src/main/java/com/avaje/ebean/config/NamingConvention.java +++ b/src/main/java/com/avaje/ebean/config/NamingConvention.java @@ -82,8 +82,7 @@ public interface NamingConvention { String getPropertyFromColumn(Class beanClass, String dbColumnName); /** - * Return the sequence name given the table name (for DB's that use - * sequences). + * Return the sequence name given the table name (for DB's that use sequences). *

* Typically you might append "_seq" to the table name as an example. *

@@ -99,14 +98,14 @@ public interface NamingConvention { * Return true if a prefix should be used building a foreign key name. *

* This by default is true and this works well when the primary key column - * names are simply "ID". In this case a prefix (such as "ORDER" and - * "CUSTOMER" etc) is added to the foreign key column producing "ORDER_ID" and - * "CUSTOMER_ID". + * names are simply "id". In this case a prefix (such as "order" and + * "customer" etc) is added to the foreign key column producing "order_id" and + * "customer_id". *

*

* This should return false when your primary key columns are the same as the * foreign key columns. For example, when the primary key columns are - * "ORDER_ID", "CUST_ID" etc ... and they are the same as the foreign key + * "order_id", "cust_id" etc ... and they are the same as the foreign key * column names. *

*/ diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java index 29f9affe4..f52b7eea2 100644 --- a/src/main/java/com/avaje/ebean/config/ServerConfig.java +++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java @@ -239,6 +239,11 @@ public class ServerConfig { */ private NamingConvention namingConvention = new UnderscoreNamingConvention(); + /** + * Naming convention used in DDL generation for primary keys, foreign keys etc. + */ + private DbConstraintNaming constraintNaming = new DbConstraintNaming(); + /** * Behaviour of update to include on the change properties. */ @@ -975,6 +980,20 @@ public class ServerConfig { this.namingConvention = namingConvention; } + /** + * Return the constraint naming convention used in DDL generation. + */ + public DbConstraintNaming getConstraintNaming() { + return constraintNaming; + } + + /** + * Set the constraint naming convention used in DDL generation. + */ + public void setConstraintNaming(DbConstraintNaming constraintNaming) { + this.constraintNaming = constraintNaming; + } + /** * Return the configuration for the Autofetch feature. */ diff --git a/src/main/java/com/avaje/ebean/config/UnderscoreNamingConvention.java b/src/main/java/com/avaje/ebean/config/UnderscoreNamingConvention.java index 38c71da72..989e88a23 100644 --- a/src/main/java/com/avaje/ebean/config/UnderscoreNamingConvention.java +++ b/src/main/java/com/avaje/ebean/config/UnderscoreNamingConvention.java @@ -3,23 +3,26 @@ package com.avaje.ebean.config; /** * Converts between Camel Case and Underscore based names for both table and * column names (and is the default naming convention in Ebean). - * + * * @author emcgreal * @author rbygrave */ public class UnderscoreNamingConvention extends AbstractNamingConvention { - /** Force toUnderscore to return in upper case. */ + /** + * Force toUnderscore to return in upper case. + */ private boolean forceUpperCase = false; - /** The digits compressed. */ + /** + * The digits compressed. + */ private boolean digitsCompressed = true; /** * Create with a given sequence format. - * - * @param sequenceFormat - * the sequence format + * + * @param sequenceFormat the sequence format */ public UnderscoreNamingConvention(String sequenceFormat) { super(sequenceFormat); @@ -34,39 +37,30 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention { /** * Returns the last part of the class name. - * - * @param beanClass - * the bean class - * + * + * @param beanClass the bean class * @return the table name from class */ public TableName getTableNameByConvention(Class beanClass) { - return new TableName(getCatalog(), - getSchema(), - toUnderscoreFromCamel(beanClass.getSimpleName())); + return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName())); } /** * Converts Camel case property name to underscore based column name. - * + * * @return the column from property */ - public String getColumnFromProperty(Class beanClass, String propertyName) {// Field - // field) - // { + public String getColumnFromProperty(Class beanClass, String propertyName) { return toUnderscoreFromCamel(propertyName); } /** * Converts underscore based column name to Camel case property name. - * - * @param beanClass - * the bean class - * @param dbColumnName - * the db column name - * + * + * @param beanClass the bean class + * @param dbColumnName the db column name * @return the property from column */ public String getPropertyFromColumn(Class beanClass, String dbColumnName) { @@ -110,7 +104,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention { protected String toUnderscoreFromCamel(String camelCase) { int lastUpper = -1; - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(camelCase.length()+4); for (int i = 0; i < camelCase.length(); i++) { char c = camelCase.charAt(i); @@ -144,16 +138,11 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention { } /** - * To camel from underscore. - * - * @param underscore - * the underscore - * - * @return the string + * Convert and return the from string from underscore to camel case. */ protected String toCamelFromUnderscore(String underscore) { - StringBuilder result = new StringBuilder(); + StringBuilder result = new StringBuilder(underscore.length()); String[] vals = underscore.split("_"); for (int i = 0; i < vals.length; i++) { diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DB2Platform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DB2Platform.java index 028f1ed85..b3181ee32 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DB2Platform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DB2Platform.java @@ -15,6 +15,7 @@ public class DB2Platform extends DatabasePlatform { public DB2Platform() { super(); this.name = "db2"; + this.maxTableNameLength = 18; this.sqlLimiter = new Db2SqlLimiter(); this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity); diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java index 68c8b7e0e..5e5c92d11 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/DatabasePlatform.java @@ -7,6 +7,7 @@ import javax.sql.DataSource; import com.avaje.ebean.BackgroundExecutor; import com.avaje.ebean.Query; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; import org.slf4j.Logger; @@ -145,6 +146,12 @@ public class DatabasePlatform { protected PlatformDdl platformDdl; + /** + * The maximum length of table names - used specifically when derived + * default table names for intersection tables. + */ + protected int maxTableNameLength = 60; + /** * Instantiates a new database platform. */ @@ -169,7 +176,7 @@ public class DatabasePlatform { *

*/ public int getMaxTableNameLength() { - return platformDdl.getMaxTableNameLength(); + return maxTableNameLength; } /** @@ -182,8 +189,8 @@ public class DatabasePlatform { /** * Create and return a DDL handler for generating DDL scripts. */ - public DdlHandler createDdlHandler() { - return platformDdl.createDdlHandler(); + public DdlHandler createDdlHandler(ServerConfig serverConfig) { + return platformDdl.createDdlHandler(serverConfig); } /** diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java b/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java index 46282a6f9..9ef0d67f4 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/Oracle10Platform.java @@ -14,6 +14,7 @@ public class Oracle10Platform extends DatabasePlatform { public Oracle10Platform() { super(); this.name = "oracle"; + this.maxIntersectionTableName = 30; // OnQueryOnly.CLOSE as a performance optimisation on Oracle this.onQueryOnly = OnQueryOnly.CLOSE; this.dbEncrypt = new Oracle10DbEncrypt(); diff --git a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java index 92205cba5..02267058d 100644 --- a/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java +++ b/src/main/java/com/avaje/ebean/config/dbplatform/PostgresPlatform.java @@ -1,6 +1,7 @@ package com.avaje.ebean.config.dbplatform; import com.avaje.ebean.BackgroundExecutor; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl; @@ -66,8 +67,8 @@ public class PostgresPlatform extends DatabasePlatform { /** * Return a DdlHandler instance for generating DDL for the specific platform. */ - public DdlHandler createDdlHandler() { - return this.platformDdl.createDdlHandler(); + public DdlHandler createDdlHandler(ServerConfig serverConfig) { + return this.platformDdl.createDdlHandler(serverConfig); } /** diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java index 6163ec561..336f8dbce 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java @@ -30,8 +30,6 @@ public class DbMigration { this.migrationConfig = server.getServerConfig().getMigrationConfig(); } - - public void writeCurrent() { CurrentModel currentModel = new CurrentModel(server); diff --git a/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java b/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java index 637059d27..c972c1f06 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java +++ b/src/main/java/com/avaje/ebean/dbmigration/DdlGenerator.java @@ -97,10 +97,8 @@ public class DdlGenerator implements SpiEbeanPlugin { try { String c = generateDropDdl(); writeFile(dropFile, c); - } catch (IOException e) { - String msg = "Error generating Drop DDL"; - throw new PersistenceException(msg, e); + throw new PersistenceException("Error generating Drop DDL", e); } } @@ -109,10 +107,8 @@ public class DdlGenerator implements SpiEbeanPlugin { try { String c = generateCreateDdl(); writeFile(createFile, c); - } catch (IOException e) { - String msg = "Error generating Create DDL"; - throw new PersistenceException(msg, e); + throw new PersistenceException("Error generating Create DDL", e); } } @@ -213,8 +209,7 @@ public class DdlGenerator implements SpiEbeanPlugin { t.commit(); } catch (Exception e) { - String msg = "Error: " + e.getMessage(); - throw new PersistenceException(msg, e); + throw new PersistenceException("Error: " + e.getMessage(), e); } finally { t.end(); } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java index edf2cb695..357e54375 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java @@ -1,8 +1,9 @@ package com.avaje.ebean.dbmigration.ddlgeneration; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.config.NamingConvention; import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseColumnDdl; import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseTableDdl; -import com.avaje.ebean.dbmigration.ddlgeneration.platform.DdlNamingConvention; import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; import com.avaje.ebean.dbmigration.migration.AddColumn; import com.avaje.ebean.dbmigration.migration.AlterColumn; @@ -22,8 +23,8 @@ public class BaseDdlHandler implements DdlHandler { protected final TableDdl tableDdl; - public BaseDdlHandler(DdlNamingConvention namingConvention, PlatformDdl platformDdl) { - this.tableDdl = new BaseTableDdl(namingConvention, platformDdl); + public BaseDdlHandler(NamingConvention namingConvention, DbConstraintNaming naming, PlatformDdl platformDdl) { + this.tableDdl = new BaseTableDdl(namingConvention, naming, platformDdl); this.columnDdl = new BaseColumnDdl(platformDdl); } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java index f7416ff48..a0693d5c8 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java @@ -55,23 +55,22 @@ public class BaseColumnDdl implements ColumnDdl { historyIncludeColumn(writer, alterColumn); } - if (hasValue(alterColumn.getOldReferences())) { + if (hasValue(alterColumn.getDropForeignKey())) { dropForeignKey(writer, alterColumn); } - if (hasValue(alterColumn.getNewReferences())) { + if (hasValue(alterColumn.getReferences())) { addForeignKey(writer, alterColumn); } - if (isTrue(alterColumn.isUnique())) { - addUniqueConstraint(writer, alterColumn); - } else if (isFalse(alterColumn.isUnique())) { + if (hasValue(alterColumn.getDropUnique())) { dropUniqueConstraint(writer, alterColumn); } + if (hasValue(alterColumn.getUnique())) { + addUniqueConstraint(writer, alterColumn); + } - if (isTrue(alterColumn.isUniqueOneToOne())) { + if (hasValue(alterColumn.getUniqueOneToOne())) { addUniqueOneToOneConstraint(writer, alterColumn); - } else if (isFalse(alterColumn.isUniqueOneToOne())) { - dropUniqueOneToOneConstraint(writer, alterColumn); } } @@ -82,34 +81,41 @@ public class BaseColumnDdl implements ColumnDdl { } - protected void dropForeignKey(DdlWrite writer, AlterColumn alterColumn) { + protected void dropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException { + String tableName = alter.getTableName(); + String fkName = alter.getDropForeignKey(); + + writer.apply() + .append(platformDdl.alterTableDropForeignKey(tableName, fkName)) + .endOfStatement(); } - protected void dropUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alterColumn) { - - } - - protected void addUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alterColumn) { - - } protected void dropUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException { String tableName = alter.getTableName(); - String columnName = alter.getColumnName(); - String uqName = platformDdl.namingConvention.uniqueConstraintName(tableName, columnName, 50); + String uqName = alter.getDropUnique(); writer.apply() .append(platformDdl.dropIndex(uqName, tableName)) .endOfStatement(); } + protected void addUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alter) throws IOException { + + addUniqueConstraint(writer, alter, alter.getUniqueOneToOne()); + } + protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException { + addUniqueConstraint(writer, alter, alter.getUnique()); + } + + protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter, String uqName) throws IOException { + String tableName = alter.getTableName(); String columnName = alter.getColumnName(); - String uqName = platformDdl.namingConvention.uniqueConstraintName(tableName, columnName, 50); String[] cols = {columnName}; writer.apply() 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 9d740c606..b8dda019e 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 @@ -1,9 +1,13 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.config.NamingConvention; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.IdType; import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.ddlgeneration.TableDdl; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.IndexSet; import com.avaje.ebean.dbmigration.migration.Column; import com.avaje.ebean.dbmigration.migration.CreateTable; import com.avaje.ebean.dbmigration.migration.ForeignKey; @@ -19,7 +23,9 @@ import java.util.List; */ public class BaseTableDdl implements TableDdl { - protected final DdlNamingConvention namingConvention; + protected final DbConstraintNaming naming; + + protected final NamingConvention namingConvention; protected final PlatformDdl platformDdl; @@ -32,7 +38,7 @@ public class BaseTableDdl implements TableDdl { /** * Used when unique constraints specifically for OneToOne can't be created normally (MsSqlServer). */ - protected IndexSet externalUnique = new IndexSet(); + protected List externalUnique = new ArrayList(); // counters used when constraint names are truncated due to maximum length // and these counters are used to keep the constraint name unique @@ -41,11 +47,16 @@ public class BaseTableDdl implements TableDdl { protected int countForeignKey; protected int countIndex; + public BaseTableDdl(ServerConfig serverConfig, PlatformDdl platformDdl) { + this(serverConfig.getNamingConvention(), serverConfig.getConstraintNaming(), platformDdl); + } + /** * Construct with a naming convention and platform specific DDL. */ - public BaseTableDdl(DdlNamingConvention namingConvention, PlatformDdl platformDdl) { + public BaseTableDdl(NamingConvention namingConvention, DbConstraintNaming naming, PlatformDdl platformDdl) { this.namingConvention = namingConvention; + this.naming = naming; this.platformDdl = platformDdl; } @@ -74,7 +85,7 @@ public class BaseTableDdl implements TableDdl { List columns = createTable.getColumn(); List pk = determinePrimaryKeyColumns(columns); - boolean singleColumnPrimaryKey = pk.size() == 1; + boolean singleColumnPrimaryKey = (pk.size() == 1); boolean useIdentity = false; boolean useSequence = false; @@ -99,7 +110,7 @@ public class BaseTableDdl implements TableDdl { writeCompoundUniqueConstraints(apply, createTable); if (!pk.isEmpty()) { // defined on the columns - writePrimaryKeyConstraint(apply, tableName, toColumnNames(pk)); + writePrimaryKeyConstraint(apply, createTable.getPkName(), toColumnNames(pk)); } apply.newLine().append(")").endOfStatement(); @@ -111,7 +122,8 @@ public class BaseTableDdl implements TableDdl { dropTable(writer.rollback(), tableName); if (useSequence) { - writeSequence(writer, createTable); + String pkCol = singleColumnPrimaryKey ? pk.get(0).getName() : null; + writeSequence(writer, createTable, pkCol); } // add blank line for a bit of whitespace between tables @@ -133,30 +145,31 @@ public class BaseTableDdl implements TableDdl { private void writeUniqueOneToOneConstraints(DdlWrite write, CreateTable createTable) throws IOException { String tableName = createTable.getName(); - for (IndexColumns index : externalUnique.indexes) { - String uqName = determineUniqueConstraintName(tableName, index.joinedNames()); + for (Column col : externalUnique) { + String uqName = col.getUniqueOneToOne(); + String[] columnNames = {col.getName()}; write.apply() - .append(platformDdl.createExternalUniqueForOneToOne(uqName, tableName, index.columnsArray())) + .append(platformDdl.createExternalUniqueForOneToOne(uqName, tableName, columnNames)) .endOfStatement(); - // register it so we check against effective duplication - // when creating the foreign key indexes - indexSet.add(index); - write.rollbackForeignKeys() .append(platformDdl.dropIndex(uqName, tableName)) .endOfStatement(); } } - private void writeSequence(DdlWrite writer, CreateTable createTable) throws IOException { + private void writeSequence(DdlWrite writer, CreateTable createTable, String pk) throws IOException { // explicit sequence use or platform decides String explicitSequenceName = createTable.getSequenceName(); int initial = toInt(createTable.getSequenceInitial()); int allocate = toInt(createTable.getSequenceAllocate()); - String seqName = namingConvention.sequenceName(createTable.getName(), explicitSequenceName); + String seqName = explicitSequenceName; + if (seqName == null) { + seqName = namingConvention.getSequenceName(createTable.getName(), pk); + } + String createSeq = platformDdl.createSequence(seqName, initial, allocate); if (createSeq != null) { writer.apply().append(createSeq).newLine(); @@ -177,7 +190,7 @@ public class BaseTableDdl implements TableDdl { for (Column column : columns) { String references = column.getReferences(); if (hasValue(references)) { - writeForeignKey(write, tableName, column.getName(), references); + writeForeignKey(write, tableName, column); } } @@ -192,19 +205,19 @@ public class BaseTableDdl implements TableDdl { for (ForeignKey key : foreignKey) { String refTableName = key.getRefTableName(); - String fkName = determineForeignKeyConstraintName(tableName, refTableName); + String fkName = key.getName(); String[] cols = toColumnNamesSplit(key.getColumnNames()); String[] refColumns = toColumnNamesSplit(key.getRefColumnNames()); - writeForeignKey(write, fkName, tableName, cols, refTableName, refColumns); + writeForeignKey(write, fkName, tableName, cols, refTableName, refColumns, key.getIndexName()); } } - protected void writeForeignKey(DdlWrite write, String tableName, String columnName, String references) throws IOException { - - String fkName = determineForeignKeyConstraintName(tableName, columnName); + protected void writeForeignKey(DdlWrite write, String tableName, Column column) throws IOException { + String fkName = column.getForeignKeyName(); + String references = column.getReferences(); int pos = references.lastIndexOf('.'); if (pos == -1) { throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]"); @@ -212,13 +225,13 @@ public class BaseTableDdl implements TableDdl { String refTableName = references.substring(0, pos); String refColumnName = references.substring(pos + 1); - String[] cols = {columnName}; + String[] cols = {column.getName()}; String[] refCols = {refColumnName}; - writeForeignKey(write, fkName, tableName, cols, refTableName, refCols); + writeForeignKey(write, fkName, tableName, cols, refTableName, refCols, column.getForeignKeyIndex()); } - protected void writeForeignKey(DdlWrite write, String fkName, String tableName, String[] columns, String refTable, String[] refColumns) throws IOException { + protected void writeForeignKey(DdlWrite write, String fkName, String tableName, String[] columns, String refTable, String[] refColumns, String indexName) throws IOException { tableName = lowerName(tableName); DdlBuffer fkeyBuffer = write.applyForeignKeys(); @@ -234,10 +247,7 @@ public class BaseTableDdl implements TableDdl { fkeyBuffer.appendWithSpace(platformDdl.getForeignKeyRestrict()) .endOfStatement(); - String indexName = determineForeignKeyIndexName(tableName, columns); - - boolean addIndex = indexSet.add(columns); - if (addIndex) { + if (indexName != null) { // no matching unique constraint so add the index fkeyBuffer.append("create index ").append(indexName).append(" on ").append(tableName); appendColumns(columns, fkeyBuffer); @@ -250,7 +260,7 @@ public class BaseTableDdl implements TableDdl { .append(platformDdl.alterTableDropForeignKey(tableName, fkName)) .endOfStatement(); - if (addIndex) { + if (indexName != null) { write.rollbackForeignKeys() .append(platformDdl.dropIndex(indexName, tableName)) .endOfStatement(); @@ -289,7 +299,7 @@ public class BaseTableDdl implements TableDdl { for (Column column : columns) { String checkConstraint = column.getCheckConstraint(); if (hasValue(checkConstraint)) { - writeCheckConstraint(apply, createTable.getName(), column, checkConstraint); + writeCheckConstraint(apply, column, checkConstraint); } } } @@ -297,9 +307,9 @@ public class BaseTableDdl implements TableDdl { /** * Write a check constraint. */ - protected void writeCheckConstraint(DdlBuffer buffer, String tableName, Column column, String checkConstraint) throws IOException { + protected void writeCheckConstraint(DdlBuffer buffer, Column column, String checkConstraint) throws IOException { - String ckName = determineCheckConstraintName(tableName, column.getName()); + String ckName = column.getCheckConstraintName(); buffer.append(",").newLine(); buffer.append(" constraint ").append(ckName); @@ -319,11 +329,11 @@ public class BaseTableDdl implements TableDdl { List columns = createTable.getColumn(); for (Column column : columns) { - if (isTrue(column.isUnique()) || (inlineUniqueOneToOne && isTrue(column.isUniqueOneToOne()))) { + if (hasValue(column.getUnique()) || (inlineUniqueOneToOne && hasValue(column.getUniqueOneToOne()))) { // normal mechanism for adding unique constraint - inlineUniqueConstraintSingle(apply, createTable.getName(), column); - indexSet.add(column); - } else if (!inlineUniqueOneToOne && isTrue(column.isUniqueOneToOne())) { + inlineUniqueConstraintSingle(apply, column); + + } else if (!inlineUniqueOneToOne && hasValue(column.getUniqueOneToOne())) { // MsSqlServer specific mechanism for adding unique constraints (that allow nulls) externalUnique.add(column); } @@ -333,9 +343,12 @@ public class BaseTableDdl implements TableDdl { /** * Write the unique constraint inline with the create table statement. */ - protected void inlineUniqueConstraintSingle(DdlBuffer buffer, String tableName, Column column) throws IOException { + protected void inlineUniqueConstraintSingle(DdlBuffer buffer, Column column) throws IOException { - String uqName = determineUniqueConstraintName(tableName, column.getName()); + String uqName = column.getUnique(); + if (uqName == null) { + uqName = column.getUniqueOneToOne(); + } buffer.append(",").newLine(); buffer.append(" constraint ").append(uqName).append(" unique "); @@ -347,9 +360,7 @@ public class BaseTableDdl implements TableDdl { /** * Write the primary key constraint inline with the create table statement. */ - protected void writePrimaryKeyConstraint(DdlBuffer buffer, String tableName, String[] pkColumns) throws IOException { - - String pkName = determinePrimaryKeyName(tableName); + protected void writePrimaryKeyConstraint(DdlBuffer buffer, String pkName, String[] pkColumns) throws IOException { buffer.append(",").newLine(); buffer.append(" constraint ").append(pkName).append(" primary key"); @@ -383,7 +394,7 @@ public class BaseTableDdl implements TableDdl { * choice for column/table names. */ protected String lowerName(String name) { - return platformDdl.lowerName(name); + return naming.lowerName(name); } /** @@ -415,46 +426,6 @@ public class BaseTableDdl implements TableDdl { return platformDdl.convert(type, identity); } - /** - * Return the primary key constraint name. - */ - protected String determinePrimaryKeyName(String tableName) { - - return namingConvention.primaryKeyName(tableName); - } - - /** - * Return the foreign key constraint name given a single column foreign key. - */ - protected String determineForeignKeyConstraintName(String tableName, String columnName) { - - return namingConvention.foreignKeyConstraintName(tableName, columnName, ++countForeignKey); - } - - /** - * Return the foreign key constraint name given a single column foreign key. - */ - protected String determineForeignKeyIndexName(String tableName, String[] columns) { - - return namingConvention.foreignKeyIndexName(tableName, columns, ++countIndex); - } - - /** - * Return the unique constraint name. - */ - protected String determineUniqueConstraintName(String tableName, String columnName) { - - return namingConvention.uniqueConstraintName(tableName, columnName, ++countUnique); - } - - /** - * Return the constraint name. - */ - protected String determineCheckConstraintName(String tableName, String columnName) { - - return namingConvention.checkConstraintName(tableName, columnName, ++countCheck); - } - /** * Return the list of columns that make the primary key. */ @@ -489,118 +460,4 @@ 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 < indexes.size(); i++) { - if (indexes.get(i).isMatch(newIndex)) { - return false; - } - } - indexes.add(newIndex); - return true; - } - - /** - * Add the externally created unique constraint here so that we check later if foreign key indexes - * don't need to be created (as the columns match this unique constraint). - */ - public void add(IndexColumns index) { - indexes.add(index); - } - } - - /** - * Set of columns making up a particular index (column order is important). - */ - protected static class IndexColumns { - - List 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 < 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); - } - - /** - * Add a unique index based on the single column. - */ - protected void add(String column) { - columns.add(column); - } - - /** - * Return the columns as a string array. - */ - public String[] columnsArray() { - return columns.toArray(new String[columns.size()]); - } - - /** - * Return the column names all joined with underscore. - */ - public String joinedNames() { - if (columns.size() == 1) { - return columns.get(0); - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < columns.size(); i++) { - if (i > 0) { - sb.append("_"); - } - sb.append(columns.get(i)); - } - return sb.toString(); - } - } - } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DB2Ddl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DB2Ddl.java index 04dc07f0b..de16de10e 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DB2Ddl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DB2Ddl.java @@ -11,6 +11,7 @@ public class DB2Ddl extends PlatformDdl { public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); this.identitySuffix = " generated by default as identity"; + this.maxConstraintNameLength = 18; } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConvention.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConvention.java deleted file mode 100644 index 57b91eaeb..000000000 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConvention.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.avaje.ebean.dbmigration.ddlgeneration.platform; - -/** - * Naming convention used for constraint names. - */ -public class DdlNamingConvention { - - protected String pkPrefix = "pk_"; - protected String pkSuffix = ""; - - protected String fkPrefix = "fk_"; - protected String fkMiddle = "_"; - protected String fkSuffix = ""; - - protected String fkIndexPrefix = "ix_"; - protected String fkIndexMiddle = "_"; - protected String fkIndexSuffix = ""; - - protected String uqPrefix = "uq_"; - protected String uqSuffix = ""; - - protected String ckPrefix = "ck_"; - protected String ckSuffix = ""; - - protected int maxConstraintNameLength = 32; - - protected boolean lowerCaseNames = true; - - protected DdlNameNormalise normalise = new DdlNameNormalise(); - - public DdlNamingConvention() { - } - - /** - * Return the primary key constraint name. - */ - public String primaryKeyName(String tableName) { - - 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, 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, int indexCount) { - - String colPart; - if (columns.length == 1) { - colPart = normaliseColumn(columns[0]); - } else { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < columns.length; i++) { - if (i > 0) { - sb.append("_"); - } - sb.append(normaliseColumn(columns[i])); - } - colPart = sb.toString(); - } - return maxLength(fkIndexPrefix + normaliseTable(tableName) + fkIndexMiddle + colPart + fkIndexSuffix, indexCount); - } - - /** - * Return the unique constraint name. - */ - public String uniqueConstraintName(String tableName, String columnName, int indexCount) { - - return maxLength(uqPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + uqSuffix, indexCount); - } - - /** - * Return the check constraint name. - */ - public String checkConstraintName(String tableName, String columnName, int checkCount) { - - return maxLength(ckPrefix + normaliseTable(tableName) + "_" + normaliseColumn(columnName) + ckSuffix, checkCount); - } - - /** - * Return the sequence name. If it is explicitly provided return that but - * otherwise derive the sequence name from the table name. - * - * @param tableName the table the sequence relates to - * @param sequenceName an explicitly provided sequence name (typically null) - * @return the sequence name to use - */ - public String sequenceName(String tableName, String sequenceName) { - - return (sequenceName != null) ? lowerName(sequenceName) : normaliseTable(tableName) + "_seq"; - } - - /** - * Return the maximum table name length. - *

- * This is used when deriving names of intersection tables. - *

- */ - public int getMaxTableNameLength() { - return maxConstraintNameLength; - } - - /** - * 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). - */ - protected String normaliseTable(String tableName) { - - return normalise.normaliseTable(tableName); - } - - /** - * Normalise the column name by removing any quoted identifier characters (",',[,] etc). - */ - protected String normaliseColumn(String tableName) { - - return normalise.normaliseColumn(tableName); - } - - public String lowerName(String tableName) { - if (lowerCaseNames && normalise.notQuoted(tableName)) { - return tableName.toLowerCase(); - } - return tableName; - } - -} diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2Ddl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2Ddl.java index cfeaf1a1f..d274b7b66 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2Ddl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2Ddl.java @@ -10,7 +10,6 @@ public class H2Ddl extends PlatformDdl { public H2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); - this.historyDdl = new H2HistoryDdl(); } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2HistoryDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2HistoryDdl.java deleted file mode 100644 index 66161e874..000000000 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/H2HistoryDdl.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.avaje.ebean.dbmigration.ddlgeneration.platform; - -import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; -import com.avaje.ebean.dbmigration.model.MTable; - -import java.io.IOException; - -/** - * - */ -public class H2HistoryDdl implements PlatformHistoryDdl { - - @Override - public void createWithHistory(DdlWrite writer, MTable table) throws IOException { - // does nothing, not supported yet - } -} diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java index 15636f65e..8204eb8df 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java @@ -13,7 +13,6 @@ public class MsSqlServerDdl extends PlatformDdl { this.identitySuffix = " identity(1,1)"; this.foreignKeyRestrict = ""; this.inlineUniqueOneToOne = false; - this.namingConvention.maxConstraintNameLength = 62; //Actually 128 } @Override diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java index d6ac50120..73fcbeadb 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MySqlDdl.java @@ -10,7 +10,6 @@ public class MySqlDdl extends PlatformDdl { public MySqlDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); - this.namingConvention.maxConstraintNameLength = 64; } /** @@ -24,6 +23,7 @@ public class MySqlDdl extends PlatformDdl { /** * Return the drop foreign key clause. */ + @Override public String alterTableDropForeignKey(String tableName, String fkName) { return "alter table " + tableName + " drop foreign key " + fkName; } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/NoHistorySupportDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/NoHistorySupportDdl.java index a2337e1b3..6706aa793 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/NoHistorySupportDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/NoHistorySupportDdl.java @@ -1,5 +1,6 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.model.MTable; @@ -12,8 +13,12 @@ import java.io.IOException; public class NoHistorySupportDdl implements PlatformHistoryDdl { @Override - public void createWithHistory(DdlWrite writer, MTable table) throws IOException { + public void configure(ServerConfig serverConfig) { + // does nothing + } + @Override + public void createWithHistory(DdlWrite writer, MTable table) throws IOException { // does nothing } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java index a91ca8e54..1b2aa9d0c 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/Oracle10Ddl.java @@ -10,11 +10,10 @@ public class Oracle10Ddl extends PlatformDdl { public Oracle10Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); - this.historyDdl = new H2HistoryDdl(); this.dropTableIfExists = "drop table "; this.dropSequenceIfExists = "drop sequence "; this.dropTableCascade = " cascade constraints purge"; - this.namingConvention.maxConstraintNameLength = 30; + this.maxConstraintNameLength = 30; this.foreignKeyRestrict = ""; } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java index eadee2052..a2a40b52b 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -1,5 +1,6 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.DbIdentity; import com.avaje.ebean.config.dbplatform.DbTypeMap; import com.avaje.ebean.config.dbplatform.IdType; @@ -7,6 +8,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.VowelRemover; import com.avaje.ebean.dbmigration.migration.AlterColumn; import com.avaje.ebean.dbmigration.migration.IdentityType; import com.avaje.ebean.dbmigration.model.MTable; @@ -20,8 +22,6 @@ public class PlatformDdl { protected PlatformHistoryDdl historyDdl = new NoHistorySupportDdl(); - protected DdlNamingConvention namingConvention = new DdlNamingConvention(); - /** * Converter for logical/standard types to platform specific types. (eg. clob -> text) */ @@ -48,18 +48,50 @@ public class PlatformDdl { protected String identitySuffix = " auto_increment"; + protected String dropConstraintIfExists = "drop constraint if exists"; + + protected String dropIndexIfExists = "drop index if exists "; + /** * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. */ protected boolean inlineUniqueOneToOne = true; + /** + * A value of 60 is a reasonable default for all databases except + * Oracle (limited to 30) and DB2 (limited to 18). + */ + protected int maxConstraintNameLength = 60; + public PlatformDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) { this.dbIdentity = dbIdentity; this.typeConverter = new PlatformTypeConverter(platformTypes); } - public DdlHandler createDdlHandler() { - return new BaseDdlHandler(namingConvention, this); + public DdlHandler createDdlHandler(ServerConfig serverConfig) { + historyDdl.configure(serverConfig); + return new BaseDdlHandler(serverConfig.getNamingConvention(), serverConfig.getConstraintNaming(), this); + } + + /** + * Apply a maximum length to the constraint name. + *

+ * This implementation should work well apart from perhaps DB2 where the limit is 18. + */ + public String maxLength(String constraintName, int count) { + if (constraintName.length() < maxConstraintNameLength) { + return constraintName; + } + if (maxConstraintNameLength < 60) { + // trim out vowels for Oracle / DB2 with short max lengths + constraintName = VowelRemover.trim(constraintName, 4); + 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; } public IdType useIdentityType(IdentityType modelIdentityType) { @@ -85,7 +117,7 @@ public class PlatformDdl { * Return the drop foreign key clause. */ public String alterTableDropForeignKey(String tableName, String fkName) { - return "alter table " + tableName + " drop constraint " + fkName; + return "alter table " + tableName + " " + dropConstraintIfExists + " " + fkName; } /** @@ -140,28 +172,9 @@ public class PlatformDdl { * Return the drop index statement. */ public String dropIndex(String indexName, String tableName) { - return "drop index "+indexName; + return dropIndexIfExists + indexName; } - /** - * Support lower naming tables and columns in DDL generation. - * Tables/Columns with quoted identifiers are exempt. - */ - public String lowerName(String name) { - return namingConvention.lowerName(name); - } - - /** - * Return the maximum table name length. - *

- * This is used when deriving names of intersection tables. - *

- */ - public int getMaxTableNameLength() { - return namingConvention.getMaxTableNameLength(); - } - - /** * Return true if unique constraints for OneToOne can be inlined as normal. * Returns false for MsSqlServer due to it's null handling for unique constraints. diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformHistoryDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformHistoryDdl.java index dfcb392c8..48da0862b 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformHistoryDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformHistoryDdl.java @@ -1,5 +1,6 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.model.MTable; @@ -10,8 +11,15 @@ import java.io.IOException; */ public interface PlatformHistoryDdl { + /** + * Configure typically reading the + * @param serverConfig + */ + void configure(ServerConfig serverConfig); + /** * Add history support to the table using platform specific mechanism. */ void createWithHistory(DdlWrite writer, MTable table) throws IOException; + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java index 30dd1e10e..bb0d3ffbf 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java @@ -10,9 +10,8 @@ public class PostgresDdl extends PlatformDdl { public PostgresDdl(DbTypeMap platformTypes, DbIdentity dbIdentity) { super(platformTypes, dbIdentity); - this.historyDdl = new PostgresHistoryDdl(this.namingConvention.normalise); + this.historyDdl = new PostgresHistoryDdl(); this.dropTableCascade = " cascade"; - this.namingConvention.maxConstraintNameLength = 62; } /** diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java index 150c2aaf6..90b2adb14 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresHistoryDdl.java @@ -1,5 +1,7 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.model.MColumn; @@ -9,18 +11,38 @@ import java.io.IOException; import java.util.Collection; /** - * + * Uses DB triggers to maintain a history table. */ public class PostgresHistoryDdl implements PlatformHistoryDdl { - private final DdlNameNormalise normalise; + private DbConstraintNaming constraintNaming; - public PostgresHistoryDdl(DdlNameNormalise normalise) { - this.normalise = normalise; + private String sysPeriod; + + private String viewSuffix; + + private String historySuffix = "_history"; + + public PostgresHistoryDdl() { + } + + @Override + public void configure(ServerConfig serverConfig) { + this.sysPeriod = serverConfig.getAsOfSysPeriod(); + this.viewSuffix = serverConfig.getAsOfViewSuffix(); + this.constraintNaming = serverConfig.getConstraintNaming(); + } + + @Override + public void createWithHistory(DdlWrite writer, MTable table) throws IOException { + + addHistoryTable(writer, table); + addStoredFunction(writer, table); + addTrigger(writer, table); } protected String historyTableName(String baseTableName) { - return baseTableName + "_history"; + return baseTableName + historySuffix; } protected String procedureName(String baseTableName) { @@ -31,42 +53,33 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { return baseTableName + "_history_upd"; } - public void createWithHistory(DdlWrite writer, MTable table) throws IOException { - - // naming convention - - addHistoryTable(writer, table); - addStoredFunction(writer, table); - addTrigger(writer, table); - } - public void addHistoryTable(DdlWrite writer, MTable table) throws IOException { - String baseTableName = this.normalise.normaliseTable(table.getName()); + String baseTableName = constraintNaming.normaliseTable(table.getName()); DdlBuffer buffer = writer.applyHistory(); buffer .append("alter table ").append(baseTableName) - .append(" add column sys_period tstzrange not null") + .append(" add column ").append(sysPeriod).append(" tstzrange not null") .endOfStatement().end(); buffer - .append("create table ").append(baseTableName).append("_history") + .append("create table ").append(baseTableName).append(historySuffix) .append(" (like ").append(baseTableName).append(")") .endOfStatement().end(); buffer - .append("create view ").append(baseTableName).append("_with_history") + .append("create view ").append(baseTableName).append(viewSuffix) .append(" as select * from").append(baseTableName) - .append(" union all select * from").append(baseTableName).append("_history") + .append(" union all select * from").append(baseTableName).append(historySuffix) .endOfStatement().end(); } public void addTrigger(DdlWrite writer, MTable table) throws IOException { - String baseTableName = this.normalise.normaliseTable(table.getName()); + String baseTableName = constraintNaming.normaliseTable(table.getName()); String procedureName = procedureName(baseTableName); String triggerName = triggerName(baseTableName); @@ -81,7 +94,7 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { public void addStoredFunction(DdlWrite writer, MTable table) throws IOException { - String baseTableName = this.normalise.normaliseTable(table.getName()); + String baseTableName = constraintNaming.normaliseTable(table.getName()); String procedureName = procedureName(baseTableName); DdlBuffer buffer = writer.applyHistory(); @@ -90,13 +103,13 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { .append("begin").newLine(); buffer .append(" if (TG_OP = 'INSERT') then").newLine() - .append(" NEW.sys_period = tstzrange(CURRENT_TIMESTAMP,null);").newLine() + .append(" NEW.").append(sysPeriod).append(" = tstzrange(CURRENT_TIMESTAMP,null);").newLine() .append(" return new;").newLine().newLine(); buffer .append(" elsif (TG_OP = 'UPDATE') then").newLine(); appendInsertIntoHistory(buffer, table); buffer - .append(" NEW.sys_period = tstzrange(CURRENT_TIMESTAMP,null);").newLine() + .append(" NEW.").append(sysPeriod).append(" = tstzrange(CURRENT_TIMESTAMP,null);").newLine() .append(" return new;").newLine().newLine(); buffer .append(" elsif (TG_OP = 'DELETE') then").newLine(); @@ -116,9 +129,9 @@ public class PostgresHistoryDdl implements PlatformHistoryDdl { String historyTable = historyTableName(table.getName()); - buffer.append(" insert into ").append(historyTable).append(" (sys_period,"); + buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriod).append(","); appendColumnNames(buffer, table, ""); - buffer.append(") values (tstzrange(lower(OLD.sys_period), CURRENT_TIMESTAMP), "); + buffer.append(") values (tstzrange(lower(OLD.").append(sysPeriod).append("), CURRENT_TIMESTAMP), "); appendColumnNames(buffer, table, "OLD."); buffer.append(");").newLine(); } diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexColumns.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexColumns.java new file mode 100644 index 000000000..d0e752674 --- /dev/null +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexColumns.java @@ -0,0 +1,89 @@ +package com.avaje.ebean.dbmigration.ddlgeneration.platform.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Set of columns making up a particular index (column order is important). + */ +public class IndexColumns { + + List columns = new ArrayList(4); + + /** + * Construct representing as a single column index. + */ + public IndexColumns(String column) { + columns.add(column); + } + + /** + * Construct representing index. + */ + public IndexColumns(String[] columnNames) { + for (int i = 0; i < columnNames.length; i++) { + columns.add(columnNames[i]); + } + } + + /** + * Return true if this index matches (same single column). + */ + public boolean isMatch(String singleColumn) { + return columns.size() == 1 && columns.get(0).equals(singleColumn); + } + + /** + * Return true if this index matches (same single column). + */ + public boolean isMatch(List columnNames) { + if (columns.size() != columnNames.size()) { + return false; + } + for (int i = 0; i 0) { + sb.append("_"); + } + sb.append(columns.get(i)); + } + return sb.toString(); + } + } +} diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexSet.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexSet.java new file mode 100644 index 000000000..5b59f538a --- /dev/null +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/IndexSet.java @@ -0,0 +1,85 @@ +package com.avaje.ebean.dbmigration.ddlgeneration.platform.util; + +import com.avaje.ebean.dbmigration.migration.Column; + +import java.util.ArrayList; +import java.util.List; + +/** + * 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. + */ +public 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(String 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 < indexes.size(); i++) { + if (indexes.get(i).isMatch(newIndex)) { + return false; + } + } + indexes.add(newIndex); + return true; + } + + /** + * Add the externally created unique constraint here so that we check later if foreign key indexes + * don't need to be created (as the columns match this unique constraint). + */ + public void add(IndexColumns index) { + indexes.add(index); + } + + public boolean contains(String column) { + + for (IndexColumns index : indexes) { + if (index.isMatch(column)) { + return true; + } + } + return false; + } + + public boolean contains(List columns) { + + for (IndexColumns index : indexes) { + if (index.isMatch(columns)) { + return true; + } + } + return false; + } + + public List getIndexes() { + return indexes; + } + + public void addIndex(Column column) { + + } +} diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemover.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemover.java new file mode 100644 index 000000000..6065c0845 --- /dev/null +++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemover.java @@ -0,0 +1,33 @@ +package com.avaje.ebean.dbmigration.ddlgeneration.platform.util; + +/** + * Utility to remove vowels (from constraint names primarily for Oracle and DB2). + */ +public class VowelRemover { + + /** + * Trim a word by removing vowels skipping some initial characters. + */ + public static String trim(String word, int skipChars) { + + if (word.length() < skipChars) { + return word; + } + + StringBuilder res = new StringBuilder(); + res.append(word.substring(0, skipChars)); + + for (int i = skipChars; i < word.length(); i++) { + char ch = word.charAt(i); + if (!isVowel(ch)) { + res.append(ch); + } + } + return res.toString(); + } + + private static boolean isVowel(char ch) { + ch = Character.toLowerCase(ch); + return ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u'; + } +} diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java index 55a05a233..ff67d66dc 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java @@ -20,16 +20,20 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="columnName" 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="type" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="defaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="oldDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="newDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="oldCheckConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="newCheckConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="oldReferences" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="newReferences" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="checkConstraintName" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="dropCheckConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="dropUnique" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="references" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyName" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="dropForeignKey" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="dropForeignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> * </complexType> @@ -48,26 +52,34 @@ public class AlterColumn { protected String tableName; @XmlAttribute(name = "type") protected String type; + @XmlAttribute(name = "defaultValue") + protected String defaultValue; @XmlAttribute(name = "notnull") protected Boolean notnull; @XmlAttribute(name = "historyExclude") protected Boolean historyExclude; + @XmlAttribute(name = "checkConstraint") + protected String checkConstraint; + @XmlAttribute(name = "checkConstraintName") + protected String checkConstraintName; + @XmlAttribute(name = "dropCheckConstraint") + protected String dropCheckConstraint; @XmlAttribute(name = "unique") - protected Boolean unique; + protected String unique; @XmlAttribute(name = "uniqueOneToOne") - protected Boolean uniqueOneToOne; - @XmlAttribute(name = "oldDefaultValue") - protected String oldDefaultValue; - @XmlAttribute(name = "newDefaultValue") - protected String newDefaultValue; - @XmlAttribute(name = "oldCheckConstraint") - protected String oldCheckConstraint; - @XmlAttribute(name = "newCheckConstraint") - protected String newCheckConstraint; - @XmlAttribute(name = "oldReferences") - protected String oldReferences; - @XmlAttribute(name = "newReferences") - protected String newReferences; + protected String uniqueOneToOne; + @XmlAttribute(name = "dropUnique") + protected String dropUnique; + @XmlAttribute(name = "references") + protected String references; + @XmlAttribute(name = "foreignKeyName") + protected String foreignKeyName; + @XmlAttribute(name = "foreignKeyIndex") + protected String foreignKeyIndex; + @XmlAttribute(name = "dropForeignKey") + protected String dropForeignKey; + @XmlAttribute(name = "dropForeignKeyIndex") + protected String dropForeignKeyIndex; /** * Gets the value of the columnName property. @@ -141,6 +153,30 @@ public class AlterColumn { this.type = value; } + /** + * Gets the value of the defaultValue property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getDefaultValue() { + return defaultValue; + } + + /** + * Sets the value of the defaultValue property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDefaultValue(String value) { + this.defaultValue = value; + } + /** * Gets the value of the notnull property. * @@ -189,15 +225,87 @@ public class AlterColumn { this.historyExclude = value; } + /** + * Gets the value of the checkConstraint property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCheckConstraint() { + return checkConstraint; + } + + /** + * Sets the value of the checkConstraint property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCheckConstraint(String value) { + this.checkConstraint = value; + } + + /** + * Gets the value of the checkConstraintName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCheckConstraintName() { + return checkConstraintName; + } + + /** + * Sets the value of the checkConstraintName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCheckConstraintName(String value) { + this.checkConstraintName = value; + } + + /** + * Gets the value of the dropCheckConstraint property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getDropCheckConstraint() { + return dropCheckConstraint; + } + + /** + * Sets the value of the dropCheckConstraint property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDropCheckConstraint(String value) { + this.dropCheckConstraint = value; + } + /** * Gets the value of the unique property. * * @return * possible object is - * {@link Boolean } + * {@link String } * */ - public Boolean isUnique() { + public String getUnique() { return unique; } @@ -206,10 +314,10 @@ public class AlterColumn { * * @param value * allowed object is - * {@link Boolean } + * {@link String } * */ - public void setUnique(Boolean value) { + public void setUnique(String value) { this.unique = value; } @@ -218,10 +326,10 @@ public class AlterColumn { * * @return * possible object is - * {@link Boolean } + * {@link String } * */ - public Boolean isUniqueOneToOne() { + public String getUniqueOneToOne() { return uniqueOneToOne; } @@ -230,155 +338,155 @@ public class AlterColumn { * * @param value * allowed object is - * {@link Boolean } + * {@link String } * */ - public void setUniqueOneToOne(Boolean value) { + public void setUniqueOneToOne(String value) { this.uniqueOneToOne = value; } /** - * Gets the value of the oldDefaultValue property. + * Gets the value of the dropUnique property. * * @return * possible object is * {@link String } * */ - public String getOldDefaultValue() { - return oldDefaultValue; + public String getDropUnique() { + return dropUnique; } /** - * Sets the value of the oldDefaultValue property. + * Sets the value of the dropUnique property. * * @param value * allowed object is * {@link String } * */ - public void setOldDefaultValue(String value) { - this.oldDefaultValue = value; + public void setDropUnique(String value) { + this.dropUnique = value; } /** - * Gets the value of the newDefaultValue property. + * Gets the value of the references property. * * @return * possible object is * {@link String } * */ - public String getNewDefaultValue() { - return newDefaultValue; + public String getReferences() { + return references; } /** - * Sets the value of the newDefaultValue property. + * Sets the value of the references property. * * @param value * allowed object is * {@link String } * */ - public void setNewDefaultValue(String value) { - this.newDefaultValue = value; + public void setReferences(String value) { + this.references = value; } /** - * Gets the value of the oldCheckConstraint property. + * Gets the value of the foreignKeyName property. * * @return * possible object is * {@link String } * */ - public String getOldCheckConstraint() { - return oldCheckConstraint; + public String getForeignKeyName() { + return foreignKeyName; } /** - * Sets the value of the oldCheckConstraint property. + * Sets the value of the foreignKeyName property. * * @param value * allowed object is * {@link String } * */ - public void setOldCheckConstraint(String value) { - this.oldCheckConstraint = value; + public void setForeignKeyName(String value) { + this.foreignKeyName = value; } /** - * Gets the value of the newCheckConstraint property. + * Gets the value of the foreignKeyIndex property. * * @return * possible object is * {@link String } * */ - public String getNewCheckConstraint() { - return newCheckConstraint; + public String getForeignKeyIndex() { + return foreignKeyIndex; } /** - * Sets the value of the newCheckConstraint property. + * Sets the value of the foreignKeyIndex property. * * @param value * allowed object is * {@link String } * */ - public void setNewCheckConstraint(String value) { - this.newCheckConstraint = value; + public void setForeignKeyIndex(String value) { + this.foreignKeyIndex = value; } /** - * Gets the value of the oldReferences property. + * Gets the value of the dropForeignKey property. * * @return * possible object is * {@link String } * */ - public String getOldReferences() { - return oldReferences; + public String getDropForeignKey() { + return dropForeignKey; } /** - * Sets the value of the oldReferences property. + * Sets the value of the dropForeignKey property. * * @param value * allowed object is * {@link String } * */ - public void setOldReferences(String value) { - this.oldReferences = value; + public void setDropForeignKey(String value) { + this.dropForeignKey = value; } /** - * Gets the value of the newReferences property. + * Gets the value of the dropForeignKeyIndex property. * * @return * possible object is * {@link String } * */ - public String getNewReferences() { - return newReferences; + public String getDropForeignKeyIndex() { + return dropForeignKeyIndex; } /** - * Sets the value of the newReferences property. + * Sets the value of the dropForeignKeyIndex property. * * @param value * allowed object is * {@link String } * */ - public void setNewReferences(String value) { - this.newReferences = value; + public void setDropForeignKeyIndex(String value) { + this.dropForeignKeyIndex = value; } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java b/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java index 69e84822c..e99569ebe 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java @@ -22,13 +22,16 @@ import javax.xml.bind.annotation.XmlValue; * <attribute name="type" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="defaultValue" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" /> - * <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="primaryKey" type="{http://www.w3.org/2001/XMLSchema}boolean" /> * <attribute name="identity" type="{http://www.w3.org/2001/XMLSchema}boolean" /> + * <attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="checkConstraintName" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="references" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyName" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="comment" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> @@ -54,20 +57,26 @@ public class Column { protected String defaultValue; @XmlAttribute(name = "notnull") protected Boolean notnull; - @XmlAttribute(name = "checkConstraint") - protected String checkConstraint; @XmlAttribute(name = "historyExclude") protected Boolean historyExclude; - @XmlAttribute(name = "unique") - protected Boolean unique; - @XmlAttribute(name = "uniqueOneToOne") - protected Boolean uniqueOneToOne; @XmlAttribute(name = "primaryKey") protected Boolean primaryKey; @XmlAttribute(name = "identity") protected Boolean identity; + @XmlAttribute(name = "checkConstraint") + protected String checkConstraint; + @XmlAttribute(name = "checkConstraintName") + protected String checkConstraintName; + @XmlAttribute(name = "unique") + protected String unique; + @XmlAttribute(name = "uniqueOneToOne") + protected String uniqueOneToOne; @XmlAttribute(name = "references") protected String references; + @XmlAttribute(name = "foreignKeyName") + protected String foreignKeyName; + @XmlAttribute(name = "foreignKeyIndex") + protected String foreignKeyIndex; @XmlAttribute(name = "comment") protected String comment; @@ -191,30 +200,6 @@ public class Column { this.notnull = value; } - /** - * Gets the value of the checkConstraint property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getCheckConstraint() { - return checkConstraint; - } - - /** - * Sets the value of the checkConstraint property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setCheckConstraint(String value) { - this.checkConstraint = value; - } - /** * Gets the value of the historyExclude property. * @@ -239,54 +224,6 @@ public class Column { this.historyExclude = value; } - /** - * Gets the value of the unique property. - * - * @return - * possible object is - * {@link Boolean } - * - */ - public Boolean isUnique() { - return unique; - } - - /** - * Sets the value of the unique property. - * - * @param value - * allowed object is - * {@link Boolean } - * - */ - public void setUnique(Boolean value) { - this.unique = value; - } - - /** - * Gets the value of the uniqueOneToOne property. - * - * @return - * possible object is - * {@link Boolean } - * - */ - public Boolean isUniqueOneToOne() { - return uniqueOneToOne; - } - - /** - * Sets the value of the uniqueOneToOne property. - * - * @param value - * allowed object is - * {@link Boolean } - * - */ - public void setUniqueOneToOne(Boolean value) { - this.uniqueOneToOne = value; - } - /** * Gets the value of the primaryKey property. * @@ -335,6 +272,102 @@ public class Column { this.identity = value; } + /** + * Gets the value of the checkConstraint property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCheckConstraint() { + return checkConstraint; + } + + /** + * Sets the value of the checkConstraint property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCheckConstraint(String value) { + this.checkConstraint = value; + } + + /** + * Gets the value of the checkConstraintName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getCheckConstraintName() { + return checkConstraintName; + } + + /** + * Sets the value of the checkConstraintName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setCheckConstraintName(String value) { + this.checkConstraintName = value; + } + + /** + * Gets the value of the unique property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getUnique() { + return unique; + } + + /** + * Sets the value of the unique property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setUnique(String value) { + this.unique = value; + } + + /** + * Gets the value of the uniqueOneToOne property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getUniqueOneToOne() { + return uniqueOneToOne; + } + + /** + * Sets the value of the uniqueOneToOne property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setUniqueOneToOne(String value) { + this.uniqueOneToOne = value; + } + /** * Gets the value of the references property. * @@ -359,6 +392,54 @@ public class Column { this.references = value; } + /** + * Gets the value of the foreignKeyName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getForeignKeyName() { + return foreignKeyName; + } + + /** + * Sets the value of the foreignKeyName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setForeignKeyName(String value) { + this.foreignKeyName = value; + } + + /** + * Gets the value of the foreignKeyIndex property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getForeignKeyIndex() { + return foreignKeyIndex; + } + + /** + * Sets the value of the foreignKeyIndex property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setForeignKeyIndex(String value) { + this.foreignKeyIndex = value; + } + /** * Gets the value of the comment property. * diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/CreateTable.java b/src/main/java/com/avaje/ebean/dbmigration/migration/CreateTable.java index 4ca9e25b1..421e5fb90 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/CreateTable.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/CreateTable.java @@ -34,6 +34,7 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="sequenceName" type="{http://www.w3.org/2001/XMLSchema}string" /> * <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" /> * </restriction> * </complexContent> * </complexType> @@ -68,6 +69,8 @@ public class CreateTable { @XmlAttribute(name = "sequenceAllocate") @XmlSchemaType(name = "positiveInteger") protected BigInteger sequenceAllocate; + @XmlAttribute(name = "pkName") + protected String pkName; @XmlAttribute(name = "tablespace") protected String tablespace; @XmlAttribute(name = "indexTablespace") @@ -306,6 +309,30 @@ public class CreateTable { this.sequenceAllocate = value; } + /** + * Gets the value of the pkName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getPkName() { + return pkName; + } + + /** + * Sets the value of the pkName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setPkName(String value) { + this.pkName = value; + } + /** * Gets the value of the tablespace property. * diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/ForeignKey.java b/src/main/java/com/avaje/ebean/dbmigration/migration/ForeignKey.java index aebea69ce..7963c73d6 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/ForeignKey.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/ForeignKey.java @@ -17,9 +17,11 @@ import javax.xml.bind.annotation.XmlType; * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="refColumnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="refTableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="indexName" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> * </complexType> @@ -32,12 +34,40 @@ import javax.xml.bind.annotation.XmlType; @XmlRootElement(name = "foreignKey") public class ForeignKey { + @XmlAttribute(name = "name", required = true) + protected String name; @XmlAttribute(name = "columnNames", required = true) protected String columnNames; @XmlAttribute(name = "refColumnNames", required = true) protected String refColumnNames; @XmlAttribute(name = "refTableName", required = true) protected String refTableName; + @XmlAttribute(name = "indexName") + protected String indexName; + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } /** * Gets the value of the columnNames property. @@ -111,4 +141,28 @@ public class ForeignKey { this.refTableName = value; } + /** + * Gets the value of the indexName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getIndexName() { + return indexName; + } + + /** + * Sets the value of the indexName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setIndexName(String value) { + this.indexName = value; + } + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/UniqueConstraint.java b/src/main/java/com/avaje/ebean/dbmigration/migration/UniqueConstraint.java index 42a3ed359..f560218cc 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/migration/UniqueConstraint.java +++ b/src/main/java/com/avaje/ebean/dbmigration/migration/UniqueConstraint.java @@ -17,8 +17,8 @@ import javax.xml.bind.annotation.XmlType; * <complexType> * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> + * <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> - * <attribute name="constraintName" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> * </complexType> @@ -31,10 +31,34 @@ import javax.xml.bind.annotation.XmlType; @XmlRootElement(name = "uniqueConstraint") public class UniqueConstraint { + @XmlAttribute(name = "name", required = true) + protected String name; @XmlAttribute(name = "columnNames", required = true) protected String columnNames; - @XmlAttribute(name = "constraintName") - protected String constraintName; + + /** + * Gets the value of the name property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getName() { + return name; + } + + /** + * Sets the value of the name property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setName(String value) { + this.name = value; + } /** * Gets the value of the columnNames property. @@ -60,28 +84,4 @@ public class UniqueConstraint { this.columnNames = value; } - /** - * Gets the value of the constraintName property. - * - * @return - * possible object is - * {@link String } - * - */ - public String getConstraintName() { - return constraintName; - } - - /** - * Sets the value of the constraintName property. - * - * @param value - * allowed object is - * {@link String } - * - */ - public void setConstraintName(String value) { - this.constraintName = value; - } - } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java index fdcfd4732..aa3c7c34e 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java @@ -2,6 +2,8 @@ package com.avaje.ebean.dbmigration.model; import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; import com.avaje.ebean.dbmigration.migration.ChangeSet; import com.avaje.ebean.dbmigration.migration.Migration; import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter; @@ -21,6 +23,10 @@ public class CurrentModel { private final SpiEbeanServer server; + private final DbConstraintNaming constraintNaming; + + private final PlatformDdl platformDdl; + private ModelContainer model; private ChangeSet changeSet; @@ -32,6 +38,8 @@ public class CurrentModel { */ public CurrentModel(SpiEbeanServer server) { this.server = server; + this.platformDdl = server.getDatabasePlatform().getPlatformDdl(); + this.constraintNaming = server.getServerConfig().getConstraintNaming(); } /** @@ -40,7 +48,7 @@ public class CurrentModel { public ModelContainer read() { if (model == null) { model = new ModelContainer(); - ModelBuildContext context = new ModelBuildContext(model); + ModelBuildContext context = new ModelBuildContext(model, constraintNaming, platformDdl); ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context); VisitAllUsing visit = new VisitAllUsing(visitor, server); visit.visitAllBeans(); @@ -124,7 +132,7 @@ public class CurrentModel { * Return the platform specific DdlHandler (to generate DDL). */ private DdlHandler handler() { - return server.getDatabasePlatform().createDdlHandler(); + return server.getDatabasePlatform().createDdlHandler(server.getServerConfig()); } /** diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java index 7855d9920..601df6513 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java @@ -11,31 +11,39 @@ public class MColumn { private final String name; private final String type; private String checkConstraint; + private String checkConstraintName; private String defaultValue; private String references; + private String foreignKeyName; + private String foreignKeyIndex; + private boolean historyExclude; private boolean notnull; private boolean primaryKey; private boolean identity; - private boolean unique; + private String unique; /** * Special unique for OneToOne as we need to handle that different * specifically for MsSqlServer. */ - private boolean uniqueOneToOne; + private String uniqueOneToOne; public MColumn(Column column) { this.name = column.getName(); this.type = column.getType(); this.checkConstraint = column.getCheckConstraint(); + this.checkConstraintName = column.getCheckConstraintName(); this.defaultValue = column.getDefaultValue(); this.references = column.getReferences(); + this.foreignKeyName = column.getForeignKeyName(); + this.foreignKeyIndex = column.getForeignKeyIndex(); this.notnull = Boolean.TRUE.equals(column.isNotnull()); this.primaryKey = Boolean.TRUE.equals(column.isPrimaryKey()); this.identity = Boolean.TRUE.equals(column.isIdentity()); - this.unique = Boolean.TRUE.equals(column.isUnique()); + this.unique = column.getUnique(); + this.uniqueOneToOne = column.getUniqueOneToOne(); this.historyExclude = Boolean.TRUE.equals(column.isHistoryExclude()); } @@ -82,6 +90,30 @@ public class MColumn { this.checkConstraint = checkConstraint; } + public String getCheckConstraintName() { + return checkConstraintName; + } + + public void setCheckConstraintName(String checkConstraintName) { + this.checkConstraintName = checkConstraintName; + } + + public String getForeignKeyName() { + return foreignKeyName; + } + + public void setForeignKeyName(String foreignKeyName) { + this.foreignKeyName = foreignKeyName; + } + + public String getForeignKeyIndex() { + return foreignKeyIndex; + } + + public void setForeignKeyIndex(String foreignKeyIndex) { + this.foreignKeyIndex = foreignKeyIndex; + } + public String getDefaultValue() { return defaultValue; } @@ -114,11 +146,11 @@ public class MColumn { this.historyExclude = historyExclude; } - public void setUnique(boolean unique) { + public void setUnique(String unique) { this.unique = unique; } - public boolean isUnique() { + public String getUnique() { return unique; } @@ -126,14 +158,14 @@ public class MColumn { * Set unique specifically for OneToOne mapping. * We need special DDL for this case for MsSqlServer. */ - public void setUniqueOneToOne(boolean uniqueOneToOne) { + public void setUniqueOneToOne(String uniqueOneToOne) { this.uniqueOneToOne = uniqueOneToOne; } /** * Return true if this is unique for a OneToOne. */ - public boolean isUniqueOneToOne() { + public String getUniqueOneToOne() { return uniqueOneToOne; } @@ -142,16 +174,20 @@ public class MColumn { Column c = new Column(); c.setName(name); c.setType(type); + if (notnull) c.setNotnull(true); - if (unique) c.setUnique(true); - if (uniqueOneToOne) c.setUniqueOneToOne(true); if (primaryKey) c.setPrimaryKey(true); if (identity) c.setIdentity(true); if (historyExclude) c.setHistoryExclude(true); c.setCheckConstraint(checkConstraint); + c.setCheckConstraintName(checkConstraintName); c.setReferences(references); + c.setForeignKeyName(foreignKeyName); + c.setForeignKeyIndex(foreignKeyIndex); c.setDefaultValue(defaultValue); + c.setUnique(unique); + c.setUniqueOneToOne(uniqueOneToOne); return c; } @@ -160,6 +196,10 @@ public class MColumn { return (val1 == null) ? val2 != null : !val1.equals(val2); } + private boolean hasValue(String val) { + return val != null && !val.isEmpty(); + } + AlterColumn alterColumn; private AlterColumn getAlterColumn(String tableName) { @@ -175,6 +215,7 @@ public class MColumn { String tableName = table.getName(); + // set to null and check at the end this.alterColumn = null; if (different(type, newColumn.type)) { @@ -188,27 +229,53 @@ public class MColumn { } if (different(defaultValue, newColumn.defaultValue)) { AlterColumn alter = getAlterColumn(tableName); - alter.setOldDefaultValue(defaultValue); - alter.setNewDefaultValue(newColumn.defaultValue); - } - if (different(checkConstraint, newColumn.checkConstraint)) { - AlterColumn alter = getAlterColumn(tableName); - alter.setOldCheckConstraint(checkConstraint); - alter.setNewCheckConstraint(newColumn.checkConstraint); - } - if (different(references, newColumn.references)) { - AlterColumn alter = getAlterColumn(tableName); - alter.setOldReferences(references); - alter.setNewReferences(newColumn.references); + alter.setDefaultValue(newColumn.defaultValue); } - if (unique != newColumn.unique) { + if (different(checkConstraint, newColumn.checkConstraint)) { AlterColumn alter = getAlterColumn(tableName); - alter.setUnique(newColumn.unique); + if (hasValue(checkConstraint)) { + alter.setDropCheckConstraint(checkConstraintName); + } + if (hasValue(newColumn.checkConstraint)) { + alter.setCheckConstraintName(newColumn.checkConstraintName); + alter.setCheckConstraint(newColumn.checkConstraint); + } } - if (uniqueOneToOne != newColumn.uniqueOneToOne) { + if (different(references, newColumn.references)) { + // foreign key change AlterColumn alter = getAlterColumn(tableName); - alter.setUniqueOneToOne(newColumn.uniqueOneToOne); + if (hasValue(foreignKeyName)) { + alter.setDropForeignKey(foreignKeyName); + } + if (hasValue(foreignKeyIndex)) { + alter.setDropForeignKeyIndex(foreignKeyIndex); + } + if (hasValue(newColumn.references)) { + // add new foreign key constraint + alter.setReferences(newColumn.references); + alter.setForeignKeyName(newColumn.foreignKeyName); + alter.setForeignKeyIndex(newColumn.foreignKeyIndex); + } + } + + if (different(unique, newColumn.unique)) { + AlterColumn alter = getAlterColumn(tableName); + if (hasValue(unique)) { + alter.setDropUnique(unique); + } + if (hasValue(newColumn.unique)) { + alter.setUnique(newColumn.unique); + } + } + if (different(uniqueOneToOne, newColumn.uniqueOneToOne)) { + AlterColumn alter = getAlterColumn(tableName); + if (hasValue(uniqueOneToOne)) { + alter.setDropUnique(uniqueOneToOne); + } + if (hasValue(newColumn.uniqueOneToOne)) { + alter.setUniqueOneToOne(newColumn.uniqueOneToOne); + } } if (alterColumn != null) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundForeignKey.java b/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundForeignKey.java index 4d48123ed..20a5a208f 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundForeignKey.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundForeignKey.java @@ -1,6 +1,5 @@ package com.avaje.ebean.dbmigration.model; -import com.avaje.ebean.dbmigration.migration.Column; import com.avaje.ebean.dbmigration.migration.ForeignKey; import java.util.ArrayList; @@ -9,33 +8,60 @@ import java.util.List; /** * A unique constraint for multiple columns. *

- * Note that unique constraint on a single column is instead - * a boolean flag on the associated MColumn. + * Note that unique constraint on a single column is instead + * a boolean flag on the associated MColumn. *

*/ public class MCompoundForeignKey { + private final String name; private final String referenceTable; private final List columns = new ArrayList(); private final List referenceColumns = new ArrayList(); + private String indexName; - public MCompoundForeignKey(String referenceTable) { + public MCompoundForeignKey(String name, String referenceTable, String indexName) { + this.name = name; this.referenceTable = referenceTable; + this.indexName = indexName; } + /** + * Add a column pair of local and referenced column. + */ public void addColumnPair(String dbCol, String refColumn) { columns.add(dbCol); referenceColumns.add(refColumn); } + /** + * Create and return an ForeignKey migration element. + */ public ForeignKey createForeignKey() { ForeignKey fk = new ForeignKey(); + fk.setName(name); + fk.setIndexName(indexName); fk.setColumnNames(toColumnNames(columns)); fk.setRefColumnNames(toColumnNames(referenceColumns)); fk.setRefTableName(referenceTable); return fk; } + /** + * Return the columns making up the foreign key in order. + */ + public List getColumns() { + return columns; + } + + /** + * Set the associated index name. Note that setting to null has the effect + * of indicating an associated index should not be created for this foreign key. + */ + public void setIndexName(String indexName) { + this.indexName = indexName; + } + /** * Return as an array of string column names. */ diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundUniqueConstraint.java b/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundUniqueConstraint.java index 200b88803..2bd087eb1 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundUniqueConstraint.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MCompoundUniqueConstraint.java @@ -9,6 +9,8 @@ package com.avaje.ebean.dbmigration.model; */ public class MCompoundUniqueConstraint { + private final String name; + /** * Flag if true indicates this was specifically created for a OneToOne mapping. */ @@ -19,7 +21,8 @@ public class MCompoundUniqueConstraint { */ private final String[] columns; - public MCompoundUniqueConstraint(String[] columns, boolean oneToOne) { + public MCompoundUniqueConstraint(String[] columns, boolean oneToOne, String name) { + this.name = name; this.columns = columns; this.oneToOne = oneToOne; } @@ -38,4 +41,10 @@ public class MCompoundUniqueConstraint { return oneToOne; } + /** + * Return the constraint name. + */ + public String getName() { + return name; + } } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java index 950ed6416..a96e50d06 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java @@ -34,6 +34,8 @@ public class MTable { private final String name; + private String pkName; + private String comment; private String tablespace; @@ -65,6 +67,7 @@ public class MTable { */ public MTable(CreateTable createTable) { this.name = createTable.getName(); + this.pkName = createTable.getPkName(); this.comment = createTable.getComment(); this.tablespace = createTable.getTablespace(); this.indexTablespace = createTable.getIndexTablespace(); @@ -90,6 +93,7 @@ public class MTable { CreateTable createTable = new CreateTable(); createTable.setName(name); + createTable.setPkName(pkName); createTable.setComment(comment); createTable.setTablespace(tablespace); createTable.setIndexTablespace(indexTablespace); @@ -165,6 +169,14 @@ public class MTable { return name; } + public String getPkName() { + return pkName; + } + + public void setPkName(String pkName) { + this.pkName = pkName; + } + public String getComment() { return comment; } @@ -273,19 +285,19 @@ public class MTable { /** * Add a compound unique constraint. */ - public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne) { - compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne)); + public void addCompoundUniqueConstraint(String[] columns, boolean oneToOne, String constraintName) { + compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns, oneToOne, constraintName)); } /** * Add a compound unique constraint. */ - public void addCompoundUniqueConstraint(List columns, boolean oneToOne) { + public void addCompoundUniqueConstraint(List columns, boolean oneToOne, String constraintName) { String[] cols = new String[columns.size()]; for (int i = 0; i < columns.size(); i++) { cols[i] = columns.get(i).getName(); } - addCompoundUniqueConstraint(cols, oneToOne); + addCompoundUniqueConstraint(cols, oneToOne, constraintName); } public void addForeignKey(MCompoundForeignKey compoundKey) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java index 667d9fb98..cf407a75f 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitor.java @@ -8,7 +8,6 @@ import com.avaje.ebean.dbmigration.model.MTable; import com.avaje.ebean.dbmigration.model.visitor.BeanPropertyVisitor; import com.avaje.ebean.dbmigration.model.visitor.BeanVisitor; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; -import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint; import com.avaje.ebeaninternal.server.deploy.InheritInfo; /** @@ -52,14 +51,7 @@ public class ModelBuildBeanVisitor implements BeanVisitor { table.addColumn(new MColumn(discColumn, discDbType, true)); } - CompoundUniqueContraint[] compoundUniqueConstraints = descriptor.getCompoundUniqueConstraints(); - if (compoundUniqueConstraints != null) { - for (int i = 0; i < compoundUniqueConstraints.length; i++) { - table.addCompoundUniqueConstraint(compoundUniqueConstraints[i].getColumns(), false); - } - } - - return new ModelBuildPropertyVisitor(ctx, table); + return new ModelBuildPropertyVisitor(ctx, table, descriptor.getCompoundUniqueConstraints()); } private void setIdentity(BeanDescriptor descriptor, MTable table) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildContext.java b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildContext.java index 1ac843a24..21bd5d37b 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildContext.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildContext.java @@ -2,6 +2,8 @@ package com.avaje.ebean.dbmigration.model.build; import com.avaje.ebean.config.dbplatform.DbType; import com.avaje.ebean.config.dbplatform.DbTypeMap; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebean.dbmigration.model.MTable; import com.avaje.ebean.dbmigration.model.ModelContainer; @@ -20,14 +22,52 @@ public class ModelBuildContext { private final ModelContainer model; - public ModelBuildContext(ModelContainer model) { + private final DbConstraintNaming constraintNaming; + + private final PlatformDdl platformDdl; + + public ModelBuildContext(ModelContainer model, DbConstraintNaming constraintNaming, PlatformDdl platformDdl) { this.model = model; + this.constraintNaming = constraintNaming; + this.platformDdl = platformDdl; + } + + public String primaryKeyName(String tableName) { + return maxLength(constraintNaming.primaryKeyName(tableName), 0); + } + + public String foreignKeyConstraintName(String tableName, String columnName, int foreignKeyCount) { + return maxLength(constraintNaming.foreignKeyConstraintName(tableName, columnName), foreignKeyCount); + } + + public String foreignKeyIndexName(String tableName, String[] columns, int indexCount) { + return maxLength(constraintNaming.foreignKeyIndexName(tableName, columns), indexCount); + } + + public String foreignKeyIndexName(String tableName, String column, int indexCount) { + return maxLength(constraintNaming.foreignKeyIndexName(tableName, column), indexCount); + } + + public String uniqueConstraintName(String tableName, String columnName, int indexCount) { + return maxLength(constraintNaming.uniqueConstraintName(tableName, columnName), indexCount); + } + + public String uniqueConstraintName(String tableName, String[] columnNames, int indexCount) { + return maxLength(constraintNaming.uniqueConstraintName(tableName, columnNames), indexCount); + } + + public String checkConstraintName(String tableName, String columnName, int checkCount) { + return maxLength(constraintNaming.checkConstraintName(tableName, columnName), checkCount); } public void addTable(MTable table) { model.addTable(table); } + private String maxLength(String constraintName, int indexCount) { + return platformDdl.maxLength(constraintName, indexCount); + } + /** * Return the map used to determine the DB specific type * for a given bean property. @@ -57,12 +97,6 @@ public class ModelBuildContext { return dbTypeMap.get(jdbcType); } -// ScalarType scalarType = p.getScalarType(); -// if (scalarType == null) { -// throw new RuntimeException("No scalarType for " + p.getFullBeanName()); -// } -// return dbTypeMap.get(scalarType.getJdbcType()); - // can be the logical JSON types (JSON, JSONB, JSONClob, JSONBlob, JSONVarchar) int dbType = p.getDbType(); if (dbType == 0) { diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildIntersectionTable.java b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildIntersectionTable.java index bade77938..ab9604e39 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildIntersectionTable.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildIntersectionTable.java @@ -23,6 +23,8 @@ public class ModelBuildIntersectionTable { private MTable intersectionTable; + private int countForeignKey; + public ModelBuildIntersectionTable(ModelBuildContext ctx, BeanPropertyAssocMany manyProp) { this.ctx = ctx; this.manyProp = manyProp; @@ -30,7 +32,7 @@ public class ModelBuildIntersectionTable { this.tableJoin = manyProp.getTableJoin(); } - public void build() { + public void build() { intersectionTable = createTable(); ctx.addTable(intersectionTable); @@ -42,66 +44,38 @@ public class ModelBuildIntersectionTable { BeanDescriptor localDesc = manyProp.getBeanDescriptor(); buildFkConstraints(localDesc, intersectionTableJoin.columns(), true); - //ctx.addIntersectionTableFk(fk1); BeanDescriptor targetDesc = manyProp.getTargetDescriptor(); buildFkConstraints(targetDesc, tableJoin.columns(), false); - //ctx.addIntersectionTableFk(fk2); } private void buildFkConstraints(BeanDescriptor desc, TableJoinColumn[] columns, boolean direction) { + String tableName = intersectionTableJoin.getTable(); + String baseTable = desc.getBaseTable(); -// String fkName = "fk_"+intersectionTableJoin.getTable()+"_"+desc.getBaseTable(); -// -// fkName = getFkNameWithSuffix(fkName); + String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, ++countForeignKey); + String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, countForeignKey); - MCompoundForeignKey foreignKey = new MCompoundForeignKey(desc.getBaseTable()); + MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex); intersectionTable.addForeignKey(foreignKey); - -// fkBuf.append("alter table "); -// fkBuf.append(intersectionTableJoin.getTable()); -// fkBuf.append(" add constraint ").append(fkName); -// -// fkBuf.append(" foreign key ("); - for (int i = 0; i < columns.length; i++) { -// if (i > 0) { -// fkBuf.append(", "); -// } String localCol = direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn(); String refCol = !direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn(); foreignKey.addColumnPair(localCol, refCol); } -// fkBuf.append(") references ").append(desc.getBaseTable()).append(" ("); -// -// for (int i = 0; i < columns.length; i++) { -// if (i > 0) { -// fkBuf.append(", "); -// } -// String col = !direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn(); -// fkBuf.append(col); -// } -// fkBuf.append(")"); -// -// String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix(); -// if (fkeySuffix != null){ -// fkBuf.append(" "); -// fkBuf.append(fkeySuffix); -// } -// fkBuf.append(";").append(NEW_LINE); -// -// return fkBuf.toString(); - } + } private MTable createTable() { BeanDescriptor localDesc = manyProp.getBeanDescriptor(); BeanDescriptor targetDesc = manyProp.getTargetDescriptor(); - MTable table = new MTable(intersectionTableJoin.getTable()); + String tableName = intersectionTableJoin.getTable(); + MTable table = new MTable(tableName); + table.setPkName(ctx.primaryKeyName(tableName)); TableJoinColumn[] columns = intersectionTableJoin.columns(); for (int i = 0; i < columns.length; i++) { @@ -125,7 +99,6 @@ public class ModelBuildIntersectionTable { MColumn col = new MColumn(column, ctx.getColumnDefn(p), true); col.setPrimaryKey(true); - table.addColumn(col); } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildPropertyVisitor.java index 69f20a318..0ee8e0d8d 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -1,15 +1,17 @@ package com.avaje.ebean.dbmigration.model.build; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.IndexSet; +import com.avaje.ebean.dbmigration.model.MColumn; import com.avaje.ebean.dbmigration.model.MCompoundForeignKey; +import com.avaje.ebean.dbmigration.model.MTable; +import com.avaje.ebean.dbmigration.model.visitor.BaseTablePropertyVisitor; import com.avaje.ebeaninternal.server.deploy.BeanProperty; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne; import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound; +import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint; import com.avaje.ebeaninternal.server.deploy.TableJoinColumn; import com.avaje.ebeaninternal.server.deploy.id.ImportedId; -import com.avaje.ebean.dbmigration.model.MColumn; -import com.avaje.ebean.dbmigration.model.MTable; -import com.avaje.ebean.dbmigration.model.visitor.BaseTablePropertyVisitor; import java.util.ArrayList; import java.util.List; @@ -20,17 +22,69 @@ import java.util.List; */ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { - private final ModelBuildContext ctx; + protected final ModelBuildContext ctx; private final MTable table; + private final IndexSet indexSet = new IndexSet(); + private MColumn lastColumn; - public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table) { + private int countForeignKey; + private int countIndex; + private int countUnique; + private int countCheck; + + + public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table, CompoundUniqueContraint[] compoundUniqueConstraints) { this.ctx = ctx; this.table = table; + + addCompoundUniqueConstraint(compoundUniqueConstraints); } + /** + * Add unique constraints defined via JPA UniqueConstraint annotations. + */ + private void addCompoundUniqueConstraint(CompoundUniqueContraint[] compoundUniqueConstraints) { + + if (compoundUniqueConstraints != null) { + for (int i = 0; i < compoundUniqueConstraints.length; i++) { + String[] columns = compoundUniqueConstraints[i].getColumns(); + String uqName = determineUniqueConstraintName(columns); + table.addCompoundUniqueConstraint(columns, false, uqName); + indexSet.add(columns); + } + } + } + + @Override + public void visitEnd() { + + // set the primary key name + table.setPkName(determinePrimaryKeyName()); + + // check if indexes on foreign keys should be suppressed + for (MColumn column : table.getColumns().values()) { + if (hasValue(column.getForeignKeyIndex())) { + if (indexSet.contains(column.getName())) { + // suppress index on foreign key as there is already + // effectively an index (probably via unique constraint) + column.setForeignKeyIndex(null); + } + } + } + + for (MCompoundForeignKey compoundKey : table.getCompoundKeys()) { + if (indexSet.contains(compoundKey.getColumns())) { + // suppress index on foreign key as there is already + // effectively an index (probably via unique constraint) + compoundKey.setIndexName(null); + } + } + } + + @Override public void visitMany(BeanPropertyAssocMany p) { if (p.isManyToMany()) { @@ -85,7 +139,9 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { if (columns.length > 1) { // compound foreign key String refTable = p.getTargetDescriptor().getBaseTable(); - compoundKey = new MCompoundForeignKey(refTable); + String fkName = determineForeignKeyConstraintName(p.getName()); + String fkIndex = determineForeignKeyIndexName(p.getName()); + compoundKey = new MCompoundForeignKey(fkName, refTable, fkIndex); table.addForeignKey(compoundKey); } @@ -109,6 +165,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { refTable = p.getTargetDescriptor().getBaseTable(); } col.setReferences(refTable + "." + refColumn); + col.setForeignKeyName(determineForeignKeyConstraintName(col.getName())); + col.setForeignKeyIndex(determineForeignKeyIndexName(col.getName())); } else { compoundKey.addColumnPair(dbCol, refColumn); } @@ -119,14 +177,19 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { // adding the unique constraint restricts the cardinality from OneToMany down to OneToOne // for MsSqlServer we need different DDL to handle NULL values on this constraint if (modelColumns.size() == 1) { - modelColumns.get(0).setUniqueOneToOne(true); + MColumn col = modelColumns.get(0); + col.setUniqueOneToOne(determineUniqueConstraintName(col.getName())); + indexSetAdd(col.getName()); + } else { - table.addCompoundUniqueConstraint(modelColumns, true); + String uqName = determineUniqueConstraintName(p.getName()); + table.addCompoundUniqueConstraint(modelColumns, true, uqName); + indexSetAdd(modelColumns); } } } - @Override + @Override public void visitScalar(BeanProperty p) { if (p.isSecondaryTable()) { @@ -146,12 +209,89 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { } if (p.isUnique() && !p.isId()) { - col.setUnique(true); + col.setUnique(determineUniqueConstraintName(col.getName())); + indexSetAdd(col.getName()); + } + String checkConstraint = p.getDbConstraintExpression(); + if (checkConstraint != null) { + col.setCheckConstraint(checkConstraint); + col.setCheckConstraintName(determineCheckConstraintName(col.getName())); } - col.setCheckConstraint(p.getDbConstraintExpression()); lastColumn = col; table.addColumn(col); } + + private void indexSetAdd(String column) { + indexSet.add(column); + } + + private void indexSetAdd(List modelColumns) { + String[] cols = new String[modelColumns.size()]; + for (int i = 0; i < modelColumns.size(); i++) { + cols[i] = modelColumns.get(i).getName(); + } + indexSet.add(cols); + } + + /** + * Return the primary key constraint name. + */ + protected String determinePrimaryKeyName() { + + return ctx.primaryKeyName(table.getName()); + } + + /** + * Return the foreign key constraint name given a single column foreign key. + */ + protected String determineForeignKeyConstraintName(String columnName) { + + return ctx.foreignKeyConstraintName(table.getName(), columnName, ++countForeignKey); + } + + protected String determineForeignKeyIndexName(String column) { + + String[] cols = {column}; + return determineForeignKeyIndexName(cols); + } + + /** + * Return the foreign key constraint name given a single column foreign key. + */ + protected String determineForeignKeyIndexName(String[] columns) { + + return ctx.foreignKeyIndexName(table.getName(), columns, ++countIndex); + } + + /** + * Return the unique constraint name. + */ + protected String determineUniqueConstraintName(String columnName) { + + return ctx.uniqueConstraintName(table.getName(), columnName, ++countUnique); + } + + /** + * Return the unique constraint name. + */ + protected String determineUniqueConstraintName(String[] columnNames) { + + return ctx.uniqueConstraintName(table.getName(), columnNames, ++countUnique); + } + + /** + * Return the constraint name. + */ + protected String determineCheckConstraintName(String columnName) { + + return ctx.checkConstraintName(table.getName(), columnName, ++countCheck); + } + + + private boolean hasValue(String val) { + return val != null && !val.isEmpty(); + } + } \ No newline at end of file diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanPropertyVisitor.java b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanPropertyVisitor.java index f536d1086..421e1dcea 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanPropertyVisitor.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanPropertyVisitor.java @@ -10,6 +10,11 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound; */ public interface BeanPropertyVisitor { + /** + * Completed visiting all the properties on the bean. + */ + void visitEnd(); + /** * Visit a OneToMany or ManyToMany property. */ diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanVisitor.java b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanVisitor.java index b140878d6..d38889317 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanVisitor.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/BeanVisitor.java @@ -13,4 +13,5 @@ public interface BeanVisitor { * property on the entity bean (return null to skip visiting this bean). */ BeanPropertyVisitor visitBean(BeanDescriptor descriptor); + } diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java index 61f9e3009..22eb83856 100644 --- a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java +++ b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java @@ -72,6 +72,7 @@ public class VisitAllUsing { } visitInheritanceProperties(desc, propertyVisitor); + propertyVisitor.visitEnd(); } } diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd index cbd6f4141..318c40635 100644 --- a/src/main/resources/ebean-dbmigration-1.0.xsd +++ b/src/main/resources/ebean-dbmigration-1.0.xsd @@ -124,6 +124,7 @@ + @@ -141,17 +142,19 @@ + - + + @@ -206,16 +209,20 @@ + - - - - - - - - + + + + + + + + + + + @@ -282,13 +289,16 @@ - - - + + + + + + diff --git a/src/test/java/com/avaje/ebean/config/DbConstraintNamingTest.java b/src/test/java/com/avaje/ebean/config/DbConstraintNamingTest.java new file mode 100644 index 000000000..3b2aae36a --- /dev/null +++ b/src/test/java/com/avaje/ebean/config/DbConstraintNamingTest.java @@ -0,0 +1,37 @@ +package com.avaje.ebean.config; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DbConstraintNamingTest { + + DbConstraintNaming naming = new DbConstraintNaming(); + + @Test + public void testPrimaryKeyName() throws Exception { + + assertThat(naming.primaryKeyName("[cat].[sce].[foo_bar]")).isEqualTo("pk_foo_bar"); + } + + @Test + public void testUniqueConstraintName() throws Exception { + + assertThat(naming.uniqueConstraintName("[foo_bar]", "[jim]")).isEqualTo("uq_foo_bar_jim"); + } + + @Test + public void testCheckConstraintName() throws Exception { + + assertThat(naming.checkConstraintName("[foo_bar]", "[jim]")).isEqualTo("ck_foo_bar_jim"); + } + + @Test + public void testNormalise() throws Exception { + + assertThat(naming.normaliseTable("cat.sch.foo_bar]")).isEqualTo("foo_bar"); + assertThat(naming.normaliseTable("sch.foo_bar]")).isEqualTo("foo_bar"); + assertThat(naming.normaliseTable("foo_bar]")).isEqualTo("foo_bar"); + } + +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandlerTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandlerTest.java index b629f677f..50c6a4635 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandlerTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandlerTest.java @@ -2,6 +2,7 @@ package com.avaje.ebean.dbmigration.ddlgeneration; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.H2Platform; import com.avaje.ebean.config.dbplatform.PostgresPlatform; import com.avaje.ebean.dbmigration.migration.ChangeSet; @@ -15,13 +16,14 @@ import static org.assertj.core.api.Assertions.assertThat; public class BaseDdlHandlerTest extends BaseTestCase { + ServerConfig serverConfig = new ServerConfig(); private DdlHandler h2Handler() { - return new H2Platform().createDdlHandler(); + return new H2Platform().createDdlHandler(serverConfig); } private DdlHandler postgresHandler() { - return new PostgresPlatform().createDdlHandler(); + return new PostgresPlatform().createDdlHandler(serverConfig); } @Test diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java index 89348a65b..94379538f 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdlTest.java @@ -1,6 +1,7 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.ServerConfig; import com.avaje.ebean.config.dbplatform.H2Platform; import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite; import com.avaje.ebean.dbmigration.ddlgeneration.Helper; @@ -15,10 +16,12 @@ import static org.assertj.core.api.Assertions.assertThat; public class BaseTableDdlTest { + ServerConfig serverConfig = new ServerConfig(); + @Test public void testGenerate() throws Exception { - BaseTableDdl ddlGen = new BaseTableDdl(new DdlNamingConvention(), new H2Platform().getPlatformDdl()); + BaseTableDdl ddlGen = new BaseTableDdl(serverConfig, new H2Platform().getPlatformDdl()); DdlWrite write = new DdlWrite(); @@ -38,6 +41,7 @@ public class BaseTableDdlTest { private CreateTable createTable() { CreateTable createTable = new CreateTable(); createTable.setName("mytable"); + createTable.setPkName("pk_mytable"); List columns = createTable.getColumn(); Column col = new Column(); col.setName("id"); @@ -51,6 +55,7 @@ public class BaseTableDdlTest { col2.setType("varchar(1)"); col2.setNotnull(true); col2.setCheckConstraint("check (status in ('A','B'))"); + col2.setCheckConstraintName("ck_mytable_status"); columns.add(col2); @@ -59,6 +64,8 @@ public class BaseTableDdlTest { col3.setType("integer"); col3.setNotnull(true); col3.setReferences("orders.id"); + col3.setForeignKeyName("fk_mytable_order_id"); + col3.setForeignKeyIndex("ix_mytable_order_id"); columns.add(col3); diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DbNameNormaliseTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DbNameNormaliseTest.java index abe29f7b9..153f233d1 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DbNameNormaliseTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DbNameNormaliseTest.java @@ -1,12 +1,13 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.config.DbConstraintNormalise; import org.junit.Test; import static org.assertj.core.api.StrictAssertions.assertThat; public class DbNameNormaliseTest { - DdlNameNormalise normalise = new DdlNameNormalise(); + DbConstraintNormalise normalise = new DbConstraintNormalise(); @Test public void testNormalise() throws Exception { diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConventionTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConventionTest.java deleted file mode 100644 index d0857d268..000000000 --- a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/DdlNamingConventionTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.avaje.ebean.dbmigration.ddlgeneration.platform; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class DdlNamingConventionTest { - - DdlNamingConvention defaultNaming = new DdlNamingConvention(); - - @Test - public void testPrimaryKeyName() throws Exception { - - assertThat(defaultNaming.primaryKeyName("[cat].[sce].[foo_bar]")).isEqualTo("pk_foo_bar"); - } - - @Test - public void testUniqueConstraintName() throws Exception { - - assertThat(defaultNaming.uniqueConstraintName("[foo_bar]", "[jim]", 1)).isEqualTo("uq_foo_bar_jim"); - } - - @Test - public void testCheckConstraintName() throws Exception { - - assertThat(defaultNaming.checkConstraintName("[foo_bar]", "[jim]", 1)).isEqualTo("ck_foo_bar_jim"); - } - - @Test - public void testNormalise() throws Exception { - - assertThat(defaultNaming.normaliseTable("cat.sch.foo_bar]")).isEqualTo("foo_bar"); - assertThat(defaultNaming.normaliseTable("sch.foo_bar]")).isEqualTo("foo_bar"); - assertThat(defaultNaming.normaliseTable("foo_bar]")).isEqualTo("foo_bar"); - } - -} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/IndexSetTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/IndexSetTest.java index d11011709..8b1dc4573 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/IndexSetTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/IndexSetTest.java @@ -1,5 +1,6 @@ package com.avaje.ebean.dbmigration.ddlgeneration.platform; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.IndexSet; import org.junit.Test; import static org.junit.Assert.*; @@ -11,7 +12,7 @@ public class IndexSetTest { @Test public void test() { - BaseTableDdl.IndexSet set = new BaseTableDdl.IndexSet(); + IndexSet set = new IndexSet(); assertTrue(set.add(new String[]{"one_column"})); assertTrue(set.add(new String[]{"two_column"})); assertFalse(set.add(new String[]{"one_column"})); diff --git a/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemoverTest.java b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemoverTest.java new file mode 100644 index 000000000..2767cf2c7 --- /dev/null +++ b/src/test/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/util/VowelRemoverTest.java @@ -0,0 +1,17 @@ +package com.avaje.ebean.dbmigration.ddlgeneration.platform.util; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class VowelRemoverTest { + + @Test + public void testTrim() throws Exception { + + + assertEquals("fk_abcd",VowelRemover.trim("fk_abcde",4)); + assertEquals("fk_a", VowelRemover.trim("fk_aaaaaa", 4)); + assertEquals("ab_avrylngtblnm", VowelRemover.trim("ab_averylongtablename", 4)); + } +} \ No newline at end of file diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java index 2b3f18078..cd55c8249 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java @@ -53,9 +53,9 @@ public class MColumnTest { assertThat(alterColumn.isNotnull()).isEqualTo(true); assertThat(alterColumn.getType()).isNull(); - assertThat(alterColumn.isUnique()).isNull(); - assertThat(alterColumn.isUniqueOneToOne()).isNull(); - assertThat(alterColumn.getNewDefaultValue()).isNull(); + assertThat(alterColumn.getUnique()).isNull(); + assertThat(alterColumn.getUniqueOneToOne()).isNull(); + assertThat(alterColumn.getDefaultValue()).isNull(); } @Test @@ -67,8 +67,8 @@ public class MColumnTest { basic().compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewCheckConstraint()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldCheckConstraint()).isNull(); + assertThat(getAlterColumn(diff).getCheckConstraint()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getDropCheckConstraint()).isNull(); } @Test @@ -77,12 +77,13 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); - oldCol.setCheckConstraint("abc"); + oldCol.setCheckConstraint("z"); + oldCol.setCheckConstraintName("abc"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewCheckConstraint()).isNull(); - assertThat(getAlterColumn(diff).getOldCheckConstraint()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getCheckConstraint()).isNull(); + assertThat(getAlterColumn(diff).getDropCheckConstraint()).isEqualTo("abc"); } @Test @@ -92,12 +93,13 @@ public class MColumnTest { MColumn newCol = basic(); newCol.setCheckConstraint("abc"); MColumn oldCol = basic(); - oldCol.setCheckConstraint("d"); + oldCol.setCheckConstraint("z"); + oldCol.setCheckConstraintName("d"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewCheckConstraint()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldCheckConstraint()).isEqualTo("d"); + assertThat(getAlterColumn(diff).getCheckConstraint()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getDropCheckConstraint()).isEqualTo("d"); } @Test @@ -109,8 +111,7 @@ public class MColumnTest { basic().compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewDefaultValue()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldDefaultValue()).isNull(); + assertThat(getAlterColumn(diff).getDefaultValue()).isEqualTo("abc"); } @Test @@ -123,8 +124,7 @@ public class MColumnTest { oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewDefaultValue()).isNull(); - assertThat(getAlterColumn(diff).getOldDefaultValue()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getDefaultValue()).isNull(); } @Test @@ -138,8 +138,7 @@ public class MColumnTest { oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewDefaultValue()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldDefaultValue()).isEqualTo("d"); + assertThat(getAlterColumn(diff).getDefaultValue()).isEqualTo("abc"); } @Test @@ -151,8 +150,8 @@ public class MColumnTest { basic().compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewReferences()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldReferences()).isNull(); + assertThat(getAlterColumn(diff).getReferences()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getDropForeignKey()).isNull(); } @@ -163,11 +162,17 @@ public class MColumnTest { MColumn newCol = basic(); MColumn oldCol = basic(); oldCol.setReferences("abc"); + oldCol.setForeignKeyName("fk_ab"); + oldCol.setForeignKeyIndex("ix_ab"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewReferences()).isNull(); - assertThat(getAlterColumn(diff).getOldReferences()).isEqualTo("abc"); + assertThat(getAlterColumn(diff).getReferences()).isNull(); + assertThat(getAlterColumn(diff).getForeignKeyName()).isNull(); + assertThat(getAlterColumn(diff).getForeignKeyIndex()).isNull(); + + assertThat(getAlterColumn(diff).getDropForeignKey()).isEqualTo("fk_ab"); + assertThat(getAlterColumn(diff).getDropForeignKeyIndex()).isEqualTo("ix_ab"); } @Test @@ -175,14 +180,24 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); - newCol.setReferences("abc"); + newCol.setReferences("ab"); + newCol.setForeignKeyName("fk_ab"); + newCol.setForeignKeyIndex("ix_ab"); + MColumn oldCol = basic(); oldCol.setReferences("d"); + oldCol.setForeignKeyName("fk_d"); + oldCol.setForeignKeyIndex("ix_d"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).getNewReferences()).isEqualTo("abc"); - assertThat(getAlterColumn(diff).getOldReferences()).isEqualTo("d"); + + assertThat(getAlterColumn(diff).getReferences()).isEqualTo("ab"); + assertThat(getAlterColumn(diff).getForeignKeyName()).isEqualTo("fk_ab"); + assertThat(getAlterColumn(diff).getForeignKeyIndex()).isEqualTo("ix_ab"); + + assertThat(getAlterColumn(diff).getDropForeignKey()).isEqualTo("fk_d"); + assertThat(getAlterColumn(diff).getDropForeignKeyIndex()).isEqualTo("ix_d"); } @Test @@ -190,11 +205,11 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); - newCol.setUnique(true); + newCol.setUnique("uq_one"); basic().compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).isUnique()).isEqualTo(true); + assertThat(getAlterColumn(diff).getUnique()).isEqualTo("uq_one"); } @Test @@ -203,11 +218,11 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); - oldCol.setUnique(true); + oldCol.setUnique("uq_one"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).isUnique()).isEqualTo(false); + assertThat(getAlterColumn(diff).getDropUnique()).isEqualTo("uq_one"); } @Test @@ -215,11 +230,14 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); - newCol.setUniqueOneToOne(true); - basic().compare(diff, table, newCol); + newCol.setUniqueOneToOne("uq_new"); + MColumn oldCol = basic(); + oldCol.setUniqueOneToOne("uq_old"); + oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).isUniqueOneToOne()).isEqualTo(true); + assertThat(getAlterColumn(diff).getUniqueOneToOne()).isEqualTo("uq_new"); + assertThat(getAlterColumn(diff).getDropUnique()).isEqualTo("uq_old"); } @Test @@ -228,11 +246,11 @@ public class MColumnTest { ModelDiff diff = diff(); MColumn newCol = basic(); MColumn oldCol = basic(); - oldCol.setUniqueOneToOne(true); + oldCol.setUniqueOneToOne("uq_new"); oldCol.compare(diff, table, newCol); assertChanges(diff); - assertThat(getAlterColumn(diff).isUniqueOneToOne()).isEqualTo(false); + assertThat(getAlterColumn(diff).getDropUnique()).isEqualTo("uq_new"); } @Test diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java index 13617e9e9..e7266f869 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java @@ -100,9 +100,9 @@ public class MTableTest { assertThat(alterColumn.getColumnName()).isEqualTo("name"); assertThat(alterColumn.getType()).isEqualTo("varchar(30)"); assertThat(alterColumn.isNotnull()).isEqualTo(true); - assertThat(alterColumn.isUnique()).isNull(); - assertThat(alterColumn.getNewCheckConstraint()).isNull(); - assertThat(alterColumn.getNewReferences()).isNull(); + assertThat(alterColumn.getUnique()).isNull(); + assertThat(alterColumn.getCheckConstraint()).isNull(); + assertThat(alterColumn.getReferences()).isNull(); assertThat(diff.getDropChanges()).hasSize(0); diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitorTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitorTest.java index 17b9f8b8b..ac84fd0e7 100644 --- a/src/test/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitorTest.java +++ b/src/test/java/com/avaje/ebean/dbmigration/model/build/ModelBuildBeanVisitorTest.java @@ -3,6 +3,8 @@ package com.avaje.ebean.dbmigration.model.build; import com.avaje.ebean.BaseTestCase; import com.avaje.ebean.Ebean; +import com.avaje.ebean.config.DbConstraintNaming; +import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl; import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebean.dbmigration.model.MTable; import com.avaje.ebean.dbmigration.model.ModelContainer; @@ -20,7 +22,10 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase { ModelContainer model = new ModelContainer(); - ModelBuildContext ctx = new ModelBuildContext(model); + PlatformDdl platformDdl = defaultServer.getDatabasePlatform().getPlatformDdl(); + DbConstraintNaming constraintNaming = defaultServer.getServerConfig().getConstraintNaming(); + ModelBuildContext ctx = new ModelBuildContext(model, constraintNaming, platformDdl); + ModelBuildBeanVisitor addTable = new ModelBuildBeanVisitor(ctx); new VisitAllUsing(addTable, defaultServer).visitAllBeans(); diff --git a/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java b/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java index b84e64671..24788d93a 100644 --- a/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java +++ b/src/test/java/com/avaje/tests/query/TestQueryFindPagedList.java @@ -45,9 +45,6 @@ public class TestQueryFindPagedList extends BaseTestCase { PagedList pagedList = Ebean.find(Order.class).findPagedList(0, 3); - LoggedSqlCollector.start(); - Thread.sleep(1); // give slf4j a little time in this multithreaded test case - Future rowCount = pagedList.getFutureRowCount(); List orders = pagedList.getList(); @@ -56,17 +53,9 @@ public class TestQueryFindPagedList extends BaseTestCase { Integer totalRowCountWithTimeout = rowCount.get(30, TimeUnit.SECONDS); Integer totalRowCountViaFuture = rowCount.get(); - List loggedSql = LoggedSqlCollector.stop(); - assertTrue(orders.size() < totalRowCount); assertEquals(Integer.valueOf(totalRowCount), totalRowCountViaFuture); assertEquals(Integer.valueOf(totalRowCount), totalRowCountWithTimeout); - assertEquals(2, loggedSql.size()); - - String firstTxn = loggedSql.get(0).substring(0, 10); - String secTxn = loggedSql.get(1).substring(0, 10); - - assertNotEquals(firstTxn, secTxn); } diff --git a/src/test/resources/assert/BaseTableDdlTest/createTable-rollbackFirst.txt b/src/test/resources/assert/BaseTableDdlTest/createTable-rollbackFirst.txt index 3534ef19b..01538b4a9 100644 --- a/src/test/resources/assert/BaseTableDdlTest/createTable-rollbackFirst.txt +++ b/src/test/resources/assert/BaseTableDdlTest/createTable-rollbackFirst.txt @@ -1,3 +1,3 @@ -alter table mytable drop constraint fk_mytable_order_id; -drop index ix_mytable_order_id; +alter table mytable drop constraint if exists fk_mytable_order_id; +drop index if exists ix_mytable_order_id; diff --git a/src/test/resources/container/test-compoundkey.xml b/src/test/resources/container/test-compoundkey.xml index b9f167021..a38205d98 100644 --- a/src/test/resources/container/test-compoundkey.xml +++ b/src/test/resources/container/test-compoundkey.xml @@ -2,26 +2,26 @@ - + - + - + - + - + - + diff --git a/src/test/resources/container/test-create-table.xml b/src/test/resources/container/test-create-table.xml index b8570a370..22ad62f4a 100644 --- a/src/test/resources/container/test-create-table.xml +++ b/src/test/resources/container/test-create-table.xml @@ -4,7 +4,7 @@ - + diff --git a/src/test/resources/dbmigration/app1/v1.0.xml b/src/test/resources/dbmigration/app1/v1.0.xml index 2bf781566..20d45b80a 100644 --- a/src/test/resources/dbmigration/app1/v1.0.xml +++ b/src/test/resources/dbmigration/app1/v1.0.xml @@ -26,7 +26,7 @@ - + diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 4d273cc87..b9cfed6a0 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -23,7 +23,7 @@ ebean.autofetch.traceUsageCollection=false ebean.ddl.generate=true ebean.ddl.run=true -datasource.default=h2 +datasource.default=pg ebean.persistBatch=NONE ebean.persistBatchOnCascade=ALL diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 816e4a15b..6fb0362e4 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -33,8 +33,6 @@ - - @@ -42,9 +40,5 @@ - - - - - + \ No newline at end of file