From 68f0c836031ad2f81237f03d307deabe9b3f6ce4 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 20 Jan 2022 08:22:35 +0100 Subject: [PATCH] DB2: Migration generation with Reorg table support (#54) * prototype for reorg table * DB2 Migration fixes * Reorg handled by BaseTableDdl Co-authored-by: Roland Praml --- ebean-ddl-generator/pom.xml | 7 + .../ddlgeneration/platform/BaseTableDdl.java | 51 +++-- .../ddlgeneration/platform/DB2Ddl.java | 113 ++++++++++- .../ddlgeneration/platform/PlatformDdl.java | 13 +- .../dbmigration/DbMigrationTest.java | 2 +- .../test/java/io/localtest/BaseTestCase.java | 4 + .../test/java/misc/migration/v1_1/EBasic.java | 6 +- .../resources/application-test.properties | 10 +- .../src/test/resources/dbinit/db2/1.4.sql | 3 + .../migrationtest/db2/1.0__initial.sql | 3 + .../dbmigration/migrationtest/db2/1.1.sql | 112 +++++++++-- .../migrationtest/db2/1.2__dropsFor_1.1.sql | 10 +- .../dbmigration/migrationtest/db2/1.3.sql | 183 ++++++++++++++++-- .../migrationtest/db2/1.4__dropsFor_1.3.sql | 15 +- .../migrationtest/db2/idx_db2.migrations | 10 +- .../migrationtest/model/1.1.model.xml | 4 + 16 files changed, 471 insertions(+), 75 deletions(-) diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 6a0c9104e..a65f733b8 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -76,6 +76,13 @@ test + + com.ibm.db2 + jcc + 11.5.6.0 + test + + diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 0e80c2676..1acbd7acd 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -35,9 +35,11 @@ import io.ebeaninternal.server.deploy.IdentityMode; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import static io.ebean.util.StringHelper.replace; import static io.ebeaninternal.api.PlatformMatch.matchPlatform; @@ -87,7 +89,11 @@ public class BaseTableDdl implements TableDdl { * columns have been added, removed, included or excluded. */ protected final Map regenerateHistoryTriggers = new LinkedHashMap<>(); - + + private final Set needsReorg = new HashSet<>(); + + private int reorgCount; + private final boolean strictMode; private final HistorySupport historySupport; @@ -144,25 +150,28 @@ public class BaseTableDdl implements TableDdl { void writeBefore(DdlBuffer buffer) throws IOException { if (!before.isEmpty()) { buffer.end(); + flushReorgTables(buffer); + if (withHistory) { + buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine(); + } + for (String ddlScript : before) { + buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue)); + } } - if (!before.isEmpty() && withHistory) { - buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine(); - } - for (String ddlScript : before) { - buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue)); - } } void writeAfter(DdlBuffer buffer) throws IOException { - if (!after.isEmpty() && withHistory) { - buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine(); - } - // here we run post migration scripts - for (String ddlScript : after) { - buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue)); - } if (!after.isEmpty()) { + if (withHistory) { + buffer.append("-- NOTE: table has @History - special migration may be necessary").newLine(); + } + flushReorgTables(buffer); + + // here we run post migration scripts + for (String ddlScript : after) { + buffer.appendStatement(translate(ddlScript, tableName, columnName, defaultValue)); + } buffer.end(); } } @@ -577,6 +586,7 @@ public class BaseTableDdl implements TableDdl { @Override public void generate(DdlWrite writer, CreateIndex index) throws IOException { if (platformInclude(index.getPlatforms())) { + flushReorgTables(writer.apply()); writer.apply().appendStatement(platformDdl.createIndex(new WriteCreateIndex(index))); writer.dropAll().appendStatement(platformDdl.dropIndex(index.getIndexName(), index.getTableName(), Boolean.TRUE.equals(index.isConcurrent()))); } @@ -585,6 +595,7 @@ public class BaseTableDdl implements TableDdl { @Override public void generate(DdlWrite writer, DropIndex dropIndex) throws IOException { if (platformInclude(dropIndex.getPlatforms())) { + flushReorgTables(writer.apply()); writer.apply().appendStatement(platformDdl.dropIndex(dropIndex.getIndexName(), dropIndex.getTableName(), Boolean.TRUE.equals(dropIndex.isConcurrent()))); } } @@ -596,6 +607,7 @@ public class BaseTableDdl implements TableDdl { writer.apply().appendStatement(platformDdl.alterTableDropUniqueConstraint(constraint.getTableName(), constraint.getConstraintName())); } else { + flushReorgTables(writer.apply()); String[] cols = split(constraint.getColumnNames()); String[] nullableColumns = split(constraint.getNullableColumns()); writer.apply().appendStatement(platformDdl.alterTableAddUniqueConstraint(constraint.getTableName(), constraint.getConstraintName(), cols, nullableColumns)); @@ -648,6 +660,7 @@ public class BaseTableDdl implements TableDdl { platformDdl.unlockTables(write.applyHistoryTrigger(), regenerateHistoryTriggers.keySet()); } platformDdl.generateEpilog(write); + flushReorgTables(write.apply()); } @Override @@ -838,11 +851,13 @@ public class BaseTableDdl implements TableDdl { protected void alterColumnNotnull(DdlWrite writer, AlterColumn alter) throws IOException { writer.apply().appendStatement(platformDdl.alterColumnNotnull(alter.getTableName(), alter.getColumnName(), alter.isNotnull())); + needsReorg.add(alter.getTableName()); } protected void alterColumnType(DdlWrite writer, AlterColumn alter) throws IOException { String ddl = platformDdl.alterColumnType(alter.getTableName(), alter.getColumnName(), alter.getType()); if (hasValue(ddl)) { + needsReorg.add(alter.getTableName()); writer.apply().appendStatement(ddl); if (isTrue(alter.isWithHistory()) && historySupport == HistorySupport.TRIGGER_BASED) { regenerateHistoryTriggers(alter.getTableName(), HistoryTableUpdate.Change.ALTER, alter.getColumnName()); @@ -884,6 +899,7 @@ public class BaseTableDdl implements TableDdl { protected void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { platformDdl.alterTableDropColumn(buffer, tableName, columnName); + needsReorg.add(tableName); } protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column, boolean onHistoryTable, boolean withHistory) throws IOException { @@ -903,6 +919,13 @@ public class BaseTableDdl implements TableDdl { } } + protected void flushReorgTables(DdlBuffer buffer) throws IOException { + for (String table : needsReorg) { + buffer.appendStatement(platformDdl.reorgTable(table, ++reorgCount)); + } + needsReorg.clear(); + } + protected boolean isFalse(Boolean value) { return value != null && !value; } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java index 3c84171fe..ac89c21e2 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java @@ -5,44 +5,137 @@ import io.ebean.config.dbplatform.DatabasePlatform; /** * DB2 platform specific DDL. + * + * according to the list + * https://datageek.blog/en/2014/05/06/db2-basics-what-is-a-reorg/ a reorg is + * necessary after + *
    + *
  1. Data type changes that increase the size of a varchar or vargraphic + * column + *
  2. Data type changes that decrease the size of a varchar or vargraphic + * column + *
  3. Altering a column to include NOT NULL + *
  4. Altering a column to inline LOBS + *
  5. Altering a column to compress the system default or turn off compression + * for the system default + *
  6. Altering a table to enable value compression + *
  7. Altering a table to drop a column + *
  8. Changing the PCTFREE for a table + *
  9. Altering a table to turn APEND mode off + *
  10. Altering a table or index to turn compression on + *
+ * + * This is currently handled by BaseTableDdl + * */ public class DB2Ddl extends PlatformDdl { - + public DB2Ddl(DatabasePlatform platform) { super(platform); this.dropTableIfExists = "drop table "; this.dropSequenceIfExists = "drop sequence "; - this.dropConstraintIfExists = "drop constraint"; - this.dropIndexIfExists = "drop index "; + this.dropConstraintIfExists = "NOT USED"; + this.dropIndexIfExists = "NOT USED"; this.identitySuffix = " generated by default as identity"; + this.columnSetNull = "drop not null"; + this.columnSetType = "set data type "; this.inlineUniqueWhenNullable = false; } @Override - public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) { + public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, + String[] nullableColumns) { + StringBuilder sb = new StringBuilder(300); if (nullableColumns == null || nullableColumns.length == 0) { - return super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns); - } + sb.append("alter table ").append(lowerTableName(tableName)); + sb.append(" add constraint ").append(maxConstraintName(uqName)).append(" unique "); + appendColumns(columns, sb); + return sb.toString(); + } if (uqName == null) { throw new NullPointerException(); } - StringBuilder sb = new StringBuilder("create unique index "); - sb.append(uqName).append(" on ").append(tableName).append('('); - + sb.append("create unique index ").append(maxConstraintName(uqName)); + sb.append(" on ").append(lowerTableName(tableName)).append('('); for (int i = 0; i < columns.length; i++) { if (i > 0) { sb.append(","); } - sb.append(columns[i]); + sb.append(lowerColumnName(columns[i])); } sb.append(") exclude null keys"); return sb.toString(); } + @Override + public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) { + return alterTableDropConstraint(tableName, uniqueConstraintName) + "\n" + + dropIndex(uniqueConstraintName, tableName); + } + @Override protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { // do nothing, no on update clause for db2 } + + @Override + public String dropSequence(String sequenceName) { + StringBuilder sb = new StringBuilder(300); + sb.append("delimiter $$\n"); + sb.append("begin\n"); + sb.append("if exists (select seqschema from syscat.sequences where seqschema = current_schema and seqname = '") + .append(maxConstraintName(sequenceName).toUpperCase()).append("') then\n"); + sb.append(" prepare stmt from 'drop sequence ").append(maxConstraintName(sequenceName)).append("';\n"); + sb.append(" execute stmt;\n"); + sb.append("end if;\n"); + sb.append("end$$"); + return sb.toString(); + } + + @Override + public String alterTableDropForeignKey(String tableName, String fkName) { + return alterTableDropConstraint(tableName, fkName); + } + + @Override + public String alterTableDropConstraint(String tableName, String constraintName) { + StringBuilder sb = new StringBuilder(300); + sb.append("delimiter $$\n"); + sb.append("begin\n"); + sb.append("if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = '"); + sb.append(maxConstraintName(constraintName).toUpperCase()); + sb.append("' and tabname = '").append(lowerTableName(tableName).toUpperCase()).append("') then\n"); + + sb.append(" prepare stmt from 'alter table ").append(lowerTableName(tableName)); + sb.append(" drop constraint ").append(maxConstraintName(constraintName)).append("';\n"); + + sb.append(" execute stmt;\n"); + sb.append("end if;\n"); + sb.append("end$$"); + return sb.toString(); + } + + @Override + public String dropIndex(String indexName, String tableName, boolean concurrent) { + StringBuilder sb = new StringBuilder(300); + sb.append("delimiter $$\n"); + sb.append("begin\n"); + sb.append("if exists (select indname from syscat.indexes where indschema = current_schema and indname = '"); + sb.append(maxConstraintName(indexName).toUpperCase()).append("') then\n"); + + sb.append(" prepare stmt from 'drop index ").append(maxConstraintName(indexName)).append("';\n"); + sb.append(" execute stmt;\n"); + sb.append("end if;\n"); + sb.append("end$$"); + return sb.toString(); + } + + @Override + public String reorgTable(String table, int counter) { + // TODO Auto-generated method stub + return "call sysproc.admin_cmd('reorg table " + lowerTableName(table) + "') /* reorg #" + counter + " */"; + } + } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index 59cf38e0d..e4eae0be9 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -307,7 +307,7 @@ public class PlatformDdl { * Return the drop foreign key clause. */ public String alterTableDropForeignKey(String tableName, String fkName) { - return "alter table " + alterTableIfExists + tableName + " " + dropConstraintIfExists + " " + maxConstraintName(fkName); + return "alter table " + alterTableIfExists + lowerTableName(tableName) + " " + dropConstraintIfExists + " " + maxConstraintName(fkName); } /** @@ -772,4 +772,15 @@ public class PlatformDdl { public void addTablePartition(DdlBuffer apply, String partitionMode, String partitionColumn) throws IOException { // only supported by postgres initially } + + /** + * Returns a statement to reorganize the table. This is required mainly for DB2. + * + * @param table the table name + * @param counter to make statements unique. + */ + public String reorgTable(String table, int counter) { + return null; + } + } diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java index aec05f62e..328ecb869 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java @@ -108,7 +108,7 @@ public class DbMigrationTest extends BaseTestCase { // Oracle caches the statement and does not detect schema change. It fails with // an ORA-01007 - if (isOracle()) { + if (isOracle() || isDB2()) { result = server().sqlQuery("select * from migtest_e_basic order by id,id").findList(); } else { result = server().sqlQuery("select * from migtest_e_basic order by id").findList(); diff --git a/ebean-ddl-generator/src/test/java/io/localtest/BaseTestCase.java b/ebean-ddl-generator/src/test/java/io/localtest/BaseTestCase.java index f7634c0e0..7c67e9152 100644 --- a/ebean-ddl-generator/src/test/java/io/localtest/BaseTestCase.java +++ b/ebean-ddl-generator/src/test/java/io/localtest/BaseTestCase.java @@ -51,6 +51,10 @@ public abstract class BaseTestCase { public boolean isSqlServer() { return Platform.SQLSERVER == platform(); } + + public boolean isDB2() { + return Platform.DB2 == platform(); + } public boolean isH2() { return Platform.H2 == platform(); diff --git a/ebean-ddl-generator/src/test/java/misc/migration/v1_1/EBasic.java b/ebean-ddl-generator/src/test/java/misc/migration/v1_1/EBasic.java index 9e5b1742d..50b53f736 100644 --- a/ebean-ddl-generator/src/test/java/misc/migration/v1_1/EBasic.java +++ b/ebean-ddl-generator/src/test/java/misc/migration/v1_1/EBasic.java @@ -5,6 +5,7 @@ import io.ebean.annotation.DbMigration; import io.ebean.annotation.EnumValue; import io.ebean.annotation.Index; import io.ebean.annotation.NotNull; +import io.ebean.annotation.Platform; import javax.persistence.Column; import javax.persistence.Entity; @@ -59,10 +60,11 @@ public class EBasic { @Size(max=127) String name; - + @DbMigration(preAlter = { "-- db2 does not support parial null indices :( - so we have to clean", + "update ${table} set status = 'N' where id = 1" }, platforms = Platform.DB2) @DbMigration(preAlter = "-- rename all collisions") @Column(unique = true) - @Size(max=127) + @Size(max = 127) String description; //@NotNull diff --git a/ebean-ddl-generator/src/test/resources/application-test.properties b/ebean-ddl-generator/src/test/resources/application-test.properties index a162570da..9b56565f5 100644 --- a/ebean-ddl-generator/src/test/resources/application-test.properties +++ b/ebean-ddl-generator/src/test/resources/application-test.properties @@ -1,12 +1,16 @@ ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} -ebean.ddl.generate=true -ebean.ddl.run=true -datasource.default=h2 +ebean.ddl.generate=false +ebean.ddl.run=false +datasource.default=db2 datasource.h2.username=sa datasource.h2.password= datasource.h2.url=jdbc:h2:mem:h2AutoTune +datasource.db2.username=migtest +datasource.db2.password=migtest +datasource.db2.url=jdbc:db2://localhost:50005/migtest + datasource.pg.username=sa datasource.pg.password= datasource.pg.url=jdbc:h2:mem:h2AutoTune diff --git a/ebean-ddl-generator/src/test/resources/dbinit/db2/1.4.sql b/ebean-ddl-generator/src/test/resources/dbinit/db2/1.4.sql index 340fd3334..5efada4cc 100644 --- a/ebean-ddl-generator/src/test/resources/dbinit/db2/1.4.sql +++ b/ebean-ddl-generator/src/test/resources/dbinit/db2/1.4.sql @@ -75,7 +75,9 @@ create table migtest_e_basic ( constraint ck_migtest_e_basic_status2 check ( status2 in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) ); +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) exclude null keys; create table migtest_e_enum ( @@ -129,6 +131,7 @@ create table migtest_e_ref ( name varchar(127) not null, constraint pk_migtest_e_ref primary key (id) ); +-- alterTableAddUniqueConstraint alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); create table migtest_e_softdelete ( diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql index 5d4113a24..6460708c9 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql @@ -75,7 +75,9 @@ create table migtest_e_basic ( constraint ck_migtest_e_basic_status2 check ( status2 in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) ); +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) exclude null keys; create table migtest_e_enum ( @@ -129,6 +131,7 @@ create table migtest_e_ref ( name varchar(127) not null, constraint pk_migtest_e_ref primary key (id) ); +-- alterTableAddUniqueConstraint alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); create table migtest_e_softdelete ( diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.1.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.1.sql index 22e95f519..143edc578 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.1.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.1.sql @@ -23,31 +23,59 @@ alter table migtest_ckey_detail add column two_key varchar(127); alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key) on delete restrict; alter table migtest_ckey_parent add column assoc_id integer; -alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_CASCADE_ONE_ID' and tabname = 'MIGTEST_FK_CASCADE') then + prepare stmt from 'alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id'; + execute stmt; +end if; +end$$; alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete restrict; alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; -alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_SET_NULL_ONE_ID' and tabname = 'MIGTEST_FK_SET_NULL') then + prepare stmt from 'alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id'; + execute stmt; +end if; +end$$; alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; update migtest_e_basic set status = 'A' where status is null; -alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_BASIC_STATUS' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status'; + execute stmt; +end if; +end$$; alter table migtest_e_basic alter column status set default 'A'; alter table migtest_e_basic alter column status set not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?')); -alter table migtest_e_basic drop constraint ck_migtest_e_basic_status2; -alter table migtest_e_basic alter column status2 varchar(127); +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_BASIC_STATUS2' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status2'; + execute stmt; +end if; +end$$; +alter table migtest_e_basic alter column status2 set data type varchar(127); alter table migtest_e_basic alter column status2 drop default; -alter table migtest_e_basic alter column status2 set null; +alter table migtest_e_basic alter column status2 drop not null; --- rename all collisions; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #1 */; +-- db2 does not support parial null indices :( - so we have to clean; +update migtest_e_basic set status = 'N' where id = 1; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_description on migtest_e_basic(description) exclude null keys; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict; -alter table migtest_e_basic alter column user_id set null; +alter table migtest_e_basic alter column user_id drop not null; alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; alter table migtest_e_basic add column new_boolean_field boolean default true not null; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #2 */; update migtest_e_basic set new_boolean_field = old_boolean; alter table migtest_e_basic add column new_boolean_field2 boolean default true not null; @@ -55,17 +83,54 @@ alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); alter table migtest_e_basic add column new_integer integer default 42 not null; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_INDEXTEST2' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_INDEXTEST2') then + prepare stmt from 'drop index uq_migtest_e_basic_indextest2'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_INDEXTEST6' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_INDEXTEST6') then + prepare stmt from 'drop index uq_migtest_e_basic_indextest6'; + execute stmt; +end if; +end$$; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_status_indextest1 on migtest_e_basic(status,indextest1) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_name on migtest_e_basic(name) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest4 on migtest_e_basic(indextest4) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest5 on migtest_e_basic(indextest5) exclude null keys; -alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_ENUM_TEST_STATUS' and tabname = 'MIGTEST_E_ENUM') then + prepare stmt from 'alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status'; + execute stmt; +end if; +end$$; comment on column migtest_e_history.test_string is 'Column altered to long now'; -alter table migtest_e_history alter column test_string bigint; +alter table migtest_e_history alter column test_string set data type bigint; comment on table migtest_e_history is 'We have history now'; +call sysproc.admin_cmd('reorg table migtest_e_history') /* reorg #3 */; -- NOTE: table has @History - special migration may be necessary update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; @@ -74,23 +139,38 @@ alter table migtest_e_history2 add column test_string2 varchar(255); alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2 add column new_column varchar(20); -alter table migtest_e_history4 alter column test_number bigint; +alter table migtest_e_history4 alter column test_number set data type bigint; alter table migtest_e_history5 add column test_boolean boolean default false not null; +call sysproc.admin_cmd('reorg table migtest_e_history2') /* reorg #4 */; +call sysproc.admin_cmd('reorg table migtest_e_history4') /* reorg #5 */; -- NOTE: table has @History - special migration may be necessary update migtest_e_history6 set test_number1 = 42 where test_number1 is null; alter table migtest_e_history6 alter column test_number1 set default 42; alter table migtest_e_history6 alter column test_number1 set not null; -alter table migtest_e_history6 alter column test_number2 set null; +alter table migtest_e_history6 alter column test_number2 drop not null; alter table migtest_e_softdelete add column deleted boolean default false not null; alter table migtest_oto_child add column master_id bigint; +call sysproc.admin_cmd('reorg table migtest_e_history6') /* reorg #6 */; create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); -drop index ix_migtest_e_basic_indextest1; -drop index ix_migtest_e_basic_indextest5; +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'IX_MIGTEST_E_BASIC_INDEXTEST1') then + prepare stmt from 'drop index ix_migtest_e_basic_indextest1'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'IX_MIGTEST_E_BASIC_INDEXTEST5') then + prepare stmt from 'drop index ix_migtest_e_basic_indextest5'; + execute stmt; +end if; +end$$; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.2__dropsFor_1.1.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.2__dropsFor_1.1.sql index f7ff8b135..0516c7c06 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.2__dropsFor_1.1.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.2__dropsFor_1.1.sql @@ -11,4 +11,12 @@ alter table migtest_e_history2 drop column obsolete_string1; alter table migtest_e_history2 drop column obsolete_string2; drop table migtest_e_ref; -drop sequence migtest_e_ref_seq; +delimiter $$ +begin +if exists (select seqschema from syscat.sequences where seqschema = current_schema and seqname = 'MIGTEST_E_REF_SEQ') then + prepare stmt from 'drop sequence migtest_e_ref_seq'; + execute stmt; +end if; +end$$; +call sysproc.admin_cmd('reorg table migtest_e_history2') /* reorg #1 */; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #2 */; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.3.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.3.sql index 9b10c4e8e..87fea5f81 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.3.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.3.sql @@ -5,63 +5,204 @@ create table migtest_e_ref ( name varchar(127) not null, constraint pk_migtest_e_ref primary key (id) ); +-- alterTableAddUniqueConstraint alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); -alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_parent; -alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_CKEY_DETAIL_PARENT' and tabname = 'MIGTEST_CKEY_DETAIL') then + prepare stmt from 'alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_parent'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_CASCADE_ONE_ID' and tabname = 'MIGTEST_FK_CASCADE') then + prepare stmt from 'alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id'; + execute stmt; +end if; +end$$; alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; -alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id; -alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id; -alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_NONE_ONE_ID' and tabname = 'MIGTEST_FK_NONE') then + prepare stmt from 'alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_NONE_VIA_JOIN_ONE_ID' and tabname = 'MIGTEST_FK_NONE_VIA_JOIN') then + prepare stmt from 'alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_FK_SET_NULL_ONE_ID' and tabname = 'MIGTEST_FK_SET_NULL') then + prepare stmt from 'alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id'; + execute stmt; +end if; +end$$; alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null; -alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_BASIC_STATUS' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status'; + execute stmt; +end if; +end$$; alter table migtest_e_basic alter column status drop default; -alter table migtest_e_basic alter column status set null; +alter table migtest_e_basic alter column status drop not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I')); +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #1 */; update migtest_e_basic set status2 = 'N' where status2 is null; -alter table migtest_e_basic drop constraint ck_migtest_e_basic_status2; -alter table migtest_e_basic alter column status2 varchar(1); +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_BASIC_STATUS2' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status2'; + execute stmt; +end if; +end$$; +alter table migtest_e_basic alter column status2 set data type varchar(1); alter table migtest_e_basic alter column status2 set default 'N'; alter table migtest_e_basic alter column status2 set not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_status2 check ( status2 in ('N','A','I')); -alter table migtest_e_basic drop constraint uq_migtest_e_basic_description; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_DESCRIPTION' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_description'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_DESCRIPTION') then + prepare stmt from 'drop index uq_migtest_e_basic_description'; + execute stmt; +end if; +end$$; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #2 */; update migtest_e_basic set user_id = 23 where user_id is null; -alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'FK_MIGTEST_E_BASIC_USER_ID' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id'; + execute stmt; +end if; +end$$; alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; alter table migtest_e_basic add column old_boolean boolean default false not null; alter table migtest_e_basic add column old_boolean2 boolean; alter table migtest_e_basic add column eref_id integer; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_status_indextest1; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest4; -alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest5; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_STATUS_INDEXTEST1' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_status_indextest1'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_STATUS_INDEXTEST1') then + prepare stmt from 'drop index uq_migtest_e_basic_status_indextest1'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_NAME' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_name'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_NAME') then + prepare stmt from 'drop index uq_migtest_e_basic_name'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_INDEXTEST4' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest4'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_INDEXTEST4') then + prepare stmt from 'drop index uq_migtest_e_basic_indextest4'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'UQ_MIGTEST_E_BASIC_INDEXTEST5' and tabname = 'MIGTEST_E_BASIC') then + prepare stmt from 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest5'; + execute stmt; +end if; +end$$ +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'UQ_MIGTEST_E_BASIC_INDEXTEST5') then + prepare stmt from 'drop index uq_migtest_e_basic_indextest5'; + execute stmt; +end if; +end$$; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #3 */; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) exclude null keys; +-- alterTableAddUniqueConstraint create unique index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) exclude null keys; -alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status; +delimiter $$ +begin +if exists (select constname from syscat.tabconst where tabschema = current_schema and constname = 'CK_MIGTEST_E_ENUM_TEST_STATUS' and tabname = 'MIGTEST_E_ENUM') then + prepare stmt from 'alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status'; + execute stmt; +end if; +end$$; alter table migtest_e_enum add constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I')); comment on column migtest_e_history.test_string is ''; comment on table migtest_e_history is ''; alter table migtest_e_history2 alter column test_string drop default; -alter table migtest_e_history2 alter column test_string set null; +alter table migtest_e_history2 alter column test_string drop not null; alter table migtest_e_history2 add column obsolete_string1 varchar(255); alter table migtest_e_history2 add column obsolete_string2 varchar(255); -alter table migtest_e_history4 alter column test_number integer; +alter table migtest_e_history4 alter column test_number set data type integer; alter table migtest_e_history6 alter column test_number1 drop default; -alter table migtest_e_history6 alter column test_number1 set null; +alter table migtest_e_history6 alter column test_number1 drop not null; +call sysproc.admin_cmd('reorg table migtest_e_history2') /* reorg #4 */; +call sysproc.admin_cmd('reorg table migtest_e_history6') /* reorg #5 */; +call sysproc.admin_cmd('reorg table migtest_e_history4') /* reorg #6 */; -- NOTE: table has @History - special migration may be necessary update migtest_e_history6 set test_number2 = 7 where test_number2 is null; alter table migtest_e_history6 alter column test_number2 set default 7; alter table migtest_e_history6 alter column test_number2 set not null; +call sysproc.admin_cmd('reorg table migtest_e_history6') /* reorg #7 */; create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -drop index ix_migtest_e_basic_indextest3; -drop index ix_migtest_e_basic_indextest6; +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'IX_MIGTEST_E_BASIC_INDEXTEST3') then + prepare stmt from 'drop index ix_migtest_e_basic_indextest3'; + execute stmt; +end if; +end$$; +delimiter $$ +begin +if exists (select indname from syscat.indexes where indschema = current_schema and indname = 'IX_MIGTEST_E_BASIC_INDEXTEST6') then + prepare stmt from 'drop index ix_migtest_e_basic_indextest6'; + execute stmt; +end if; +end$$; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.4__dropsFor_1.3.sql b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.4__dropsFor_1.3.sql index 038f64f6a..274f3b336 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.4__dropsFor_1.3.sql +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/1.4__dropsFor_1.3.sql @@ -29,6 +29,19 @@ alter table migtest_e_softdelete drop column deleted; alter table migtest_oto_child drop column master_id; drop table migtest_e_user; -drop sequence migtest_e_user_seq; +delimiter $$ +begin +if exists (select seqschema from syscat.sequences where seqschema = current_schema and seqname = 'MIGTEST_E_USER_SEQ') then + prepare stmt from 'drop sequence migtest_e_user_seq'; + execute stmt; +end if; +end$$; drop table migtest_mtm_c_migtest_mtm_m; drop table migtest_mtm_m_migtest_mtm_c; +call sysproc.admin_cmd('reorg table migtest_e_history2') /* reorg #1 */; +call sysproc.admin_cmd('reorg table migtest_e_softdelete') /* reorg #2 */; +call sysproc.admin_cmd('reorg table migtest_oto_child') /* reorg #3 */; +call sysproc.admin_cmd('reorg table migtest_ckey_parent') /* reorg #4 */; +call sysproc.admin_cmd('reorg table migtest_e_history5') /* reorg #5 */; +call sysproc.admin_cmd('reorg table migtest_ckey_detail') /* reorg #6 */; +call sysproc.admin_cmd('reorg table migtest_e_basic') /* reorg #7 */; diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/idx_db2.migrations b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/idx_db2.migrations index 8ddb0c4f4..86c945d59 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/idx_db2.migrations +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/db2/idx_db2.migrations @@ -1,6 +1,6 @@ -1580812656, 1.0__initial.sql --522424232, 1.1.sql -578073685, 1.2__dropsFor_1.1.sql --1685257725, 1.3.sql --1475628451, 1.4__dropsFor_1.3.sql +997100585, 1.0__initial.sql +855187652, 1.1.sql +1091886546, 1.2__dropsFor_1.1.sql +-364921922, 1.3.sql +2020621716, 1.4__dropsFor_1.3.sql diff --git a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml index e165e05d8..f913814b4 100644 --- a/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml +++ b/ebean-ddl-generator/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml @@ -16,6 +16,10 @@ + + -- db2 does not support parial null indices :( - so we have to clean + update ${table} set status = 'N' where id = 1 + -- rename all collisions