From a810ef0c63ce5c15ebc99bf105859c71134fbe3a Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 17 Mar 2022 11:57:24 +0100 Subject: [PATCH] Handle DB2 extra lob options --- .../server/deploy/BeanProperty.java | 2 +- .../platform/DB2ColumnOptionsParser.java | 77 +++++++++++++++++++ .../ddlgeneration/platform/DB2Ddl.java | 30 +++++++- .../platform/DB2ColumnOptionsParserTest.java | 42 ++++++++++ .../test/java/misc/migration/v1_0/EBasic.java | 7 +- .../test/java/misc/migration/v1_1/EBasic.java | 5 +- .../test/java/misc/migration/v1_2/EBasic.java | 7 +- 7 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParser.java create mode 100644 ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParserTest.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 3e5ae47b3..4fa11fce5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -1004,7 +1004,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { * Return the DB column default to use for DDL. */ public String dbColumnDefault() { - return dbColumnDefn != null ? null : dbColumnDefault; + return dbColumnDefault; } /** diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParser.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParser.java new file mode 100644 index 000000000..358e8ee0a --- /dev/null +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParser.java @@ -0,0 +1,77 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * This class parses the inline column options of a create-statement (see + * https://www.ibm.com/docs/en/db2/11.5?topic=statements-create-table#sdx-synid_frag-column-options) into separate pieces if you + * want to alter a column. The later one has to be done in separate statements: See + * https://www.ibm.com/docs/en/db2/11.5?topic=statements-alter-table#sdx-synid_frag-column-options + * + *
+ * Note 1: This class parses only 'inline length', 'compact' and 'logged' options
+ * Note 2: You cannot alter the compact or logged option on an existing column. + * + * @author Roland Praml, FOCONIS AG + */ +public class DB2ColumnOptionsParser { + private static final Pattern INLINE_LENGTH = Pattern.compile(".*( inline length \\d+).*", Pattern.CASE_INSENSITIVE); + private static final Pattern NOT_LOGGED = Pattern.compile(".*?(( not)? logged).*", Pattern.CASE_INSENSITIVE); + private static final Pattern NOT_COMPACT = Pattern.compile(".*?(( not)? compact).*", Pattern.CASE_INSENSITIVE); + + private final String type; + private final String inlineLength; + private final boolean logged; + private final boolean compact; + private boolean extraOptions; + + DB2ColumnOptionsParser(String def) { + Matcher m = INLINE_LENGTH.matcher(def); + if (m.matches()) { + def = def.replace(m.group(1), ""); + inlineLength = m.group(1).trim(); + } else { + inlineLength = null; + } + m = NOT_LOGGED.matcher(def); + if (m.matches()) { + extraOptions = true; + def = def.replace(m.group(1), ""); + logged = m.group(2) == null; + } else { + logged = true; // default + } + + m = NOT_COMPACT.matcher(def); + if (m.matches()) { + extraOptions = true; + def = def.replace(m.group(1), ""); + compact = m.group(2) == null; + } else { + compact = false; // default + } + type = def.trim(); + } + + public String getInlineLength() { + return inlineLength; + } + + public String getType() { + return type; + } + + public boolean isLogged() { + return logged; + } + + public boolean isCompact() { + return compact; + } + + public boolean hasExtraOptions() { + return extraOptions; + } + +} 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 616515e1e..60af6b00b 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 @@ -8,6 +8,7 @@ import java.util.List; import io.ebean.util.StringHelper; import io.ebeaninternal.dbmigration.ddlgeneration.DdlAlterTable; import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; +import io.ebeaninternal.dbmigration.migration.AlterColumn; import io.ebeaninternal.dbmigration.migration.Column; /** @@ -151,10 +152,31 @@ public class DB2Ddl extends PlatformDdl { return sb.toString(); } -@Override -protected DdlAlterTable alterTable(DdlWrite writer, String tableName) { - return writer.applyAlterTable(tableName, Db2AlterTableWrite::new); -}; + @Override + protected void alterColumnType(DdlWrite writer, AlterColumn alter) { + String type = convert(alter.getType()); + DB2ColumnOptionsParser parser = new DB2ColumnOptionsParser(type); + alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName()) + .append(columnSetType).append(parser.getType()); + + if (parser.getInlineLength() != null) { + alterTable(writer, alter.getTableName()).append(alterColumn, alter.getColumnName()) + .append("set").appendWithSpace(parser.getInlineLength()); + } + + if (parser.hasExtraOptions()) { + alterTable(writer, alter.getTableName()).raw("-- ignored options for ") + .append(alter.getTableName()).append(".").append(alter.getColumnName()) + .append(": compact=").append(String.valueOf(parser.isCompact())) + .append(", logged=").append(String.valueOf(parser.isLogged())); + } + } + + @Override + protected DdlAlterTable alterTable(DdlWrite writer, String tableName) { + return writer.applyAlterTable(tableName, Db2AlterTableWrite::new); + }; + static class Db2AlterTableWrite extends BaseAlterTableWrite { public Db2AlterTableWrite(String tableName) { diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParserTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParserTest.java new file mode 100644 index 000000000..62e3ba00e --- /dev/null +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2ColumnOptionsParserTest.java @@ -0,0 +1,42 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + + +public class DB2ColumnOptionsParserTest { + + private final SoftAssertions softly = new SoftAssertions(); + + @AfterEach + void assertAll() { + softly.assertAll(); + } + @Test + public void testParser() { + DB2ColumnOptionsParser p = new DB2ColumnOptionsParser("blob(64M) inline length 200 logged compact"); + softly.assertThat(p.getType()).isEqualTo("blob(64M)"); + softly.assertThat(p.getInlineLength()).isEqualTo("inline length 200"); + softly.assertThat(p.isLogged()).isTrue(); + softly.assertThat(p.isCompact()).isTrue(); + + p = new DB2ColumnOptionsParser("blob(64M) inline length 200 not logged not compact"); + softly.assertThat(p.getType()).isEqualTo("blob(64M)"); + softly.assertThat(p.getInlineLength()).isEqualTo("inline length 200"); + softly.assertThat(p.isLogged()).isFalse(); + softly.assertThat(p.isCompact()).isFalse(); + + p = new DB2ColumnOptionsParser("blob(64M) inline length 200"); + softly.assertThat(p.getType()).isEqualTo("blob(64M)"); + softly.assertThat(p.getInlineLength()).isEqualTo("inline length 200"); + softly.assertThat(p.isLogged()).isTrue(); + softly.assertThat(p.isCompact()).isFalse(); + + p = new DB2ColumnOptionsParser("blob(64M)"); + softly.assertThat(p.getType()).isEqualTo("blob(64M)"); + softly.assertThat(p.getInlineLength()).isNull(); + softly.assertThat(p.isLogged()).isTrue(); + softly.assertThat(p.isCompact()).isFalse(); + } +} diff --git a/ebean-test/src/test/java/misc/migration/v1_0/EBasic.java b/ebean-test/src/test/java/misc/migration/v1_0/EBasic.java index 6f7fed9c2..c360b2d71 100644 --- a/ebean-test/src/test/java/misc/migration/v1_0/EBasic.java +++ b/ebean-test/src/test/java/misc/migration/v1_0/EBasic.java @@ -55,9 +55,14 @@ public class EBasic { File descriptionFile; @DbJson - //@Column(columnDefinition = "db2;clob(16K);") + @Column(columnDefinition = "db2;clob(16K) inline length 500 compact;") List jsonList; + @NotNull + @DbDefault("X") + @Column(columnDefinition = "db2;clob(16K) inline length 500 not logged;") + String aLob; + Timestamp someDate; boolean old_boolean; diff --git a/ebean-test/src/test/java/misc/migration/v1_1/EBasic.java b/ebean-test/src/test/java/misc/migration/v1_1/EBasic.java index 151ccc21a..3ed011c12 100644 --- a/ebean-test/src/test/java/misc/migration/v1_1/EBasic.java +++ b/ebean-test/src/test/java/misc/migration/v1_1/EBasic.java @@ -60,9 +60,12 @@ public class EBasic { String description; @DbJson - //@Column(columnDefinition = "db2;clob(16K);") + @Column(columnDefinition = "db2;clob(16K) inline length 500 compact;") List jsonList; + @Column(columnDefinition = "db2;clob(16K) inline length 500 not logged;", nullable = true) + String aLob; + //@NotNull //@DbDefault("2000-01-01T00:00:00") //- date time literals do not work for each platform yet //@DbDefault("now") //- now does not work for mariaDb diff --git a/ebean-test/src/test/java/misc/migration/v1_2/EBasic.java b/ebean-test/src/test/java/misc/migration/v1_2/EBasic.java index 8f748814d..b80603673 100644 --- a/ebean-test/src/test/java/misc/migration/v1_2/EBasic.java +++ b/ebean-test/src/test/java/misc/migration/v1_2/EBasic.java @@ -53,9 +53,14 @@ public class EBasic { File descriptionFile; @DbJson - //@Column(columnDefinition = "db2;clob(16K);") + @Column(columnDefinition = "db2;clob(16K) inline length 500 compact;") List jsonList; + @NotNull + @DbDefault("X") + @Column(columnDefinition = "db2;clob(16K) inline length 500 compact;") + String aLob; + Timestamp someDate; boolean old_boolean;