mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#374 - Move db constraint max length to database platform
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,21 @@ package com.avaje.ebean.config;
|
||||
*/
|
||||
public class DbConstraintNaming {
|
||||
|
||||
/**
|
||||
* Defines how constraint names are shortened if required based on platform limitations.
|
||||
*/
|
||||
public interface MaxLength {
|
||||
|
||||
/**
|
||||
* Truncate or shorten the constraint name to support DB platform limitations.
|
||||
* <p>
|
||||
* There is a default implementation of this which is used if an implementation is
|
||||
* not specified.
|
||||
* </p>
|
||||
*/
|
||||
String maxLength(String constraintName, int count);
|
||||
}
|
||||
|
||||
protected String pkPrefix = "pk_";
|
||||
protected String pkSuffix = "";
|
||||
|
||||
@@ -28,11 +43,27 @@ public class DbConstraintNaming {
|
||||
|
||||
protected boolean lowerCaseNames = true;
|
||||
|
||||
protected MaxLength maxLength;
|
||||
|
||||
protected DbConstraintNormalise normalise = new DbConstraintNormalise();
|
||||
|
||||
public DbConstraintNaming() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MaxLength implementation used to truncate/shorten db constraint names as necessary.
|
||||
*/
|
||||
public MaxLength getMaxLength() {
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MaxLength implementation used to truncate/shorten db constraint names as necessary.
|
||||
*/
|
||||
public void setMaxLength(MaxLength maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary key constraint name.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ public class DB2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "db2";
|
||||
this.maxTableNameLength = 18;
|
||||
this.maxConstraintNameLength = 18;
|
||||
this.sqlLimiter = new Db2SqlLimiter();
|
||||
this.platformDdl = new DB2Ddl(dbTypeMap, dbIdentity);
|
||||
|
||||
@@ -26,7 +27,6 @@ public class DB2Platform extends DatabasePlatform {
|
||||
dbTypeMap.put(Types.REAL, new DbType("real"));
|
||||
dbTypeMap.put(Types.TINYINT, new DbType("smallint"));
|
||||
dbTypeMap.put(Types.DECIMAL, new DbType("decimal", 15));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -152,6 +152,12 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected int maxTableNameLength = 60;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Instantiates a new database platform.
|
||||
*/
|
||||
@@ -179,6 +185,13 @@ public class DatabasePlatform {
|
||||
return maxTableNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum constraint name allowed for the platform.
|
||||
*/
|
||||
public int getMaxConstraintNameLength() {
|
||||
return maxConstraintNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform specific DDL.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
/**
|
||||
* Built in supported platforms.
|
||||
*/
|
||||
public enum DbPlatformName {
|
||||
|
||||
/**
|
||||
* Generic base platform configured via properties or code.
|
||||
*/
|
||||
GENERIC,
|
||||
|
||||
/**
|
||||
* H2.
|
||||
*/
|
||||
H2,
|
||||
|
||||
/**
|
||||
* Postgres.
|
||||
*/
|
||||
POSTGRES,
|
||||
|
||||
/**
|
||||
* MySql.
|
||||
*/
|
||||
MYSQL,
|
||||
|
||||
/**
|
||||
* Oracle.
|
||||
*/
|
||||
ORACLE,
|
||||
|
||||
/**
|
||||
* Microsoft SQL Server.
|
||||
*/
|
||||
SQLSERVER,
|
||||
|
||||
/**
|
||||
* DB2.
|
||||
*/
|
||||
DB2,
|
||||
|
||||
/**
|
||||
* SQLite.
|
||||
*/
|
||||
SQLITE
|
||||
}
|
||||
@@ -15,6 +15,7 @@ public class Oracle10Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "oracle";
|
||||
this.maxTableNameLength = 30;
|
||||
this.maxConstraintNameLength = 30;
|
||||
// OnQueryOnly.CLOSE as a performance optimisation on Oracle
|
||||
this.onQueryOnly = OnQueryOnly.CLOSE;
|
||||
this.dbEncrypt = new Oracle10DbEncrypt();
|
||||
@@ -54,8 +55,7 @@ public class Oracle10Platform extends DatabasePlatform {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds,
|
||||
String seqName, int batchSize) {
|
||||
public IdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) {
|
||||
|
||||
return new OracleSequenceIdGenerator(be, ds, seqName, batchSize);
|
||||
}
|
||||
|
||||
@@ -2,13 +2,30 @@ package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.config.DbMigrationConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DB2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import com.avaje.ebean.config.dbplatform.H2Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MsSqlServer2005Platform;
|
||||
import com.avaje.ebean.config.dbplatform.MySqlPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.Oracle10Platform;
|
||||
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SQLitePlatform;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import com.avaje.ebean.dbmigration.model.CurrentModel;
|
||||
import com.avaje.ebean.dbmigration.model.MigrationModel;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDdlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.ModelDiff;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -17,38 +34,131 @@ public class DbMigration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
private SpiEbeanServer server;
|
||||
|
||||
private final DbMigrationConfig migrationConfig;
|
||||
private DbMigrationConfig migrationConfig;
|
||||
|
||||
private String pathToResources = "src/main/resources";
|
||||
|
||||
private DatabasePlatform databasePlatform;
|
||||
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
private DbConstraintNaming constraintNaming;
|
||||
|
||||
public DbMigration() {
|
||||
this(Ebean.getDefaultServer());
|
||||
DbOffline.asH2();
|
||||
}
|
||||
|
||||
public DbMigration(EbeanServer ebeanServer) {
|
||||
public void setPathToResources(String pathToResources) {
|
||||
this.pathToResources = pathToResources;
|
||||
}
|
||||
|
||||
public void setServer(EbeanServer ebeanServer) {
|
||||
this.server = (SpiEbeanServer) ebeanServer;
|
||||
this.migrationConfig = server.getServerConfig().getMigrationConfig();
|
||||
setServerConfig(server.getServerConfig());
|
||||
}
|
||||
|
||||
public void writeCurrent() {
|
||||
|
||||
CurrentModel currentModel = new CurrentModel(server);
|
||||
|
||||
File writeTo = getWritePath();
|
||||
logger.info("... write to {}", writeTo.getAbsolutePath());
|
||||
currentModel.writeMigration(writeTo);
|
||||
public void setServerConfig(ServerConfig config) {
|
||||
if (this.serverConfig == null) {
|
||||
this.serverConfig = config;
|
||||
}
|
||||
if (migrationConfig == null) {
|
||||
this.migrationConfig = serverConfig.getMigrationConfig();
|
||||
}
|
||||
if (constraintNaming == null) {
|
||||
this.constraintNaming = serverConfig.getConstraintNaming();
|
||||
}
|
||||
}
|
||||
|
||||
public File getWritePath() {
|
||||
File resourceRootDir = new File("./dbmigration-test/resources");
|
||||
public void setPlatform(DbPlatformName platform) {
|
||||
setPlatform(getPlatform(platform));
|
||||
}
|
||||
|
||||
public void setPlatform(DatabasePlatform databasePlatform) {
|
||||
this.databasePlatform = databasePlatform;
|
||||
DbOffline.setPlatform(databasePlatform.getName());
|
||||
}
|
||||
|
||||
|
||||
public void runMigration() throws IOException {
|
||||
|
||||
setDefaults();
|
||||
|
||||
try {
|
||||
MigrationModel migrationModel = new MigrationModel(migrationConfig.getResourcePath());
|
||||
ModelContainer migrated = migrationModel.read();
|
||||
int nextMajorVersion = migrationModel.getNextMajorVersion();
|
||||
|
||||
logger.info("next migration version {}", nextMajorVersion);
|
||||
|
||||
CurrentModel currentModel = new CurrentModel(server, constraintNaming);
|
||||
ModelContainer current = currentModel.read();
|
||||
|
||||
ModelDiff diff = new ModelDiff(migrated);
|
||||
diff.compareTo(current);
|
||||
Migration dbMigration = diff.getMigration();
|
||||
|
||||
ModelDdlWriter writer = new ModelDdlWriter(databasePlatform, serverConfig);
|
||||
writer.processMigration(dbMigration);
|
||||
|
||||
File writePath = getWritePath();
|
||||
|
||||
logger.info("migration writing version {} to {}", nextMajorVersion, writePath.getAbsolutePath());
|
||||
writer.writeMigration(writePath, nextMajorVersion);
|
||||
|
||||
} finally {
|
||||
DbOffline.reset();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setDefaults() {
|
||||
if (server == null) {
|
||||
String set = DbOffline.getPlatform();
|
||||
setServer(Ebean.getDefaultServer());
|
||||
}
|
||||
if (databasePlatform == null) {
|
||||
databasePlatform = server.getDatabasePlatform();
|
||||
}
|
||||
}
|
||||
|
||||
protected File getWritePath() {
|
||||
|
||||
// path to src/main/resources in typical maven project
|
||||
File resourceRootDir = new File(pathToResources);
|
||||
|
||||
// expect to be a relative path
|
||||
String resourcePath = migrationConfig.getResourcePath();
|
||||
|
||||
// expect to be a path to something like - src/main/resources/dbmigration/myapp
|
||||
File path = new File(resourceRootDir, resourcePath);
|
||||
if (!path.exists()) {
|
||||
path.mkdirs();
|
||||
if (!path.mkdirs()) {
|
||||
logger.debug("Unable to ensure migration directory exists at {}", path.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
return new File(path, "migration-current.xml");
|
||||
return path;
|
||||
}
|
||||
|
||||
protected DatabasePlatform getPlatform(DbPlatformName platform) {
|
||||
switch (platform) {
|
||||
case H2:
|
||||
return new H2Platform();
|
||||
case POSTGRES:
|
||||
return new PostgresPlatform();
|
||||
case MYSQL:
|
||||
return new MySqlPlatform();
|
||||
case ORACLE:
|
||||
return new Oracle10Platform();
|
||||
case SQLSERVER:
|
||||
return new MsSqlServer2005Platform();
|
||||
case DB2:
|
||||
return new DB2Platform();
|
||||
case SQLITE:
|
||||
return new SQLitePlatform();
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Platform missing? " + platform);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.config.dbplatform.DbPlatformName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -12,7 +13,9 @@ public class DbOffline {
|
||||
|
||||
private static final String KEY = "ebean.dboffline";
|
||||
|
||||
public static final String H2 = "H2";
|
||||
public static void setPlatform(DbPlatformName dbPlatform) {
|
||||
System.setProperty(KEY, dbPlatform.name());
|
||||
}
|
||||
|
||||
public static void setPlatform(String platformName) {
|
||||
System.setProperty(KEY, platformName);
|
||||
@@ -23,7 +26,7 @@ public class DbOffline {
|
||||
}
|
||||
|
||||
public static void asH2() {
|
||||
setPlatform(H2);
|
||||
setPlatform(DbPlatformName.H2);
|
||||
}
|
||||
|
||||
public static boolean isSet() {
|
||||
|
||||
@@ -62,10 +62,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
if (generateDdl) {
|
||||
writeDrop(getDropFileName());
|
||||
writeCreate(getCreateFileName());
|
||||
|
||||
String mn = server.getName() + "-migration.xml";
|
||||
File migrationXml = new File(mn);
|
||||
writeMigration(migrationXml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,11 +118,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMigration(File file) {
|
||||
|
||||
currentModel().writeMigration(file);
|
||||
}
|
||||
|
||||
public String generateCreateDdl() {
|
||||
|
||||
try {
|
||||
@@ -138,11 +129,11 @@ public class DdlGenerator implements SpiEbeanPlugin {
|
||||
}
|
||||
|
||||
protected String getDropFileName() {
|
||||
return server.getName() + "-drop.sql";
|
||||
return server.getName() + "-drop-all.sql";
|
||||
}
|
||||
|
||||
protected String getCreateFileName() {
|
||||
return server.getName() + "-create.sql";
|
||||
return server.getName() + "-create-all.sql";
|
||||
}
|
||||
|
||||
protected CurrentModel currentModel() {
|
||||
|
||||
@@ -14,6 +14,11 @@ public interface DdlBuffer {
|
||||
*/
|
||||
MConfiguration getConfiguration();
|
||||
|
||||
/**
|
||||
* Return true if the buffer is empty.
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
/**
|
||||
* Append DDL content to the buffer.
|
||||
*/
|
||||
|
||||
@@ -20,7 +20,24 @@ public class DdlWrite {
|
||||
|
||||
private final DdlBuffer rollbackForeignKeys;
|
||||
|
||||
private final DdlBuffer rollbackLast;
|
||||
private final DdlBuffer rollback;
|
||||
|
||||
/**
|
||||
* For DDL that drops tables and columns etc.
|
||||
*
|
||||
* This DDL typically can not run automatically in production as there is most commonly
|
||||
* existing servers running the application using these tables and columns. Typically
|
||||
* these drop statements may be executed AFTER all the servers in the application have
|
||||
* migrated onto new code.
|
||||
*/
|
||||
private final DdlBuffer drop;
|
||||
|
||||
/**
|
||||
* For use when History is turned off for a base table or history is no longer
|
||||
* desired on specific columns. This DDL should typically execute manually after review
|
||||
* by DBA's.
|
||||
*/
|
||||
private final DdlBuffer dropHistory;
|
||||
|
||||
/**
|
||||
* Create without any configuration or current model (no history support).
|
||||
@@ -38,7 +55,9 @@ public class DdlWrite {
|
||||
this.applyForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.applyHistory = new BaseDdlBuffer(configuration);
|
||||
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
|
||||
this.rollbackLast = new BaseDdlBuffer(configuration);
|
||||
this.rollback = new BaseDdlBuffer(configuration);
|
||||
this.drop = new BaseDdlBuffer(configuration);
|
||||
this.dropHistory = new BaseDdlBuffer(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,6 +71,29 @@ public class DdlWrite {
|
||||
return currentModel.getTable(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the apply buffers are all empty.
|
||||
*/
|
||||
public boolean isApplyEmpty() {
|
||||
return apply.getBuffer().isEmpty()
|
||||
&& applyForeignKeys.getBuffer().isEmpty()
|
||||
&& applyHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true the drop buffer is empty.
|
||||
*/
|
||||
public boolean isDropEmpty() {
|
||||
return drop.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true the drop history buffer is empty.
|
||||
*/
|
||||
public boolean isDropHistoryEmpty() {
|
||||
return dropHistory.getBuffer().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that APPLY DDL is written to.
|
||||
*/
|
||||
@@ -84,13 +126,33 @@ public class DdlWrite {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that ROLLBACK DDL is written to (typically drop tables).
|
||||
* Return the buffer that ROLLBACK DDL is written to which is considered safe to run when
|
||||
* apply changes fail to execute. This will reverse the apply changes typically dropping
|
||||
* newly created tables, foreign keys etc.
|
||||
* <p>
|
||||
* Statements added to this rollback buffer are executed after foreign key rollback
|
||||
* When apply changes are made against DB's that support transactional DDL you could argue
|
||||
* that these rollback statements are not necessary.
|
||||
* <p>
|
||||
* Note that statements added to this rollback buffer are executed after foreign key rollback
|
||||
* has been executed.
|
||||
*/
|
||||
public DdlBuffer rollback() {
|
||||
return rollbackLast;
|
||||
return rollback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that destructive changes are written to. This is typically drop table and
|
||||
* drop column.
|
||||
*/
|
||||
public DdlBuffer drop() {
|
||||
return drop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer that is used when history is no longer required on a table or specific columns.
|
||||
*/
|
||||
public DdlBuffer dropHistory() {
|
||||
return dropHistory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -22,14 +23,18 @@ public interface TableDdl {
|
||||
*/
|
||||
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the drop column change.
|
||||
*/
|
||||
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the alter column changes.
|
||||
*/
|
||||
void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the drop column change.
|
||||
*/
|
||||
void generate(DdlWrite writer, DropTable dropTable) throws IOException;
|
||||
|
||||
/**
|
||||
* Write the drop column change.
|
||||
*/
|
||||
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,13 @@ import com.avaje.ebean.dbmigration.model.MConfiguration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Base implementation of DdlBuffer using an underlying writer.
|
||||
*/
|
||||
public class BaseDdlBuffer implements DdlBuffer {
|
||||
|
||||
protected final Writer writer;
|
||||
protected final StringWriter writer;
|
||||
|
||||
protected final MConfiguration configuration;
|
||||
|
||||
@@ -26,6 +25,11 @@ public class BaseDdlBuffer implements DdlBuffer {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return writer.getBuffer().length() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException {
|
||||
if (foreignKeyRestrict != null && !foreignKeyRestrict.isEmpty()) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.Column;
|
||||
import com.avaje.ebean.dbmigration.migration.CreateTable;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.DropTable;
|
||||
import com.avaje.ebean.dbmigration.migration.ForeignKey;
|
||||
import com.avaje.ebean.dbmigration.model.MTable;
|
||||
|
||||
@@ -460,15 +461,20 @@ public class BaseTableDdl implements TableDdl {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropTable dropTable) throws IOException {
|
||||
|
||||
String tableName = dropTable.getName();
|
||||
|
||||
dropTable(writer.drop(), tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
|
||||
|
||||
String tableName = dropColumn.getTableName();
|
||||
|
||||
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
|
||||
|
||||
// no good rollback option here, it is best if drop columns
|
||||
// are put into a separate changeSet that is run last
|
||||
alterTableDropColumn(writer.drop(), tableName, dropColumn.getColumnName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -11,7 +11,6 @@ public class DB2Ddl extends PlatformDdl {
|
||||
public DB2Ddl(DbTypeMap platformTypes, DbIdentity dbIdentity) {
|
||||
super(platformTypes, dbIdentity);
|
||||
this.identitySuffix = " generated by default as identity";
|
||||
this.maxConstraintNameLength = 18;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.VowelRemover;
|
||||
|
||||
/**
|
||||
* Default implementation used to truncate or shorten db constraint names as required.
|
||||
*/
|
||||
public class DefaultConstraintMaxLength implements DbConstraintNaming.MaxLength {
|
||||
|
||||
private final int maxConstraintNameLength;
|
||||
|
||||
public DefaultConstraintMaxLength(int maxConstraintNameLength) {
|
||||
this.maxConstraintNameLength = maxConstraintNameLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a maximum length to the constraint name.
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ public class Oracle10Ddl extends PlatformDdl {
|
||||
this.dropTableIfExists = "drop table ";
|
||||
this.dropSequenceIfExists = "drop sequence ";
|
||||
this.dropTableCascade = " cascade constraints purge";
|
||||
this.maxConstraintNameLength = 30;
|
||||
this.foreignKeyRestrict = "";
|
||||
}
|
||||
|
||||
|
||||
@@ -57,12 +57,6 @@ public class PlatformDdl {
|
||||
*/
|
||||
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);
|
||||
@@ -73,27 +67,6 @@ public class PlatformDdl {
|
||||
return new BaseDdlHandler(serverConfig.getNamingConvention(), serverConfig.getConstraintNaming(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a maximum length to the constraint name.
|
||||
* <p>
|
||||
* 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) {
|
||||
|
||||
return dbIdentity.useIdentityType(modelIdentityType);
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
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.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
|
||||
import com.avaje.ebean.dbmigration.model.build.ModelBuildBeanVisitor;
|
||||
import com.avaje.ebean.dbmigration.model.build.ModelBuildContext;
|
||||
import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
@@ -25,7 +22,7 @@ public class CurrentModel {
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final PlatformDdl platformDdl;
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
private ModelContainer model;
|
||||
|
||||
@@ -37,9 +34,36 @@ public class CurrentModel {
|
||||
* Construct with a given EbeanServer instance.
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server) {
|
||||
this(server, server.getServerConfig().getConstraintNaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct with a given EbeanServer, platformDdl and constraintNaming convention.
|
||||
* <p>
|
||||
* Note the EbeanServer is just used to read the BeanDescriptors and platformDdl supplies
|
||||
* the platform specific handling on
|
||||
* </p>
|
||||
*/
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming) {
|
||||
this.server = server;
|
||||
this.platformDdl = server.getDatabasePlatform().getPlatformDdl();
|
||||
this.constraintNaming = server.getServerConfig().getConstraintNaming();
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = maxLength(server, constraintNaming);
|
||||
}
|
||||
|
||||
public CurrentModel(SpiEbeanServer server, DbConstraintNaming constraintNaming, int maxConstraintLength) {
|
||||
this.server = server;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.maxLength = new DefaultConstraintMaxLength(maxConstraintLength);
|
||||
}
|
||||
|
||||
private DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) {
|
||||
|
||||
if (naming.getMaxLength() != null) {
|
||||
return naming.getMaxLength();
|
||||
}
|
||||
|
||||
int maxConstraintNameLength = server.getDatabasePlatform().getMaxConstraintNameLength();
|
||||
return new DefaultConstraintMaxLength(maxConstraintNameLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +72,8 @@ public class CurrentModel {
|
||||
public ModelContainer read() {
|
||||
if (model == null) {
|
||||
model = new ModelContainer();
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, platformDdl);
|
||||
|
||||
ModelBuildContext context = new ModelBuildContext(model, constraintNaming, maxLength);
|
||||
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
|
||||
VisitAllUsing visit = new VisitAllUsing(visitor, server);
|
||||
visit.visitAllBeans();
|
||||
@@ -71,19 +96,6 @@ public class CurrentModel {
|
||||
return changeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write as migration xml to the given file.
|
||||
*/
|
||||
public void writeMigration(File file) {
|
||||
|
||||
ChangeSet changeSet = getChangeSet();
|
||||
Migration migration = new Migration();
|
||||
migration.getChangeSet().add(changeSet);
|
||||
|
||||
MigrationXmlWriter writer = new MigrationXmlWriter();
|
||||
writer.write(migration, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'Create' DDL.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,8 @@ public class MigrationModel {
|
||||
|
||||
private final String resourcePath;
|
||||
|
||||
int nextMajorVersion;
|
||||
|
||||
public MigrationModel(String resourcePath) {
|
||||
this.resourcePath = normaliseResourcePath(resourcePath);
|
||||
}
|
||||
@@ -55,10 +57,16 @@ public class MigrationModel {
|
||||
return readVersions;
|
||||
}
|
||||
|
||||
public int getNextMajorVersion() {
|
||||
return nextMajorVersion;
|
||||
}
|
||||
|
||||
private void readMigrations() {
|
||||
|
||||
for (int majorVersion = 1; majorVersion < 100; majorVersion++) {
|
||||
if (!readMinorVersions(majorVersion)){
|
||||
// no major.0 version so stopping
|
||||
nextMajorVersion = majorVersion;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -82,6 +90,7 @@ public class MigrationModel {
|
||||
|
||||
Migration migration = MigrationXmlReader.readMaybe(path);
|
||||
if (migration == null) {
|
||||
logger.info("... no migration at path:{}", path);
|
||||
return false;
|
||||
}
|
||||
readVersions.add(version);
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
|
||||
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ModelDdlWriter {
|
||||
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final DatabasePlatform platform;
|
||||
|
||||
private Migration dbMigration;
|
||||
|
||||
private DdlWrite write;
|
||||
|
||||
public ModelDdlWriter(DatabasePlatform platform, ServerConfig serverConfig) {
|
||||
this.platform = platform;
|
||||
this.serverConfig = serverConfig;
|
||||
}
|
||||
|
||||
public void processMigration(Migration dbMigration) throws IOException {
|
||||
this.dbMigration = dbMigration;
|
||||
this.write = new DdlWrite();
|
||||
|
||||
DdlHandler handler = handler();
|
||||
|
||||
List<ChangeSet> changeSets = dbMigration.getChangeSet();
|
||||
for (ChangeSet changeSet : changeSets) {
|
||||
handler.generate(write, changeSet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write as migration xml to the given file.
|
||||
*/
|
||||
public void writeMigration(File resourcePath, int migrationVersion) throws IOException {
|
||||
|
||||
File file = new File(resourcePath, "v"+migrationVersion+".0.xml");
|
||||
|
||||
MigrationXmlWriter xmlWriter = new MigrationXmlWriter();
|
||||
xmlWriter.write(dbMigration, file);
|
||||
|
||||
if (!write.isApplyEmpty()) {
|
||||
FileWriter ddlWriter = createWriter(resourcePath, migrationVersion, ".0-apply.sql");
|
||||
try {
|
||||
writeApplyDdl(ddlWriter);
|
||||
ddlWriter.flush();
|
||||
} finally {
|
||||
ddlWriter.close();
|
||||
}
|
||||
|
||||
FileWriter rbWriter = createWriter(resourcePath, migrationVersion, ".0-applyRollback.sql");
|
||||
try {
|
||||
writeApplyRollbackDdl(rbWriter);
|
||||
rbWriter.flush();
|
||||
} finally {
|
||||
rbWriter.close();
|
||||
}
|
||||
}
|
||||
|
||||
String content = write.drop().getBuffer();
|
||||
if (!content.isEmpty()) {
|
||||
writeFile(resourcePath, migrationVersion, ".0-drop.sql", content);
|
||||
}
|
||||
|
||||
String dropHistory = write.dropHistory().getBuffer();
|
||||
if (!dropHistory.isEmpty()) {
|
||||
writeFile(resourcePath, migrationVersion, ".0-dropHistory.sql", dropHistory);
|
||||
}
|
||||
}
|
||||
|
||||
private FileWriter createWriter(File resourcePath, int migrationVersion, String suffix) throws IOException {
|
||||
|
||||
File applyFile = new File(resourcePath, "v" + migrationVersion + suffix);
|
||||
return new FileWriter(applyFile);
|
||||
}
|
||||
|
||||
private void writeFile(File resourcePath, int migrationVersion, String suffix, String content) throws IOException {
|
||||
|
||||
FileWriter ddlWriter =createWriter(resourcePath, migrationVersion, suffix);
|
||||
try {
|
||||
ddlWriter.append(content);
|
||||
ddlWriter.flush();
|
||||
} finally {
|
||||
ddlWriter.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the 'Create' DDL.
|
||||
*/
|
||||
private void writeApplyDdl(Writer writer) throws IOException {
|
||||
|
||||
writer.append(write.apply().getBuffer());
|
||||
writer.append(write.applyForeignKeys().getBuffer());
|
||||
writer.append(write.applyHistory().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the 'Rollback' DDL.
|
||||
*/
|
||||
private void writeApplyRollbackDdl(Writer writer) throws IOException {
|
||||
|
||||
writer.append(write.rollbackForeignKeys().getBuffer());
|
||||
writer.append(write.rollback().getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the platform specific DdlHandler (to generate DDL).
|
||||
*/
|
||||
private DdlHandler handler() {
|
||||
return platform.createDdlHandler(serverConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,10 @@ package com.avaje.ebean.dbmigration.model;
|
||||
|
||||
import com.avaje.ebean.dbmigration.migration.AddColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.AlterColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSet;
|
||||
import com.avaje.ebean.dbmigration.migration.ChangeSetType;
|
||||
import com.avaje.ebean.dbmigration.migration.DropColumn;
|
||||
import com.avaje.ebean.dbmigration.migration.Migration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -49,6 +52,30 @@ public class ModelDiff {
|
||||
return createChanges;
|
||||
}
|
||||
|
||||
public ChangeSet getApplyChangeSet() {
|
||||
// put the changes into a ChangeSet
|
||||
ChangeSet createChangeSet = new ChangeSet();
|
||||
createChangeSet.setType(ChangeSetType.APPLY);
|
||||
createChangeSet.getChangeSetChildren().addAll(createChanges);
|
||||
return createChangeSet;
|
||||
}
|
||||
|
||||
public ChangeSet getDropChangeSet() {
|
||||
// put the changes into a ChangeSet
|
||||
ChangeSet createChangeSet = new ChangeSet();
|
||||
createChangeSet.setType(ChangeSetType.DROP);
|
||||
createChangeSet.getChangeSetChildren().addAll(dropChanges);
|
||||
return createChangeSet;
|
||||
}
|
||||
|
||||
public Migration getMigration() {
|
||||
|
||||
Migration migration = new Migration();
|
||||
migration.getChangeSet().add(getApplyChangeSet());
|
||||
migration.getChangeSet().add(getDropChangeSet());
|
||||
return migration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of 'drop' changes.
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.avaje.ebean.dbmigration.model.build;
|
||||
|
||||
import com.avaje.ebean.config.DbConstraintNaming;
|
||||
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;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
|
||||
/**
|
||||
@@ -24,12 +23,12 @@ public class ModelBuildContext {
|
||||
|
||||
private final DbConstraintNaming constraintNaming;
|
||||
|
||||
private final PlatformDdl platformDdl;
|
||||
private final DbConstraintNaming.MaxLength maxLength;
|
||||
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming constraintNaming, PlatformDdl platformDdl) {
|
||||
public ModelBuildContext(ModelContainer model, DbConstraintNaming naming, DbConstraintNaming.MaxLength maxLength) {
|
||||
this.model = model;
|
||||
this.constraintNaming = constraintNaming;
|
||||
this.platformDdl = platformDdl;
|
||||
this.constraintNaming = naming;
|
||||
this.maxLength = maxLength;
|
||||
}
|
||||
|
||||
public String primaryKeyName(String tableName) {
|
||||
@@ -65,7 +64,7 @@ public class ModelBuildContext {
|
||||
}
|
||||
|
||||
private String maxLength(String constraintName, int indexCount) {
|
||||
return platformDdl.maxLength(constraintName, indexCount);
|
||||
return maxLength.maxLength(constraintName, indexCount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,6 +60,12 @@ public class DatabasePlatformFactory {
|
||||
private DatabasePlatform byDatabaseName(String dbName) {
|
||||
|
||||
dbName = dbName.toLowerCase();
|
||||
if (dbName.equals("h2")) {
|
||||
return new H2Platform();
|
||||
}
|
||||
if (dbName.equals("mysql")) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
if (dbName.equals("postgres") || dbName.equals("postgres9")) {
|
||||
return new PostgresPlatform();
|
||||
}
|
||||
@@ -72,6 +78,9 @@ public class DatabasePlatformFactory {
|
||||
if (dbName.equals("oracle") || dbName.equals("oracle10")) {
|
||||
return new Oracle10Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver")) {
|
||||
return new MsSqlServer2005Platform();
|
||||
}
|
||||
if (dbName.equals("sqlserver2005")) {
|
||||
return new MsSqlServer2005Platform();
|
||||
}
|
||||
@@ -84,12 +93,6 @@ public class DatabasePlatformFactory {
|
||||
if (dbName.equals("db2")) {
|
||||
return new DB2Platform();
|
||||
}
|
||||
if (dbName.equals("mysql")) {
|
||||
return new MySqlPlatform();
|
||||
}
|
||||
if (dbName.equals("h2")) {
|
||||
return new H2Platform();
|
||||
}
|
||||
if (dbName.equals("sqlite")) {
|
||||
return new SQLitePlatform();
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.avaje.ebean.dbmigration;
|
||||
|
||||
import com.avaje.ebean.BaseTestCase;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class DbMigrationTest extends BaseTestCase {
|
||||
|
||||
@@ -22,7 +21,7 @@ public class DbMigrationTest extends BaseTestCase {
|
||||
DbMigration migration = new DbMigration();
|
||||
DbOffline.reset();
|
||||
|
||||
migration.writeCurrent();
|
||||
//migration.writeCurrent();
|
||||
|
||||
assertThat(DbOffline.isSet()).isFalse();
|
||||
|
||||
|
||||
+4
-3
@@ -4,7 +4,7 @@ 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.ebean.dbmigration.ddlgeneration.platform.DefaultConstraintMaxLength;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebean.dbmigration.model.MTable;
|
||||
import com.avaje.ebean.dbmigration.model.ModelContainer;
|
||||
@@ -22,9 +22,10 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
|
||||
|
||||
ModelContainer model = new ModelContainer();
|
||||
|
||||
PlatformDdl platformDdl = defaultServer.getDatabasePlatform().getPlatformDdl();
|
||||
DbConstraintNaming constraintNaming = defaultServer.getServerConfig().getConstraintNaming();
|
||||
ModelBuildContext ctx = new ModelBuildContext(model, constraintNaming, platformDdl);
|
||||
|
||||
DefaultConstraintMaxLength maxLength = new DefaultConstraintMaxLength(60);
|
||||
ModelBuildContext ctx = new ModelBuildContext(model, constraintNaming, maxLength);
|
||||
|
||||
ModelBuildBeanVisitor addTable = new ModelBuildBeanVisitor(ctx);
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ ebean.autofetch.traceUsageCollection=false
|
||||
|
||||
ebean.ddl.generate=true
|
||||
ebean.ddl.run=true
|
||||
datasource.default=pg
|
||||
datasource.default=mysql
|
||||
|
||||
ebean.persistBatch=NONE
|
||||
ebean.persistBatchOnCascade=ALL
|
||||
|
||||
Reference in New Issue
Block a user