From 4a20c9eb99db34b8c04aca747a2d6a955280a222 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 27 Jan 2022 13:56:21 +0100 Subject: [PATCH 01/48] Test against H2 1.4.199 --- .../ddlgeneration/platform/H2Ddl.java | 5 +++++ .../ddlgeneration/BaseDdlHandlerTest.java | 14 ++++++++++++-- .../platform/PlatformDdl_AlterColumnTest.java | 17 +++++++++++++---- .../test/resources/application-test.properties | 4 ++-- .../config/PlatformNoGeneratedKeysTest.java | 2 +- .../org/tests/update/TestSqlUpdateUpsert.java | 8 +++++++- ebean-test/src/test/resources/ebean.properties | 2 +- .../src/test/resources/test-ebean.properties | 2 +- pom.xml | 2 +- 9 files changed, 43 insertions(+), 13 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/H2Ddl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/H2Ddl.java index 542bc695a..952fa9858 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/H2Ddl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/H2Ddl.java @@ -7,6 +7,8 @@ import io.ebean.config.dbplatform.DatabasePlatform; */ public class H2Ddl extends PlatformDdl { + private static boolean useV1Syntax = Boolean.getBoolean("ebean.h2.useV1Syntax"); + public H2Ddl(DatabasePlatform platform) { super(platform); this.historyDdl = new H2HistoryDdl(); @@ -22,6 +24,9 @@ public class H2Ddl extends PlatformDdl { @Override protected String convertArrayType(String logicalArrayType) { + if (useV1Syntax) { + return "array"; + } int pos = logicalArrayType.indexOf('['); if (pos == -1) { return logicalArrayType; diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java index 87c48bb85..550d508ad 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java @@ -18,6 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; public class BaseDdlHandlerTest extends BaseTestCase { + private static boolean useV1Syntax = Boolean.getBoolean("ebean.h2.useV1Syntax"); + private final DatabaseConfig serverConfig = new DatabaseConfig(); private DdlHandler handler(DatabasePlatform platform) { @@ -107,7 +109,11 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); h2Handler().generate(write, Helper.getAlterTableAddDbArrayColumnWithLength()); - assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety varchar array;\n\n"); + if (useV1Syntax) { + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety array;\n\n"); + } else { + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_ninety varchar array;\n\n"); + } write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAlterTableAddDbArrayColumnWithLength()); @@ -127,7 +133,11 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); h2Handler().generate(write, Helper.getAlterTableAddDbArrayColumnIntegerWithLength()); - assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer integer array;\n\n"); + if (useV1Syntax) { + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer array;\n\n"); + } else { + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column dbarray_integer integer array;\n\n"); + } write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAlterTableAddDbArrayColumnIntegerWithLength()); diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java index 3141eef74..2ae1118f1 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java @@ -25,6 +25,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class PlatformDdl_AlterColumnTest { + private static boolean useV1Syntax = Boolean.getBoolean("ebean.h2.useV1Syntax"); + private final PlatformDdl h2Ddl = PlatformDdlBuilder.create(new H2Platform()); private final PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform()); private final PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); @@ -57,10 +59,17 @@ public class PlatformDdl_AlterColumnTest { @Test public void convertArrayType_h2() { - assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("varchar array"); - assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("integer array"); - assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("varchar array"); - assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("integer array"); + if (useV1Syntax) { + assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("array"); + assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("array"); + assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("array"); + assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("array"); + } else { + assertThat(h2Ddl.convertArrayType("varchar[](90)")).isEqualTo("varchar array"); + assertThat(h2Ddl.convertArrayType("integer[](60)")).isEqualTo("integer array"); + assertThat(h2Ddl.convertArrayType("varchar[]")).isEqualTo("varchar array"); + assertThat(h2Ddl.convertArrayType("integer[]")).isEqualTo("integer array"); + } } @Test diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties index fef41029d..2cb5bb2c7 100644 --- a/ebean-querybean/src/test/resources/application-test.properties +++ b/ebean-querybean/src/test/resources/application-test.properties @@ -6,8 +6,8 @@ datasource.default=h2 datasource.h2.username=sa datasource.h2.password= -datasource.h2.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY +datasource.h2.url=jdbc:h2:mem:tests datasource.pg.username=sa datasource.pg.password= -datasource.pg.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY +datasource.pg.url=jdbc:h2:mem:tests diff --git a/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java b/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java index 6c57e56bb..63b672137 100644 --- a/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java +++ b/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java @@ -101,7 +101,7 @@ public class PlatformNoGeneratedKeysTest { config.setDatabasePlatform(platform); config.getDataSourceConfig().setUsername("sa"); config.getDataSourceConfig().setPassword(""); - config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;MODE=LEGACY"); + config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery"); config.getDataSourceConfig().setDriver("org.h2.Driver"); config.setDisableLazyLoading(true); diff --git a/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java b/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java index 515540ea3..ffa1bd26b 100644 --- a/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java +++ b/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java @@ -11,6 +11,8 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestSqlUpdateUpsert extends BaseTestCase { + private static boolean useV1Syntax = Boolean.getBoolean("ebean.h2.useV1Syntax"); + @ForPlatform(Platform.H2) @Test public void h2Merge() throws InterruptedException { @@ -39,7 +41,11 @@ public class TestSqlUpdateUpsert extends BaseTestCase { .setParameter("online", false); Object key2 = sqlUpdate2.executeGetKey(); - assertThat(key2).isEqualTo(key); + if (useV1Syntax) { + assertThat(key2).isNull(); + } else { + assertThat(key2).isEqualTo(key); + } EPersonOnline found2 = DB.find(EPersonOnline.class).where().eq("email", email).findOne(); diff --git a/ebean-test/src/test/resources/ebean.properties b/ebean-test/src/test/resources/ebean.properties index d7e1debae..402facaab 100644 --- a/ebean-test/src/test/resources/ebean.properties +++ b/ebean-test/src/test/resources/ebean.properties @@ -72,7 +72,7 @@ datasource.db.databaseDriver=org.h2.Driver datasource.h2.username=sa datasource.h2.password= -datasource.h2.url=jdbc:h2:mem:testsMem;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE +datasource.h2.url=jdbc:h2:mem:testsMem;DB_CLOSE_ON_EXIT=FALSE datasource.h2.poolListener=org.tests.basic.MyTestDataSourcePoolListener #datasource.h2.minConnections=1 #datasource.h2.maxConnections=25 diff --git a/ebean-test/src/test/resources/test-ebean.properties b/ebean-test/src/test/resources/test-ebean.properties index 436499c1b..2405e5104 100644 --- a/ebean-test/src/test/resources/test-ebean.properties +++ b/ebean-test/src/test/resources/test-ebean.properties @@ -8,5 +8,5 @@ ebean.jodaLocalTimeMode=normal datasource.someotherdb.username=sa datasource.someotherdb.password= -datasource.someotherdb.databaseUrl=jdbc:h2:mem:someotherdb;NON_KEYWORDS=KEY,VALUE +datasource.someotherdb.databaseUrl=jdbc:h2:mem:someotherdb datasource.someotherdb.databaseDriver=org.h2.Driver diff --git a/pom.xml b/pom.xml index 20aa39271..5e85ad050 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ false 2.12.1 - 2.1.210 + 1.4.199 1.2 1.1 12.13.1 From ddaff81b9c14227a5f6f08481ee81094feb6c8d4 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 28 Jan 2022 09:26:08 +0100 Subject: [PATCH 02/48] FIX: Datasource was not initialized in offline mode. --- .../server/core/InitDataSource.java | 1 - .../server/core/InitDataSourceTest.java | 66 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InitDataSource.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InitDataSource.java index 5cf4d7b2c..54bfff518 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InitDataSource.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InitDataSource.java @@ -99,7 +99,6 @@ final class InitDataSource { if (config.getDatabasePlatformName() == null) { throw new PersistenceException("You MUST specify a DatabasePlatformName on DatabaseConfig when offline"); } - return null; } attachAlert(dsConfig); diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/core/InitDataSourceTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/core/InitDataSourceTest.java index 584a943be..eb501029e 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/core/InitDataSourceTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/core/InitDataSourceTest.java @@ -1,11 +1,19 @@ package io.ebeaninternal.server.core; import io.ebean.config.DatabaseConfig; +import io.ebean.datasource.DataSourceAlert; import io.ebean.datasource.DataSourceConfig; +import io.ebean.datasource.pool.ConnectionPool; + import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; +import java.sql.SQLException; + +import javax.sql.DataSource; + public class InitDataSourceTest { private DatabaseConfig newConfig(String readOnlyUrl) { @@ -121,4 +129,62 @@ public class InitDataSourceTest { assertNotNull(roConfig); assertEquals("foo", roConfig.getUrl()); } + + + @Test + public void online() { + DatabaseConfig config = new DatabaseConfig(); + config.getDataSourceConfig().setUsername("sa"); + config.getDataSourceConfig().setPassword(""); + config.getDataSourceConfig().setUrl("jdbc:h2:mem:dsTestOnline"); + config.getDataSourceConfig().setDriver("org.h2.Driver"); + InitDataSource.init(config); + ConnectionPool pool = (ConnectionPool) config.getDataSource(); + assertThat(pool.isDataSourceUp()).isTrue(); + pool.shutdown(); + } + + static class MyAlert implements DataSourceAlert { + + int up; + + @Override + public void dataSourceUp(DataSource dataSource) { + up++; + } + + @Override + public void dataSourceDown(DataSource dataSource, SQLException reason) { + } + + @Override + public void dataSourceWarning(DataSource dataSource, String msg) { + } + + } + + @Test + public void offline() throws SQLException { + DatabaseConfig config = new DatabaseConfig(); + config.getDataSourceConfig().setUsername("sa"); + config.getDataSourceConfig().setPassword(""); + config.getDataSourceConfig().setUrl("jdbc:h2:mem:dsTestOffline"); + config.getDataSourceConfig().setDriver("org.h2.Driver"); + config.getDataSourceConfig().setOffline(true); + config.getDataSourceConfig().setFailOnStart(false); + MyAlert alert = new MyAlert(); + config.getDataSourceConfig().setAlert(alert); + config.setDatabasePlatformName("h2"); + InitDataSource.init(config); + ConnectionPool pool = (ConnectionPool) config.getDataSource(); + assertThat(pool).isNotNull(); + // make some additional tests with the pool + assertThat(pool.isDataSourceUp()).isFalse(); + assertThat(alert.up).isEqualTo(0); + pool.online(); + assertThat(alert.up).isEqualTo(1); + assertThat(pool.isDataSourceUp()).isTrue(); + pool.shutdown(); + } + } From d982ac73b7c5a8912c1fefedc87ae0b4480b54d1 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 16:41:41 +0100 Subject: [PATCH 03/48] DB2: Fix Concat operator --- .../server/expression/platform/Db2DbExpression.java | 13 +++++++++++++ .../platform/DbExpressionHandlerFactory.java | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/Db2DbExpression.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/Db2DbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/Db2DbExpression.java new file mode 100644 index 000000000..8bc485f2c --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/Db2DbExpression.java @@ -0,0 +1,13 @@ +package io.ebeaninternal.server.expression.platform; + +/** + * DB2 handling of platform specific expressions. ARRAY expressions not supported. + */ +final class Db2DbExpression extends BasicDbExpression { + + @Override + public String concat(String property0, String separator, String property1, String suffix) { + return concatOperator(property0, separator, property1, suffix); + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java index 1af660cae..da3eee778 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java @@ -24,6 +24,8 @@ public final class DbExpressionHandlerFactory { return new MySqlDbExpression(); case ORACLE: return new OracleDbExpression(); + case DB2: + return new Db2DbExpression(); case SQLSERVER: return new SqlServerDbExpression(); case HANA: From e529232f769ea7b20046950d0699b981e26be8ae Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 16:45:06 +0100 Subject: [PATCH 04/48] DB2: Fix insert default values --- .../java/io/ebeaninternal/server/persist/dml/InsertMeta.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java index 2ebba4d05..e3a89d1fa 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java @@ -181,6 +181,8 @@ final class InsertMeta { case MARIADB: case ORACLE: return " values (default)"; + case DB2: + return " (" + id.getIdentityColumn() + ") values (default)"; default: return " default values"; } From 6d978add294a4eb0a8baf7ce3ca7f0407bc50220 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 17:16:46 +0100 Subject: [PATCH 05/48] DB2: Fix default values --- .../src/test/java/org/tests/defaultvalues/TestDefaults.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java b/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java index 170584d5b..9822a68ff 100644 --- a/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java +++ b/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java @@ -28,6 +28,8 @@ public class TestDefaults extends BaseTestCase { assertThat(current).isNotEmpty(); if (isMySql() || isMariaDB() || isOracle()) { assertThat(current.get(0)).contains("insert into defaults_model_draft values (default);"); + } else if (isDb2()) { + assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (default)"); } else if (isSqlServer()) { assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (?)"); } else { From 015dd00b8e795e864f538b4f0d1cf65e4c4a3b5c Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 17:04:01 +0100 Subject: [PATCH 06/48] DB2: Fix Raw like --- .../java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java index fb4fff30a..4d1a8c37b 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java @@ -22,6 +22,7 @@ public abstract class BaseDB2Platform extends DatabasePlatform { this.platform = Platform.DB2; this.supportsNativeJavaTime = false; this.truncateTable = "truncate table %s reuse storage ignore delete triggers immediate"; + this.likeClauseRaw = "like ?"; this.sqlLimiter = new Db2SqlLimiter(); this.dbIdentity.setSupportsGetGeneratedKeys(true); From 0310601e31c481bc6952723aa8299766461ee18d Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 16:45:54 +0100 Subject: [PATCH 07/48] DB2: Fix getGenerateKeys (ungly workaround) --- .../server/persist/BatchedPstmt.java | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java index d3aa6174f..0a14d485a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java @@ -6,6 +6,8 @@ import io.ebeaninternal.api.SpiTransaction; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -42,6 +44,18 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent { private int[] results; private List inputStreams; + private static Class DB2_PREPARED_STATEMENT; + private static Method GET_DB_GENERATED_KEYS; + + static { + try { + DB2_PREPARED_STATEMENT = (Class) Class.forName("com.ibm.db2.jcc.DB2PreparedStatement"); + GET_DB_GENERATED_KEYS = DB2_PREPARED_STATEMENT.getDeclaredMethod("getDBGeneratedKeys"); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException cnf) { + // NOP + } + + } /** * Create with a given statement. */ @@ -169,8 +183,35 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent { } } - private void getGeneratedKeys() throws SQLException { + protected void getGeneratedKeys() throws SQLException { int index = 0; + if (DB2_PREPARED_STATEMENT != null) { + PreparedStatement db2Stmt = null; + if (DB2_PREPARED_STATEMENT.isInstance(pstmt)) { + db2Stmt = pstmt; + } else if (pstmt.isWrapperFor(DB2_PREPARED_STATEMENT)) { + db2Stmt = pstmt.unwrap(DB2_PREPARED_STATEMENT); + } + if (db2Stmt != null) { + // WTF: https://stackoverflow.com/questions/41725492/how-to-get-auto-generated-keys-of-batch-insert-statement + ResultSet[] result; + try { + result = (ResultSet[]) GET_DB_GENERATED_KEYS.invoke(db2Stmt); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SQLException("Could not get generated keys for DB2", e); + } + for (int i = 0; i < result.length; i++) { + while (result[i].next()) { + ResultSet rset = result[i]; + Object idValue = rset.getObject(1); + list.get(index).setGeneratedKey(idValue); + index++; + } + } + return; + } + } + try (ResultSet rset = pstmt.getGeneratedKeys()) { while (rset.next()) { Object idValue = rset.getObject(1); From 90f6d0707f804e71a37ef373dad47f4cc1c0671f Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 10:37:53 +0100 Subject: [PATCH 08/48] DB2: SqlCodeTranslator must check exception chain --- .../config/dbplatform/SqlCodeTranslator.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/SqlCodeTranslator.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/SqlCodeTranslator.java index 90ef29de6..8f7adc846 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/SqlCodeTranslator.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/SqlCodeTranslator.java @@ -31,14 +31,39 @@ public class SqlCodeTranslator implements SqlExceptionTranslator { this.map = Collections.emptyMap(); } - @Override - public PersistenceException translate(String message, SQLException e) { - + private DataErrorType getErrorType(SQLException e) { DataErrorType errorType = map.get(e.getSQLState()); if (errorType == null) { // fall back to error code errorType = map.get(String.valueOf(e.getErrorCode())); } + return errorType; + } + + @Override + public PersistenceException translate(String message, SQLException e) { + + DataErrorType errorType = getErrorType(e); + // for DB2 we must inspect the sql exception chain to determine which + // persistence error occurred in a batch execution. We also concatenate + // the error messages to improve error analysis. + SQLException chain = e.getNextException(); + if (chain != null) { + StringBuilder sb = new StringBuilder(message); + int i = 1; + while (chain != null && i < 100000) { // prevents from endless loop + sb.append("\n\t#").append(i++).append(": ").append(chain.getMessage()); + if (errorType == null) { + errorType = getErrorType(chain); + if (errorType != null) { + sb.append(" (causing error)"); // mark the line, where we found a matching error code + } + } + chain = chain.getNextException(); + } + message = sb.toString(); + } + if (errorType != null) { switch (errorType) { case AcquireLock: From 5ae5e408e3e3856eac0668cc494d52a2055683ae Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 11:12:28 +0100 Subject: [PATCH 09/48] DB2: FIX Db2SqlLimiter & tests --- .../config/dbplatform/db2/Db2SqlLimiter.java | 7 +++++-- .../java/io/ebean/EbeanServer_eqlTest.java | 14 +++++++------- .../cache/TestCacheViaComplexNaturalKey3.java | 4 ++-- .../org/tests/query/TestQueryOrderById.java | 4 ++-- .../query/other/TestQuerySingleAttribute.java | 8 +++----- .../org/tests/rawsql/TestRawSqlOrmQuery.java | 18 +++++++++++++----- 6 files changed, 32 insertions(+), 23 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/Db2SqlLimiter.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/Db2SqlLimiter.java index c78aafe45..670cb324c 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/Db2SqlLimiter.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/Db2SqlLimiter.java @@ -15,10 +15,13 @@ public class Db2SqlLimiter implements SqlLimiter { sb.append("distinct "); } sb.append(request.getDbSql()); - + int firstRow = request.getFirstRow(); + if (firstRow > 0) { + sb.append(" offset ").append(firstRow).append(" rows"); + } int maxRows = request.getMaxRows(); if (maxRows > 0) { - sb.append(" ").append(NEW_LINE).append("FETCH FIRST ").append(maxRows).append(" ROWS ONLY"); + sb.append(" fetch next ").append(maxRows).append(" rows only"); } String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery()); diff --git a/ebean-test/src/test/java/io/ebean/EbeanServer_eqlTest.java b/ebean-test/src/test/java/io/ebean/EbeanServer_eqlTest.java index c913e8495..6e538d0ec 100644 --- a/ebean-test/src/test/java/io/ebean/EbeanServer_eqlTest.java +++ b/ebean-test/src/test/java/io/ebean/EbeanServer_eqlTest.java @@ -26,7 +26,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).startsWith("select top 100 "); assertSql(query).endsWith("order by t0.id"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains(" fetch next 100 rows only"); } else { assertSql(query).endsWith("order by t0.id limit 100"); @@ -44,7 +44,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).startsWith("select top 10 "); assertSql(query).endsWith("order by t0.id"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains(" fetch next 10 rows only"); } else { assertSql(query).endsWith("order by t0.id limit 10"); @@ -61,7 +61,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).endsWith("order by t0.id offset 3 rows fetch next 10 rows only"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("offset 3 rows fetch next 10 rows only"); } else { assertSql(query).endsWith("order by t0.id limit 10 offset 3"); @@ -81,7 +81,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).endsWith("order by t0.name offset 3 rows fetch next 10 rows only"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("offset 3 rows fetch next 10 rows only"); } else { assertSql(query).endsWith("order by t0.name limit 10 offset 3"); @@ -107,7 +107,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).endsWith("order by t0.name, t0.id offset 3 rows fetch next 10 rows only"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("offset 3 rows fetch next 10 rows only"); } else { assertSql(query).endsWith("order by t0.name, t0.id limit 10 offset 3"); @@ -136,7 +136,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).endsWith("from o_customer t0 order by t0.id offset 3 rows fetch next 10 rows only"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("offset 3 rows fetch next 10 rows only"); } else { assertSql(query).endsWith("from o_customer t0 limit 10 offset 3"); @@ -154,7 +154,7 @@ public class EbeanServer_eqlTest extends BaseTestCase { if (isSqlServer()) { assertSql(query).startsWith("select top 10 "); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("fetch next 10 rows only"); } else { assertSql(query).endsWith("limit 10"); diff --git a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index 70ccc6d1b..b4bb8f788 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -369,7 +369,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { if (isH2()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?,?) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); - } else if (isPostgres() || isOracle()) { + } else if (isPostgres() || isOracle() || isDb2()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)"); } else if (isHana()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, '-'||t0.code)"); @@ -412,7 +412,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { if (isH2()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?,?) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); - } else if (isPostgres() || isOracle()){ + } else if (isPostgres() || isOracle() || isDb2()){ assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')"); } else if (isHana()){ assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, ':'||t0.code||'-foo')"); diff --git a/ebean-test/src/test/java/org/tests/query/TestQueryOrderById.java b/ebean-test/src/test/java/org/tests/query/TestQueryOrderById.java index f98a0c04d..579c1dfd0 100644 --- a/ebean-test/src/test/java/org/tests/query/TestQueryOrderById.java +++ b/ebean-test/src/test/java/org/tests/query/TestQueryOrderById.java @@ -18,7 +18,7 @@ public class TestQueryOrderById extends BaseTestCase { .setMaxRows(5); query.findList(); - if (isSqlServer()) { + if (isSqlServer() || isDb2()) { assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id offset 1 rows fetch next 5 rows only"); } else if (!isOracle()) { assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id limit 5 offset 1"); @@ -35,7 +35,7 @@ public class TestQueryOrderById extends BaseTestCase { .orderById(true); query.findList(); - if (isSqlServer()) { + if (isSqlServer() || isDb2()) { assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id offset 1 rows fetch next 5 rows only"); } else if (!isOracle()) { assertSql(query).isEqualTo("select t0.id, t0.name from o_customer t0 order by t0.id limit 5 offset 1"); diff --git a/ebean-test/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java b/ebean-test/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java index 8329e0d1e..69d6ffa59 100644 --- a/ebean-test/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java +++ b/ebean-test/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java @@ -314,7 +314,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { List ids = query.findSingleAttributeList(); if (isSqlServer()) { assertThat(sqlOf(query)).contains("select distinct top 100 t0.id from o_customer t0"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 fetch next 100 rows only"); } else { assertThat(sqlOf(query)).contains("select distinct t0.id from o_customer t0 limit 100"); @@ -393,7 +393,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { List ids = query.findSingleAttributeList(); if (isSqlServer()) { assertThat(sqlOf(query)).contains("select top 100 t0.id from o_customer t0"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertThat(sqlOf(query)).contains("fetch next 100 rows only"); } else { assertThat(sqlOf(query)).contains("select t0.id from o_customer t0 limit 100"); @@ -727,9 +727,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { } if (isSqlServer()) { assertThat(sqlOf(query)).endsWith(" fetch next 2 rows only"); - } else if (isDb2()) { - assertSql(query).endsWith("FETCH FIRST 2 ROWS ONLY"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains(" offset 1 rows fetch next 2 rows only"); } else { assertThat(sqlOf(query)).endsWith(" limit 2 offset 1"); diff --git a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java index ac27ba981..154395bba 100644 --- a/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java +++ b/ebean-test/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java @@ -147,7 +147,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { if (isSqlServer()) { assertSql(query).contains("top 100 "); assertSql(query).contains("order by o.ship_date desc"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("fetch next 100 rows only"); } else { assertSql(query).contains("order by o.ship_date desc limit 100"); @@ -182,7 +182,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { if (isSqlServer()) { assertSql(query).contains("top 100 "); assertSql(query).contains("order by o.ship_date desc, o.id"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertSql(query).contains("fetch next 100 rows only"); } else { assertSql(query).contains("order by o.ship_date desc, o.id limit 100"); @@ -224,7 +224,11 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.order("coalesce(shipDate, now()) desc"); query.findList(); - assertSql(query).contains("order by coalesce(o.ship_date, now()) desc limit 100"); + if (isDb2()) { + assertSql(query).contains("order by coalesce(o.ship_date, now()) desc fetch next 100 rows only"); + } else { + assertSql(query).contains("order by coalesce(o.ship_date, now()) desc limit 100"); + } } } @@ -257,7 +261,11 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.order("coalesce(shipDate, now()) desc"); query.findList(); - assertSql(query).contains("order by coalesce(o.ship_date, now()) desc, o.id limit 100"); + if (isDb2()) { + assertSql(query).contains("order by coalesce(o.ship_date, now()) desc, o.id fetch next 100 rows only"); + } else { + assertSql(query).contains("order by coalesce(o.ship_date, now()) desc, o.id limit 100"); + } } } @@ -284,7 +292,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase { if (isSqlServer()) { assertThat(sqlOf(query)).contains("select top 100 "); assertThat(sqlOf(query)).contains("order by o.id desc"); - } else if (isOracle()) { + } else if (isOracle() || isDb2()) { assertThat(sqlOf(query)).contains("fetch next 100 rows only"); } else { assertThat(sqlOf(query)).contains("order by o.id desc limit 100"); From e5d29afa4c526999c11508e0a3c7647730df6a36 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 13:08:19 +0100 Subject: [PATCH 10/48] DB2: Disabled test for encryption, as it is not supported for Db2 --- .../src/test/java/org/tests/basic/encrypt/TestEncrypt.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-test/src/test/java/org/tests/basic/encrypt/TestEncrypt.java b/ebean-test/src/test/java/org/tests/basic/encrypt/TestEncrypt.java index 3c9925c04..0189aaf03 100644 --- a/ebean-test/src/test/java/org/tests/basic/encrypt/TestEncrypt.java +++ b/ebean-test/src/test/java/org/tests/basic/encrypt/TestEncrypt.java @@ -56,7 +56,7 @@ public class TestEncrypt extends BaseTestCase { assertThat(loggedSql.get(1)).contains("left join e_basicenc t1 on t1.id = t0.other_id"); } - @IgnorePlatform(Platform.ORACLE) + @IgnorePlatform({Platform.ORACLE, Platform.DB2}) @Test public void asDto() { DB.find(EBasicEncrypt.class).delete(); From dd824ffe52e12cfe821a9bcc2352b2a88764948c Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 12:55:58 +0100 Subject: [PATCH 11/48] DB2: Fix EqlParserTests similar to HANA --- .../ebeaninternal/server/grammer/EqlParserTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java index 38fceeefc..f0c2d1149 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java @@ -231,7 +231,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' + @IgnorePlatform({Platform.HANA, Platform.DB2}) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' public void where_or1() { Query query = parse("where name = 'Rob' or (status = 'NEW' and smallnote is null)"); @@ -241,7 +241,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @ForPlatform(Platform.HANA) + @ForPlatform({Platform.HANA, Platform.DB2})) public void where_or1_hana() { Query query = parse("where name = 'Rob' or (status = 'N' and smallnote is null)"); @@ -251,7 +251,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' + @IgnorePlatform({Platform.HANA, Platform.DB2})) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' public void where_or2() { Query query = parse("where (name = 'Rob' or status = 'NEW') and smallnote is null"); @@ -261,7 +261,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @ForPlatform(Platform.HANA) + @ForPlatform({Platform.HANA, Platform.DB2})) public void where_or2_hana() { Query query = parse("where (name = 'Rob' or status = 'N') and smallnote is null"); @@ -271,7 +271,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' + @IgnorePlatform({Platform.HANA, Platform.DB2})) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' public void test_simplifyExpressions() { Query query = parse("where not (name = 'Rob' and status = 'NEW')"); @@ -288,7 +288,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - @ForPlatform(Platform.HANA) + @ForPlatform({Platform.HANA, Platform.DB2}) public void test_simplifyExpressions_hana() { Query query = parse("where not (name = 'Rob' and status = 'N')"); From 5845f9430336531e81d88b8622052f32f6e682bd Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 11:53:16 +0100 Subject: [PATCH 12/48] DB2:ignored tests --- .../src/test/java/org/tests/basic/TestMetaAnnotation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java b/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java index 71007df58..b9e8aa409 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java +++ b/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java @@ -49,7 +49,7 @@ public class TestMetaAnnotation extends BaseTestCase { * This test writes 101 spaces to "line1" which is annotated with @Size(max=100). */ @Test - @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB}) // pg & mssql does not fail if string is too long. + @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2}) // pg & mssql does not fail if string is too long. public void testWrite101SpacesToLine1() { Address address = new Address(); @@ -66,7 +66,7 @@ public class TestMetaAnnotation extends BaseTestCase { * This test writes 101 spaces to "line1" which is meta-annotated with {@link SizeMedium}. */ @Test - @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB}) + @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2}) public void testWrite101SpacesToLine2() { Address address = new Address(); From 9f9184ac6a94c8dd5bb6e2e0541d4336f1fca275 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 14:44:43 +0100 Subject: [PATCH 13/48] DB2 does not support ids in compressed form --- .../java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java index fb4fff30a..cbe83842e 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java @@ -26,7 +26,7 @@ public abstract class BaseDB2Platform extends DatabasePlatform { this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsSequence(true); - + this.idInExpandedForm = true; // Db2 does not support (a,b) in ((?,?),(?,?)) this.exceptionTranslator = new SqlErrorCodes() .addAcquireLock("40001","57033") // key -911/-913 From 3b30708dfc975e08d9beddaa14bcf5facec45b26 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 11:52:34 +0100 Subject: [PATCH 14/48] DB2: truncate needs commit after each statement --- .../main/java/io/ebeaninternal/server/core/DefaultServer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 1cdabc9f8..552816408 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -613,6 +613,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { try (Connection connection = dataSource().getConnection()) { for (String table : tables) { executeSql(connection, databasePlatform.truncateStatement(table)); + if (databasePlatform.getPlatform().base() == Platform.DB2) { + // DB2 requires commit after each truncate statement + connection.commit(); + } } connection.commit(); } catch (SQLException e) { From c0e827ffdaa8fe75c11d06445111c0b21651c17b Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 5 Jan 2022 16:44:31 +0100 Subject: [PATCH 15/48] DB2: Fix Sequence generator --- .../io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java index a5170a759..3f2d3eb25 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java @@ -19,7 +19,7 @@ public class DB2SequenceIdGenerator extends SequenceBatchIdGenerator { public DB2SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { super(be, ds, seqName, batchSize); this.baseSql = "values nextval for " + seqName; - this.unionBaseSql = " union " + baseSql; + this.unionBaseSql = ", nextval for " + seqName; } @Override From ba21eeaadbea016607858dc4caac40a8912d2043 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 15:24:49 +0100 Subject: [PATCH 16/48] DB2: Do not try to update deferred null values (Discovered by TestPrinterStateIssue) --- ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java | 2 ++ .../ebeaninternal/server/core/PersistDeferredRelationship.java | 3 +++ .../io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java | 3 +++ .../io/ebeaninternal/server/deploy/id/ImportedIdSimple.java | 3 +++ 4 files changed, 11 insertions(+) diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java b/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java index ca813ae14..ec3b6ed05 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/BindParams.java @@ -167,6 +167,7 @@ public final class BindParams implements Serializable { */ @SuppressWarnings("rawtypes") public void setParameter(int position, Object value) { + assert value != null : "use setNullParameter"; Param p = getParam(position); if (value instanceof Collection) { // use of postgres ANY with positioned parameter @@ -218,6 +219,7 @@ public final class BindParams implements Serializable { * Set a named In parameter that is not null. */ public Param setParameter(String name, Object value) { + assert value != null : "use setNullParameter"; Param p = getParam(name); p.setInValue(value); return p; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistDeferredRelationship.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistDeferredRelationship.java index 279bf6329..30cb469af 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistDeferredRelationship.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistDeferredRelationship.java @@ -40,6 +40,9 @@ public final class PersistDeferredRelationship { // bind the set clause for the importedId int pos = importedId.bind(1, sqlUpdate, assocBean); + if (pos == -1) { + return; // could not bind: TODO: should we log/throw an error? + } // bind the where clause for the bean Object[] idValues = beanDescriptor.idBinder().getIdValues(bean); for (int j = 0; j < idValues.length; j++) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java index 7f6c3d96e..ee64f86af 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdEmbedded.java @@ -85,6 +85,9 @@ public final class ImportedIdEmbedded implements ImportedId { for (ImportedIdSimple anImported : imported) { if (anImported.owner.isUpdateable()) { Object scalarValue = anImported.foreignProperty.getValue(embedded); + if (scalarValue == null) { + return -1; // could not bind + } update.setParameter(pos++, scalarValue); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java index fe3e8ce2e..2c844c4a2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/id/ImportedIdSimple.java @@ -151,6 +151,9 @@ public final class ImportedIdSimple implements ImportedId, Comparable Date: Fri, 28 Jan 2022 11:31:28 +0100 Subject: [PATCH 17/48] fix compile errors for EqlParserTest --- .../server/grammer/EqlParserTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java index f0c2d1149..4d2f4f2e2 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java @@ -241,17 +241,17 @@ public class EqlParserTest extends BaseTestCase { } @Test - @ForPlatform({Platform.HANA, Platform.DB2})) + @ForPlatform({Platform.HANA, Platform.DB2}) public void where_or1_hana() { Query query = parse("where name = 'Rob' or (status = 'N' and smallnote is null)"); query.findList(); - assertSql(query).contains("where (t0.name = ? or (t0.status = ? and t0.smallnote is null ) )"); + assertSql(query).contains("where (t0.name = ? or (t0.status = ? and t0.smallnote is null))"); } @Test - @IgnorePlatform({Platform.HANA, Platform.DB2})) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' + @IgnorePlatform({Platform.HANA, Platform.DB2}) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' public void where_or2() { Query query = parse("where (name = 'Rob' or status = 'NEW') and smallnote is null"); @@ -261,17 +261,17 @@ public class EqlParserTest extends BaseTestCase { } @Test - @ForPlatform({Platform.HANA, Platform.DB2})) + @ForPlatform({Platform.HANA, Platform.DB2}) public void where_or2_hana() { Query query = parse("where (name = 'Rob' or status = 'N') and smallnote is null"); query.findList(); - assertSql(query).contains("where ((t0.name = ? or t0.status = ? ) and t0.smallnote is null )"); + assertSql(query).contains("where ((t0.name = ? or t0.status = ?) and t0.smallnote is null)"); } @Test - @IgnorePlatform({Platform.HANA, Platform.DB2})) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' + @IgnorePlatform({Platform.HANA, Platform.DB2}) // The HANA & DB2 JDBC driver checks the field length on binding and rejects 'NEW' public void test_simplifyExpressions() { Query query = parse("where not (name = 'Rob' and status = 'NEW')"); @@ -293,15 +293,15 @@ public class EqlParserTest extends BaseTestCase { Query query = parse("where not (name = 'Rob' and status = 'N')"); query.findList(); - assertSql(query).contains("where not (t0.name = ? and t0.status = ? )"); + assertSql(query).contains("where not (t0.name = ? and t0.status = ?)"); query = parse("where not ((name = 'Rob' and status = 'N'))"); query.findList(); - assertSql(query).contains("where not (t0.name = ? and t0.status = ? )"); + assertSql(query).contains("where not (t0.name = ? and t0.status = ?)"); query = parse("where not (((name = 'Rob') and (status = 'N')))"); query.findList(); - assertSql(query).contains("where not (t0.name = ? and t0.status = ? )"); + assertSql(query).contains("where not (t0.name = ? and t0.status = ?)"); } @Test From aadb79198060b9f40dc61036cc23d2e68c468646 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 28 Jan 2022 11:35:56 +0100 Subject: [PATCH 18/48] FIX: isSame replaceed by isEqualTo --- .../server/core/DefaultServer_getReferenceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java index e638d9d00..a7dbc0165 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java @@ -41,7 +41,7 @@ public class DefaultServer_getReferenceTest extends BaseTestCase { Vehicle reference = DB.reference(Vehicle.class, car.getId()); assertThat(reference).isInstanceOf(Car.class); - assertThat(reference.getId()).isSameAs(car.getId()); + assertThat(reference.getId()).isEqualTo(car.getId()); DB.delete(car); } From 953f8054e672daeec9cadffd36ed9587aa4757ef Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 28 Jan 2022 11:36:11 +0100 Subject: [PATCH 19/48] FIX: Clean up tests --- .../test/java/org/tests/model/m2m/TestM2MWithWhere.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java b/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java index a433c388e..62dff12e4 100644 --- a/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java +++ b/ebean-test/src/test/java/org/tests/model/m2m/TestM2MWithWhere.java @@ -3,6 +3,8 @@ package org.tests.model.m2m; import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.test.LoggedSql; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.util.List; @@ -123,6 +125,11 @@ public class TestM2MWithWhere extends BaseTestCase { // System.out.println(sb); dump the table } + @AfterEach + void deleteTestData() { + DB.find(MnyEdge.class).delete(); + DB.find(MnyNode.class).delete(); + } @Test public void testWithDbTableName() { From 8c9f5f4a227be5c6067c101474713308137fbe33 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 28 Jan 2022 11:36:32 +0100 Subject: [PATCH 20/48] Disabled more tests for DB2 --- .../test/java/org/tests/model/history/TestHistoryExclude.java | 2 +- .../test/java/org/tests/model/history/TestHistoryInclude.java | 2 +- .../test/java/org/tests/model/history/TestHistoryOneToMany.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/model/history/TestHistoryExclude.java b/ebean-test/src/test/java/org/tests/model/history/TestHistoryExclude.java index b7b1e2f5b..a8bfdb268 100644 --- a/ebean-test/src/test/java/org/tests/model/history/TestHistoryExclude.java +++ b/ebean-test/src/test/java/org/tests/model/history/TestHistoryExclude.java @@ -70,7 +70,7 @@ public class TestHistoryExclude extends BaseTestCase { linkFound.getDocs().size(); } - @IgnorePlatform(Platform.ORACLE) + @IgnorePlatform({Platform.ORACLE, Platform.DB2}) @Test public void testAsOfThenLazy() { diff --git a/ebean-test/src/test/java/org/tests/model/history/TestHistoryInclude.java b/ebean-test/src/test/java/org/tests/model/history/TestHistoryInclude.java index 3c462c1cc..8b7c8714f 100644 --- a/ebean-test/src/test/java/org/tests/model/history/TestHistoryInclude.java +++ b/ebean-test/src/test/java/org/tests/model/history/TestHistoryInclude.java @@ -37,7 +37,7 @@ public class TestHistoryInclude extends BaseTestCase { assertThat(linkFound.getDocs().size()).isEqualTo(2); } - @IgnorePlatform(Platform.ORACLE) + @IgnorePlatform({Platform.ORACLE, Platform.DB2}) @Test public void testAsOfThenLazy() { diff --git a/ebean-test/src/test/java/org/tests/model/history/TestHistoryOneToMany.java b/ebean-test/src/test/java/org/tests/model/history/TestHistoryOneToMany.java index 42a214988..d57fa1d8b 100644 --- a/ebean-test/src/test/java/org/tests/model/history/TestHistoryOneToMany.java +++ b/ebean-test/src/test/java/org/tests/model/history/TestHistoryOneToMany.java @@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestHistoryOneToMany extends BaseTestCase { - @IgnorePlatform(Platform.ORACLE) + @IgnorePlatform({Platform.ORACLE, Platform.DB2}) @Test public void test() throws InterruptedException { From b4fe4ec8b9c8e58c138e72d778eb338552a336d3 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 28 Jan 2022 16:04:35 +0100 Subject: [PATCH 21/48] ADD.profile and autodetect code --- .../resources/application-test.properties | 4 +-- .../test/config/AutoConfigureForTesting.java | 25 +++++++++++++++++++ .../config/PlatformNoGeneratedKeysTest.java | 4 +-- .../src/test/resources/ebean.properties | 2 +- .../src/test/resources/test-ebean.properties | 2 +- pom.xml | 8 +++++- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties index 2cb5bb2c7..fef41029d 100644 --- a/ebean-querybean/src/test/resources/application-test.properties +++ b/ebean-querybean/src/test/resources/application-test.properties @@ -6,8 +6,8 @@ datasource.default=h2 datasource.h2.username=sa datasource.h2.password= -datasource.h2.url=jdbc:h2:mem:tests +datasource.h2.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY datasource.pg.username=sa datasource.pg.password= -datasource.pg.url=jdbc:h2:mem:tests +datasource.pg.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY diff --git a/ebean-test/src/main/java/io/ebean/test/config/AutoConfigureForTesting.java b/ebean-test/src/main/java/io/ebean/test/config/AutoConfigureForTesting.java index 8cd4f6395..5366597a1 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/AutoConfigureForTesting.java +++ b/ebean-test/src/main/java/io/ebean/test/config/AutoConfigureForTesting.java @@ -10,6 +10,8 @@ import org.slf4j.LoggerFactory; import java.util.Properties; +import javax.sql.DataSource; + /** * Automatically configure ServerConfig for testing purposes. *

@@ -47,6 +49,29 @@ public class AutoConfigureForTesting implements AutoConfigure { @Override public void postConfigure(DatabaseConfig config) { setupProviders(config); + + if (org.h2.engine.Constants.VERSION_MAJOR == 1) { + // This code may be removed later, when droppinv H2 1.xxx compatibility + System.err.println("Running tests in H2 1.xxx compatibility mode"); + System.setProperty("ebean.h2.useV1Syntax", "true"); + makeV1Compatible(config.getDataSourceConfig()); + makeV1Compatible(config.getReadOnlyDataSourceConfig()); + } + } + + private void makeV1Compatible(DataSourceConfig ds) { + if (ds == null) { + return; + } + String url = ds.getUrl(); + if (url == null || !url.startsWith("jdbc:h2:")) { + return; + } + // remove illegal URL options + url = url.replace(";MODE=LEGACY", ""); + url = url.replace(";NON_KEYWORDS=KEY,VALUE", ""); + url = url.replace(";NON_KEYWORDS=KEY", ""); + ds.setUrl(url); } /** diff --git a/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java b/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java index 63b672137..37d02bbb8 100644 --- a/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java +++ b/ebean-test/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java @@ -101,7 +101,7 @@ public class PlatformNoGeneratedKeysTest { config.setDatabasePlatform(platform); config.getDataSourceConfig().setUsername("sa"); config.getDataSourceConfig().setPassword(""); - config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery"); + config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;MODE=LEGACY"); config.getDataSourceConfig().setDriver("org.h2.Driver"); config.setDisableLazyLoading(true); @@ -112,7 +112,7 @@ public class PlatformNoGeneratedKeysTest { config.setDdlRun(true); config.getClasses().add(EBasicVer.class); config.getClasses().add(BasicDraftableBean.class); - + config.loadFromProperties(); // trigger auto config for H2 1.x return DatabaseFactory.create(config); } diff --git a/ebean-test/src/test/resources/ebean.properties b/ebean-test/src/test/resources/ebean.properties index 402facaab..d7e1debae 100644 --- a/ebean-test/src/test/resources/ebean.properties +++ b/ebean-test/src/test/resources/ebean.properties @@ -72,7 +72,7 @@ datasource.db.databaseDriver=org.h2.Driver datasource.h2.username=sa datasource.h2.password= -datasource.h2.url=jdbc:h2:mem:testsMem;DB_CLOSE_ON_EXIT=FALSE +datasource.h2.url=jdbc:h2:mem:testsMem;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=KEY,VALUE datasource.h2.poolListener=org.tests.basic.MyTestDataSourcePoolListener #datasource.h2.minConnections=1 #datasource.h2.maxConnections=25 diff --git a/ebean-test/src/test/resources/test-ebean.properties b/ebean-test/src/test/resources/test-ebean.properties index 2405e5104..436499c1b 100644 --- a/ebean-test/src/test/resources/test-ebean.properties +++ b/ebean-test/src/test/resources/test-ebean.properties @@ -8,5 +8,5 @@ ebean.jodaLocalTimeMode=normal datasource.someotherdb.username=sa datasource.someotherdb.password= -datasource.someotherdb.databaseUrl=jdbc:h2:mem:someotherdb +datasource.someotherdb.databaseUrl=jdbc:h2:mem:someotherdb;NON_KEYWORDS=KEY,VALUE datasource.someotherdb.databaseDriver=org.h2.Driver diff --git a/pom.xml b/pom.xml index 5e85ad050..2ddf524ee 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ false 2.12.1 - 1.4.199 + 2.1.210 1.2 1.1 12.13.1 @@ -99,6 +99,12 @@ release + + h2v1 + + 1.4.199 + + default From 1359d534d50cced77bee7e539678ebf841e34e36 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 29 Jan 2022 17:05:12 +1300 Subject: [PATCH 22/48] Yugabyte - Use Postgres ScalarTypes for JSON/JSONB but not HSTORE --- .../server/type/DefaultTypeManager.java | 17 ++++++++++++----- ebean-test/src/test/resources/extra-ddl.xml | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 94ebb0572..747208ecc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -95,6 +95,7 @@ public final class DefaultTypeManager implements TypeManager { private final TypeJsonManager jsonManager; private final boolean offlineMigrationGeneration; private final EnumType defaultEnumType; + private final DatabasePlatform databasePlatform; // OPTIONAL ScalarTypes registered if Jackson/JsonNode is in the classpath @@ -132,7 +133,8 @@ public final class DefaultTypeManager implements TypeManager { this.typeMap = new ConcurrentHashMap<>(); this.nativeMap = new ConcurrentHashMap<>(); this.logicalMap = new ConcurrentHashMap<>(); - this.postgres = isPostgres(config.getDatabasePlatform()); + this.databasePlatform = config.getDatabasePlatform(); + this.postgres = isPostgresCompatible(config.getDatabasePlatform()); this.objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : null; this.jsonManager = (objectMapperPresent) ? new TypeJsonManager(postgres, objectMapper, config.getJsonMutationDetection()) : null; @@ -198,8 +200,13 @@ public final class DefaultTypeManager implements TypeManager { } } - private boolean isPostgres(DatabasePlatform databasePlatform) { - return databasePlatform.getPlatform().base() == Platform.POSTGRES; + private boolean isPostgresCompatible(DatabasePlatform databasePlatform) { + return databasePlatform.isPlatform(Platform.POSTGRES) + || databasePlatform.isPlatform(Platform.YUGABYTE); + } + + private boolean hstoreSupport() { + return databasePlatform.isPlatform(Platform.POSTGRES); } /** @@ -302,7 +309,7 @@ public final class DefaultTypeManager implements TypeManager { @Override public ScalarType getDbMapScalarType() { - return (postgres) ? hstoreType : ScalarTypeJsonMap.typeFor(false, Types.VARCHAR, false); + return hstoreSupport() ? hstoreType : ScalarTypeJsonMap.typeFor(false, Types.VARCHAR, false); } @Override @@ -740,7 +747,7 @@ public final class DefaultTypeManager implements TypeManager { jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(mapper); jsonNodeJson = jsonNodeClob; // Default for non-Postgres databases jsonNodeJsonb = jsonNodeClob; // Default for non-Postgres databases - if (isPostgres(config.getDatabasePlatform())) { + if (postgres) { jsonNodeJson = new ScalarTypeJsonNodePostgres.JSON(mapper); jsonNodeJsonb = new ScalarTypeJsonNodePostgres.JSONB(mapper); } diff --git a/ebean-test/src/test/resources/extra-ddl.xml b/ebean-test/src/test/resources/extra-ddl.xml index ae128968c..9bc702735 100644 --- a/ebean-test/src/test/resources/extra-ddl.xml +++ b/ebean-test/src/test/resources/extra-ddl.xml @@ -5,7 +5,7 @@ drop view order_agg_vw if exists; - + create or replace view order_agg_vw as select d.order_id, sum(d.order_qty * d.unit_price) as order_total, sum(d.ship_qty * d.unit_price) as ship_total From 4b8565e7c740144b666293b026d877592178e31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Mon, 31 Jan 2022 11:32:22 +0100 Subject: [PATCH 23/48] FIX: we can set persistBatchOnCascade to ALL for newer DB2 versions --- .../java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java | 1 - .../java/io/ebean/config/dbplatform/db2/DB2LegacyPlatform.java | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java index b0fcdbd99..dce52f4ea 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/BaseDB2Platform.java @@ -43,7 +43,6 @@ public abstract class BaseDB2Platform extends DatabasePlatform { dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false)); dbTypeMap.put(DbType.REAL, new DbPlatformType("real")); dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("decimal", 16, 3)); - persistBatchOnCascade = PersistBatch.NONE; } /** diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2LegacyPlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2LegacyPlatform.java index 51f03c2a4..896bdf9b0 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2LegacyPlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/db2/DB2LegacyPlatform.java @@ -1,5 +1,6 @@ package io.ebean.config.dbplatform.db2; +import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; /** @@ -16,5 +17,6 @@ public class DB2LegacyPlatform extends BaseDB2Platform { // TOOD: Check if we need to introduce a new platform (DB2_LUW_11 ?) this.maxTableNameLength = 18; this.maxConstraintNameLength = 18; + this.persistBatchOnCascade = PersistBatch.NONE; } } From f2e04d9fbff5b51a9048facc27ae17e368149796 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 7 Jan 2022 11:31:00 +0100 Subject: [PATCH 24/48] DB2. Support for unique indices with null columns (cherry picked from commit 23a5d577a6aafe015ffaca74bda6342b8ecd1829) --- .../ddlgeneration/platform/DB2Ddl.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) 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 7ee9e1c30..1eae12035 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 @@ -24,10 +24,22 @@ public class DB2Ddl extends PlatformDdl { public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) { if (nullableColumns == null || nullableColumns.length == 0) { return super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns); - } else { - // Hmm: Complex workaround: https://www.ibm.com/developerworks/mydeveloperworks/blogs/SQLTips4DB2LUW/entry/unique_where_not_null_indexes26?lang=en - return "-- NOT SUPPORTED " + super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns); + } + + if (uqName == null) { + throw new NullPointerException(); } + StringBuilder sb = new StringBuilder("create unique index "); + sb.append(uqName).append(" on ").append(tableName).append('('); + + for (int i = 0; i < columns.length; i++) { + if (i > 0) { + sb.append(","); + } + sb.append(columns[i]); + } + sb.append(") exclude null keys"); + return sb.toString(); } @Override From b4ddbe38eea195f7c479f940ff1b8aa99a1e831c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 09:49:23 +1300 Subject: [PATCH 25/48] Yugabyte - Fix some tests for running against Yugabyte --- ebean-test/src/test/java/io/ebean/BaseTestCase.java | 4 ++++ .../test/java/org/tests/basic/type/TestInetAddressType.java | 2 +- .../model/basic/cache/TestCacheViaComplexNaturalKey3.java | 4 ++-- .../elementcollection/TestElementCollectionBasicSet.java | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ebean-test/src/test/java/io/ebean/BaseTestCase.java b/ebean-test/src/test/java/io/ebean/BaseTestCase.java index 6e9ad234f..e7b591c3d 100644 --- a/ebean-test/src/test/java/io/ebean/BaseTestCase.java +++ b/ebean-test/src/test/java/io/ebean/BaseTestCase.java @@ -199,6 +199,10 @@ public abstract class BaseTestCase { return Platform.POSTGRES == platform().base(); } + public boolean isYugabyte() { + return Platform.YUGABYTE == platform().base(); + } + public boolean isMySql() { return Platform.MYSQL == platform(); } diff --git a/ebean-test/src/test/java/org/tests/basic/type/TestInetAddressType.java b/ebean-test/src/test/java/org/tests/basic/type/TestInetAddressType.java index ec226169b..fad06a837 100644 --- a/ebean-test/src/test/java/org/tests/basic/type/TestInetAddressType.java +++ b/ebean-test/src/test/java/org/tests/basic/type/TestInetAddressType.java @@ -27,7 +27,7 @@ public class TestInetAddressType extends TransactionalTestCase { @Test public void testIp6() throws UnknownHostException { - if (isPostgres()) { + if (isPostgres() || isYugabyte()) { insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3::8a2e:370:7334", "2001:4f8:3:ba::/64", "2001:4f8:3:ba::/64"); } else { insertUpdateDeleteFind("2001:db8:85a3:0:0:8a2e:370:7334", "2001:db8:85a3:0:0:8a2e:370:7334", "192.168.100.128/25", "192.168.100.128/25"); diff --git a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index b4bb8f788..38798bba1 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/ebean-test/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -369,7 +369,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { if (isH2()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?,?) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); - } else if (isPostgres() || isOracle() || isDb2()) { + } else if (isPostgres() || isOracle() || isDb2() || isYugabyte()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)"); } else if (isHana()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, '-'||t0.code)"); @@ -412,7 +412,7 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { if (isH2()) { assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?,?) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); - } else if (isPostgres() || isOracle() || isDb2()){ + } else if (isPostgres() || isOracle() || isDb2() || isYugabyte()){ assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')"); } else if (isHana()){ assertSql(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, ':'||t0.code||'-foo')"); diff --git a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java index fa99f45da..65359a683 100644 --- a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java @@ -52,8 +52,8 @@ class TestElementCollectionBasicSet extends BaseTestCase { Set phoneNumbers1 = found.get(1).getPhoneNumbers(); phoneNumbers0.size(); - assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); - assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321", "09 9876"); + assertThat(phoneNumbers0).containsExactlyInAnyOrder("021 1234", "021 4321"); + assertThat(phoneNumbers1).containsExactlyInAnyOrder("09 1234", "09 4321", "09 9876"); sql = LoggedSql.collect(); assertThat(sql).hasSize(2); From 567ad920503f7e2072c0070fa97dc9086e6c6f42 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 10:41:29 +1300 Subject: [PATCH 26/48] Yugabyte - Tidy tests --- .../src/test/java/main/StartYugabyte.java | 1 + .../org/tests/basic/TestMetaAnnotation.java | 4 +- .../bitwise/TestBitwiseExpressions.java | 40 ++++++++----------- .../transaction/TestCommitAndContinue.java | 14 +++---- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/ebean-test/src/test/java/main/StartYugabyte.java b/ebean-test/src/test/java/main/StartYugabyte.java index b45f2b7f2..e68c4b3c0 100644 --- a/ebean-test/src/test/java/main/StartYugabyte.java +++ b/ebean-test/src/test/java/main/StartYugabyte.java @@ -11,6 +11,7 @@ public class StartYugabyte { YugabyteConfig config = new YugabyteConfig("2.11.2.0-b89"); config.setDbName("unit"); config.setUser("unit"); + config.setExtensions("pgcrypto"); YugabyteContainer container = new YugabyteContainer(config); container.start(); diff --git a/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java b/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java index b9e8aa409..13073c583 100644 --- a/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java +++ b/ebean-test/src/test/java/org/tests/basic/TestMetaAnnotation.java @@ -49,7 +49,7 @@ public class TestMetaAnnotation extends BaseTestCase { * This test writes 101 spaces to "line1" which is annotated with @Size(max=100). */ @Test - @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2}) // pg & mssql does not fail if string is too long. + @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2, Platform.YUGABYTE}) // pg & mssql does not fail if string is too long. public void testWrite101SpacesToLine1() { Address address = new Address(); @@ -66,7 +66,7 @@ public class TestMetaAnnotation extends BaseTestCase { * This test writes 101 spaces to "line1" which is meta-annotated with {@link SizeMedium}. */ @Test - @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2}) + @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.DB2, Platform.YUGABYTE}) public void testWrite101SpacesToLine2() { Address address = new Address(); diff --git a/ebean-test/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java b/ebean-test/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java index 30cdafd84..01d89b277 100644 --- a/ebean-test/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java +++ b/ebean-test/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java @@ -2,29 +2,21 @@ package org.tests.expression.bitwise; import io.ebean.BaseTestCase; import io.ebean.DB; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -public class TestBitwiseExpressions extends BaseTestCase { +class TestBitwiseExpressions extends BaseTestCase { @Test - public void where() { - - setup(); - bitwiseNot(); - bitwiseAnd(); - bitwiseAny(); - bitwiseAll(); - } - - private void bitwiseNot() { - + void bitwiseNot() { List notColour = DB.find(BwBean.class) // HAS_COLOUR not set ... .where().bitwiseNot("flags", BwFlags.HAS_COLOUR) + .orderBy("name") .findList(); assertThat(notColour).hasSize(2); @@ -32,8 +24,8 @@ public class TestBitwiseExpressions extends BaseTestCase { assertThat(notColour.get(1).getName()).isEqualTo("SizeOnly"); } - private void bitwiseAnd() { - + @Test + void bitwiseAnd() { List list = DB.find(BwBean.class) // not bulk set AND size set .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE, BwFlags.HAS_SIZE) @@ -59,10 +51,11 @@ public class TestBitwiseExpressions extends BaseTestCase { assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); } - private void bitwiseAny() { - + @Test + void bitwiseAny() { List list = DB.find(BwBean.class) .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) + .order().asc("id") .findList(); assertThat(list).hasSize(3); @@ -70,21 +63,23 @@ public class TestBitwiseExpressions extends BaseTestCase { assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); assertThat(list.get(2).getName()).isEqualTo("Everything"); - list = DB.find(BwBean.class) .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .order().asc("id") .findList(); assertThat(list).hasSize(4); list = DB.find(BwBean.class) .where().bitwiseAny("flags", BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .order().asc("id") .findList(); assertThat(list).hasSize(4); list = DB.find(BwBean.class) .where().bitwiseAny("flags", BwFlags.HAS_SIZE) + .order().asc("id") .findList(); assertThat(list).hasSize(2); @@ -93,6 +88,7 @@ public class TestBitwiseExpressions extends BaseTestCase { list = DB.find(BwBean.class) .where().bitwiseAny("flags", BwFlags.HAS_COLOUR) + .order().asc("id") .findList(); assertThat(list).hasSize(3); @@ -101,8 +97,8 @@ public class TestBitwiseExpressions extends BaseTestCase { assertThat(list.get(2).getName()).isEqualTo("Everything"); } - private void bitwiseAll() { - + @Test + void bitwiseAll() { List list = DB.find(BwBean.class) .where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) .findList(); @@ -137,11 +133,10 @@ public class TestBitwiseExpressions extends BaseTestCase { assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); assertThat(list.get(2).getName()).isEqualTo("Everything"); - } - private void setup() { - + @BeforeAll + static void setup() { DB.find(BwBean.class).delete(); new BwBean("Nothing", BwFlags.NOTHING).save(); @@ -149,6 +144,5 @@ public class TestBitwiseExpressions extends BaseTestCase { new BwBean("SizeOnly", BwFlags.HAS_SIZE).save(); new BwBean("ColourAndBulk", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK).save(); new BwBean("Everything", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK + BwFlags.HAS_SIZE).save(); - } } diff --git a/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java b/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java index 144d8f5e3..9e700e821 100644 --- a/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java +++ b/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java @@ -15,14 +15,14 @@ import org.tests.model.m2m.MnyB; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; -public class TestCommitAndContinue extends BaseTestCase { +class TestCommitAndContinue extends BaseTestCase { private static final Logger logger = LoggerFactory.getLogger("org.avaje.ebean.TXN"); @Test @Transactional @IgnorePlatform({Platform.SQLSERVER, Platform.HSQLDB, Platform.COCKROACH}) // they will dead lock - public void transactional_partialSuccess() { + void transactional_partialSuccess() { MnyB a = new MnyB("a100"); MnyB b = new MnyB("b200"); @@ -58,7 +58,7 @@ public class TestCommitAndContinue extends BaseTestCase { */ @Test @IgnorePlatform({Platform.SQLSERVER, Platform.HSQLDB, Platform.COCKROACH}) // they will dead lock - public void tryFinally_partialSuccess() { + void tryFinally_partialSuccess() { MnyB a = new MnyB("a100"); MnyB b = new MnyB("b200"); @@ -69,7 +69,6 @@ public class TestCommitAndContinue extends BaseTestCase { a.save(); // commit at this point txn.commitAndContinue(); - try { b.save(); @@ -102,7 +101,7 @@ public class TestCommitAndContinue extends BaseTestCase { @Test @Transactional @IgnorePlatform({Platform.SQLSERVER, Platform.HSQLDB, Platform.COCKROACH}) // they will dead lock - public void transactional_partialSuccess_secondTransactionInsert() { + void transactional_partialSuccess_secondTransactionInsert() { MnyB a = new MnyB("a100"); MnyB b = new MnyB("b200"); @@ -150,8 +149,7 @@ public class TestCommitAndContinue extends BaseTestCase { } @Test - public void basic() { - + void basic() { MnyB a = new MnyB("a"); MnyB b = new MnyB("b"); MnyB c = new MnyB("c"); @@ -176,7 +174,7 @@ public class TestCommitAndContinue extends BaseTestCase { @Test @Transactional - public void runTransactional() { + void runTransactional() { new MnyB("a100").save(); new MnyB("a101").save(); From 804098149e23c73a7391e416d6c2e0c094b43b53 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 11:51:46 +1300 Subject: [PATCH 27/48] Yugabyte - Tidy tests with element collections not maintaining ordering --- .../TestElementCollectionBasic.java | 20 ++++--------- ...estElementCollectionEmbeddedListCache.java | 16 ++++++++--- ...stElementCollectionEmbeddedListCache2.java | 28 +++++++++++-------- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java index b214a3381..6524d0e7f 100644 --- a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -10,14 +10,14 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -public class TestElementCollectionBasic extends BaseTestCase { +class TestElementCollectionBasic extends BaseTestCase { private List eventLog() { return EcPersonPersistAdapter.eventLog(); } @Test - public void insertThen_UpdateWhenNotChanged_expect_noChanges() { + void insertThen_UpdateWhenNotChanged_expect_noChanges() { EcPerson person = new EcPerson("Nothing021"); person.getPhoneNumbers().add("021 1234"); @@ -51,9 +51,10 @@ public class TestElementCollectionBasic extends BaseTestCase { } @Test - public void test() { + void test() { eventLog(); + DB.find(EcPerson.class).where().eq("name", "Fiona021").delete(); LoggedSql.start(); EcPerson person = new EcPerson("Fiona021"); @@ -95,8 +96,8 @@ public class TestElementCollectionBasic extends BaseTestCase { List phoneNumbers1 = found.get(1).getPhoneNumbers(); phoneNumbers0.size(); - assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); - assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321"); + assertThat(phoneNumbers0).containsExactlyInAnyOrder("021 1234", "021 4321"); + assertThat(phoneNumbers1).containsExactlyInAnyOrder("09 1234", "09 4321"); sql = LoggedSql.collect(); assertThat(sql).hasSize(2); @@ -126,7 +127,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateBasic(EcPerson bean) { - bean.setName("Fiona021-mod-0"); DB.save(bean); @@ -140,7 +140,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateBasicInBatch(EcPerson bean) { - try (Transaction txn = DB.beginTransaction()) { txn.setBatchMode(true); bean.setName("Fiona021-mod-0-batch"); @@ -158,7 +157,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateBoth(EcPerson bean) { - bean.setName("Fiona021-mod-both"); bean.getPhoneNumbers().add("01-22123"); DB.save(bean); @@ -187,7 +185,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateBothInBatch(EcPerson bean) { - try (Transaction txn = DB.beginTransaction()) { txn.setBatchMode(true); bean.setName("Fiona021-mod-both-batch"); @@ -210,7 +207,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateNothing(EcPerson bean) { - DB.save(bean); List sql = LoggedSql.collect(); @@ -222,7 +218,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateOnlyCollectionInBatch(EcPerson bean) { - try (Transaction txn = DB.beginTransaction()) { txn.setBatchMode(true); bean.getPhoneNumbers().add("01-4321"); @@ -243,7 +238,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void updateOnlyCollection(EcPerson bean) { - bean.getPhoneNumbers().add("01-4321"); DB.save(bean); @@ -272,7 +266,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void delete(EcPerson bean) { - DB.delete(bean); List sql = LoggedSql.collect(); @@ -284,7 +277,6 @@ public class TestElementCollectionBasic extends BaseTestCase { } private void jsonToFrom(EcPerson foundFirst) { - String asJson = DB.json().toJson(foundFirst); EcPerson fromJson = DB.json().toBean(EcPerson.class, asJson); assertThat(fromJson.getPhoneNumbers()).containsAll(foundFirst.getPhoneNumbers()); diff --git a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java index 80e2d9bd1..6b5c62b3b 100644 --- a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java @@ -15,8 +15,8 @@ class TestElementCollectionEmbeddedListCache extends BaseTestCase { void test() { EcblPerson person = new EcblPerson("CacheL"); - person.getPhoneNumbers().add(new EcPhone("64", "021","1234")); - person.getPhoneNumbers().add(new EcPhone("64","021","4321")); + person.getPhoneNumbers().add(new EcPhone("64", "021", "1234")); + person.getPhoneNumbers().add(new EcPhone("64", "021", "4321")); DB.save(person); EcblPerson one = DB.find(EcblPerson.class) @@ -42,7 +42,7 @@ class TestElementCollectionEmbeddedListCache extends BaseTestCase { assertThat(sql).isEmpty(); // cache hit two.getPhoneNumbers().add(new EcPhone("61", "07", "11")); - two.getPhoneNumbers().remove(1); + removeByNumber(two.getPhoneNumbers(), "4321"); DB.save(two); @@ -72,7 +72,7 @@ class TestElementCollectionEmbeddedListCache extends BaseTestCase { three.setName("mod-3"); - three.getPhoneNumbers().remove(0); + removeByNumber(three.getPhoneNumbers(), "1234"); DB.save(three); @@ -92,4 +92,12 @@ class TestElementCollectionEmbeddedListCache extends BaseTestCase { LoggedSql.stop(); } + + private void removeByNumber(List phoneNumbers, String num) { + phoneNumbers + .stream() + .filter(ecPhone1 -> ecPhone1.number.equals(num)) + .findFirst() + .ifPresent(phoneNumbers::remove); + } } diff --git a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java index 1a361c33b..ea6d47d90 100644 --- a/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java @@ -3,7 +3,6 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.test.LoggedSql; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import java.util.List; @@ -17,8 +16,8 @@ class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { EcblPerson2 person = new EcblPerson2(); person.setName("CacheL"); - person.getPhoneNumbers().add(new EcPhone("64", "021","1234")); - person.getPhoneNumbers().add(new EcPhone("64","021","4321")); + person.getPhoneNumbers().add(new EcPhone("64", "021", "1234")); + person.getPhoneNumbers().add(new EcPhone("64", "021", "4321")); DB.save(person); EcblPerson2 one = DB.find(EcblPerson2.class) @@ -33,7 +32,7 @@ class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { List sql = LoggedSql.collect(); assertThat(sql).isEmpty(); - EcblPerson2 two = DB.find(EcblPerson2.class ) + EcblPerson2 two = DB.find(EcblPerson2.class) .setId(person.getId()) .findOne(); @@ -44,7 +43,7 @@ class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { assertThat(sql).isEmpty(); // cache hit two.getPhoneNumbers().add(new EcPhone("61", "07", "11")); - two.getPhoneNumbers().remove(1); + removeByNumber(two.getPhoneNumbers(), "4321"); DB.save(two); @@ -62,38 +61,43 @@ class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { assertSql(sql.get(2)).contains("insert into ecbl_person2_phone_numbers (person_id,country_code,area,phnum) values (?,?,?,?)"); } - EcblPerson2 three = DB.find(EcblPerson2.class ) + EcblPerson2 three = DB.find(EcblPerson2.class) .setId(person.getId()) .findOne(); - assertThat(three.getPhoneNumbers().toString()).contains("61-07-11", "64-021-1234"); assertThat(three.getPhoneNumbers()).hasSize(2); + assertThat(three.getPhoneNumbers().toString()).contains("61-07-11", "64-021-1234"); sql = LoggedSql.collect(); assertThat(sql).isEmpty(); // cache hit - three.setName("mod-3"); - three.getPhoneNumbers().remove(0); + removeByNumber(three.getPhoneNumbers(), "1234"); DB.save(three); sql = LoggedSql.collect(); assertThat(sql).hasSize(5); - EcblPerson2 four = DB.find(EcblPerson2.class ) + EcblPerson2 four = DB.find(EcblPerson2.class) .setId(person.getId()) .findOne(); assertThat(four.getPhoneNumbers().toString()).contains("61-07-11"); assertThat(four.getPhoneNumbers()).hasSize(1); - DB.delete(four); sql = LoggedSql.collect(); assertThat(sql).hasSize(2); - LoggedSql.stop(); } + + private void removeByNumber(List phoneNumbers, String num) { + phoneNumbers + .stream() + .filter(ecPhone1 -> ecPhone1.number.equals(num)) + .findFirst() + .ifPresent(phoneNumbers::remove); + } } From bc477c64cb31aa8a2bc8b7c1ff81ef4aeb7130ba Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 11:53:03 +1300 Subject: [PATCH 28/48] Yugabyte - Disable commit and continue test for Yugabyte (failing occasionally, need to review) --- ebean-test/src/test/java/main/StartYugabyte.java | 2 +- .../test/java/org/tests/transaction/TestCommitAndContinue.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-test/src/test/java/main/StartYugabyte.java b/ebean-test/src/test/java/main/StartYugabyte.java index e68c4b3c0..01b670c21 100644 --- a/ebean-test/src/test/java/main/StartYugabyte.java +++ b/ebean-test/src/test/java/main/StartYugabyte.java @@ -14,7 +14,7 @@ public class StartYugabyte { config.setExtensions("pgcrypto"); YugabyteContainer container = new YugabyteContainer(config); - container.start(); + container.startWithDropCreate(); // Run container ut_yugabyte with host:localhost port:6433 db:unit user:unit/test shutdown:None // docker run -d --name ut_yugabyte -p 6433:5433 -p 7000:7000 -p 9000:9000 -p 9042:9042 yugabytedb/yugabyte:2.11.2.0-b89 bin/yugabyted start --daemon=false diff --git a/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java b/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java index 9e700e821..e8197fc33 100644 --- a/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java +++ b/ebean-test/src/test/java/org/tests/transaction/TestCommitAndContinue.java @@ -57,7 +57,7 @@ class TestCommitAndContinue extends BaseTestCase { * The @Transactional is nicer to me. */ @Test - @IgnorePlatform({Platform.SQLSERVER, Platform.HSQLDB, Platform.COCKROACH}) // they will dead lock + @IgnorePlatform({Platform.SQLSERVER, Platform.HSQLDB, Platform.COCKROACH, Platform.YUGABYTE}) // they will dead lock void tryFinally_partialSuccess() { MnyB a = new MnyB("a100"); From 1fa92efb63254315b2f1d1f15372d9d9e084ce69 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 11:55:15 +1300 Subject: [PATCH 29/48] Yugabyte - Adjust DbJsonTest wrt ordering in content, use JSON assertContainsResource() Highlights that the DbJson assertContains() asserts are better longer term approach (over content matching asserts) --- .../test/java/io/ebean/test/DbJsonTest.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java b/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java index 17ecd262b..21e28d2a3 100644 --- a/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java +++ b/ebean-test/src/test/java/io/ebean/test/DbJsonTest.java @@ -1,6 +1,7 @@ package io.ebean.test; import com.fasterxml.jackson.databind.JsonNode; +import io.ebean.BaseTestCase; import io.ebean.DB; import org.etest.BSimpleFor; import org.junit.jupiter.api.Test; @@ -11,10 +12,10 @@ import static io.ebean.test.DbJson.readResource; import static org.assertj.core.api.Assertions.assertThat; -public class DbJsonTest { +class DbJsonTest extends BaseTestCase { @Test - public void of() { + void of() { DB.find(BSimpleFor.class).delete(); @@ -34,14 +35,19 @@ public class DbJsonTest { final List beans = DB.find(BSimpleFor.class).findList(); + if (isH2() || isPostgres()) { + DbJson.of(beans) + //.withPlaceholder("_") + .replace("id", "whenModified") + .assertContentMatches("/bean/example-list-match.json"); + } + DbJson.of(beans) - //.withPlaceholder("_") - .replace("id", "whenModified") - .assertContentMatches("/bean/example-list.json"); + .assertContainsResource("/bean/example-list-contains.json"); } @Test - public void assertContains_pass() { + void assertContains_pass() { BSimpleFor bean = new BSimpleFor("something-contains-me", "YeahNah"); DB.save(bean); @@ -55,7 +61,7 @@ public class DbJsonTest { } @Test - public void asJson() { + void asJson() { BSimpleFor bean = new BSimpleFor("other"); DB.save(bean); From 13cfaba0c858f940466452f0eca7c5b1f10a563a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 11:55:26 +1300 Subject: [PATCH 30/48] Yugabyte - Disable commit and continue test for Yugabyte (failing occasionally, need to review) --- .../src/test/resources/bean/example-list-contains.json | 9 +++++++++ .../bean/{example-list.json => example-list-match.json} | 0 2 files changed, 9 insertions(+) create mode 100644 ebean-test/src/test/resources/bean/example-list-contains.json rename ebean-test/src/test/resources/bean/{example-list.json => example-list-match.json} (100%) diff --git a/ebean-test/src/test/resources/bean/example-list-contains.json b/ebean-test/src/test/resources/bean/example-list-contains.json new file mode 100644 index 000000000..dc7599b10 --- /dev/null +++ b/ebean-test/src/test/resources/bean/example-list-contains.json @@ -0,0 +1,9 @@ +[ { + "name": "something", + "other": null, + "version": 1 +}, { + "name": "other", + "other": null, + "version": 1 +} ] diff --git a/ebean-test/src/test/resources/bean/example-list.json b/ebean-test/src/test/resources/bean/example-list-match.json similarity index 100% rename from ebean-test/src/test/resources/bean/example-list.json rename to ebean-test/src/test/resources/bean/example-list-match.json From 530a75b591dc794ab6f375941136c981c68f1f36 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 13:24:50 +1300 Subject: [PATCH 31/48] DB - test ddl changes --- .../dbmigration/migrationtest/db2/1.0__initial.sql | 4 ++-- .../resources/dbmigration/migrationtest/db2/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/db2/1.3.sql | 4 ++-- .../dbmigration/migrationtest/db2/idx_db2.migrations | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) 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 095b581de..049e2affc 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,8 +75,8 @@ create table migtest_e_basic ( constraint ck_mgtst__b_z543fg check ( status2 in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) ); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4aybzy unique (indextest2); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4ayc02 unique (indextest6); +create unique index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) exclude null keys; +create unique index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) exclude null keys; create table migtest_e_enum ( id integer generated by default as identity not null, 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 3d7f846c7..37c9d9db5 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 @@ -41,7 +41,7 @@ alter table migtest_e_basic alter column status2 drop default; alter table migtest_e_basic alter column status2 drop not null; -- rename all collisions; --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_vs45xo unique (description); +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_mgtst__bsc_sr_d foreign key (user_id) references migtest_e_user (id) on delete restrict; @@ -57,10 +57,10 @@ alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_mgtst__b_4aybzy; alter table migtest_e_basic drop constraint uq_mgtst__b_4ayc02; --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_ucfcne unique (status,indextest1); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__bsc_nm unique (name); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4ayc00 unique (indextest4); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4ayc01 unique (indextest5); +create unique index uq_migtest_e_basic_status_indextest1 on migtest_e_basic(status,indextest1) exclude null keys; +create unique index uq_migtest_e_basic_name on migtest_e_basic(name) exclude null keys; +create unique index uq_migtest_e_basic_indextest4 on migtest_e_basic(indextest4) exclude null keys; +create unique index uq_migtest_e_basic_indextest5 on migtest_e_basic(indextest5) exclude null keys; alter table migtest_e_enum drop constraint ck_mgtst__n_773sok; comment on column migtest_e_history.test_string is 'Column altered to long now'; alter table migtest_e_history alter column test_string set data type bigint; 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 47fc898ae..ab2148795 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 @@ -39,8 +39,8 @@ alter table migtest_e_basic drop constraint uq_mgtst__b_ucfcne; alter table migtest_e_basic drop constraint uq_mgtst__bsc_nm; alter table migtest_e_basic drop constraint uq_mgtst__b_4ayc00; alter table migtest_e_basic drop constraint uq_mgtst__b_4ayc01; --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4aybzy unique (indextest2); --- NOT SUPPORTED alter table migtest_e_basic add constraint uq_mgtst__b_4ayc02 unique (indextest6); +create unique index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) exclude null keys; +create unique index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) exclude null keys; alter table migtest_e_enum drop constraint ck_mgtst__n_773sok; alter table migtest_e_enum add constraint ck_mgtst__n_773sok check ( test_status in ('N','A','I')); comment on column migtest_e_history.test_string is ''; 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 9c74dc16e..5714cbdcb 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 @@ -441570368, 1.0__initial.sql -367602802, 1.1.sql +-1494430232, 1.0__initial.sql +-1611753488, 1.1.sql 578073685, 1.2__dropsFor_1.1.sql --478470986, 1.3.sql +-183167227, 1.3.sql -1475628451, 1.4__dropsFor_1.3.sql From 6d0f5aea82cd6194422b8391bb60b7f423c42fd9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 13:26:05 +1300 Subject: [PATCH 32/48] Yugabyte - ebean-test support via ebean.test.platform=yugabyte --- .../config/platform/PlatformAutoConfig.java | 6 +-- .../test/config/platform/YugabyteSetup.java | 49 +++++++++++++++++++ .../testconfig/ebean-yugabyte.properties | 3 ++ 3 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 ebean-test/src/main/java/io/ebean/test/config/platform/YugabyteSetup.java create mode 100644 ebean-test/testconfig/ebean-yugabyte.properties diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PlatformAutoConfig.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PlatformAutoConfig.java index deefcd0fb..3569db727 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PlatformAutoConfig.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PlatformAutoConfig.java @@ -35,18 +35,14 @@ public class PlatformAutoConfig { KNOWN_PLATFORMS.put("cockroach", new CockroachSetup()); KNOWN_PLATFORMS.put("hana", new HanaSetup()); KNOWN_PLATFORMS.put("db2", new Db2Setup()); + KNOWN_PLATFORMS.put("yugabyte", new YugabyteSetup()); } private final DatabaseConfig config; - private final Properties properties; - private String db; - private String platform; - private PlatformSetup platformSetup; - private String databaseName; public PlatformAutoConfig(String db, DatabaseConfig config) { diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/YugabyteSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/YugabyteSetup.java new file mode 100644 index 000000000..eb14158e3 --- /dev/null +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/YugabyteSetup.java @@ -0,0 +1,49 @@ +package io.ebean.test.config.platform; + +import java.util.Properties; + +class YugabyteSetup implements PlatformSetup { + + @Override + public Properties setup(Config config) { + int defaultPort = config.isUseDocker() ? 6433 : 5433; + config.ddlMode("dropCreate"); + config.setDefaultPort(defaultPort); + config.setUsernameDefault(); + config.setPasswordDefault(); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); + String schema = config.getSchema(); + if (schema != null && !schema.equals(config.getUsername())) { + config.urlAppend("?currentSchema=" + schema); + } + config.setDriver("org.postgresql.Driver"); + config.datasourceDefaults(); + return dockerProperties(config); + } + + private Properties dockerProperties(Config config) { + if (!config.isUseDocker()) { + return new Properties(); + } + config.setDockerVersion("2.11.2.0-b89"); + config.setExtensions("pgcrypto"); + return config.getDockerProperties(); + } + + @Override + public void setupExtraDbDataSource(Config config) { + int defaultPort = config.isUseDocker() ? 6433 : 5433; + config.setDefaultPort(defaultPort); + config.setExtraUsernameDefault(); + config.setExtraDbPasswordDefault(); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); + config.setDriver("org.postgresql.Driver"); + config.extraDatasourceDefaults(); + } + + @Override + public boolean isLocal() { + return false; + } + +} diff --git a/ebean-test/testconfig/ebean-yugabyte.properties b/ebean-test/testconfig/ebean-yugabyte.properties new file mode 100644 index 000000000..126360434 --- /dev/null +++ b/ebean-test/testconfig/ebean-yugabyte.properties @@ -0,0 +1,3 @@ +ebean.test.platform=yugabyte +datasource.default=yugabyte +ebean.test.dbName=unit From 9470a1376c22d485b9046435ad2bd9101db34989 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 13:32:55 +1300 Subject: [PATCH 33/48] Yugabyte - Add specific github workflow build --- .github/workflows/yugabyte.yml | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/yugabyte.yml diff --git a/.github/workflows/yugabyte.yml b/.github/workflows/yugabyte.yml new file mode 100644 index 000000000..b060cc54d --- /dev/null +++ b/.github/workflows/yugabyte.yml @@ -0,0 +1,38 @@ + +name: Yugabyte + +on: + workflow_dispatch: + schedule: + - cron: '10 3 * * *' + +jobs: + build: + + runs-on: ${{ matrix.os }} + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + java_version: [11] + os: [ubuntu-latest] + + steps: + - uses: actions/checkout@v2 + - name: Set up Java + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.java_version }} + distribution: 'adopt' + - name: Maven cache + uses: actions/cache@v2 + env: + cache-name: maven-cache + with: + path: + ~/.m2 + key: build-${{ env.cache-name }} + - name: yugabyte + run: mvn clean test -Dprops.file=testconfig/ebean-yugabyte.properties From a412873da6fc5312b7683434dcf314d182e5fc77 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 13:36:37 +1300 Subject: [PATCH 34/48] ebean-test - bump Postgres default container to 14 --- .../io/ebean/test/config/platform/PostgresSetup.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java index e5d1206f7..836532f76 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java @@ -6,41 +6,33 @@ class PostgresSetup implements PlatformSetup { @Override public Properties setup(Config config) { - int defaultPort = config.isUseDocker() ? 6432 : 5432; - config.ddlMode("dropCreate"); config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); - String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { config.urlAppend("?currentSchema=" + schema); } config.setDriver("org.postgresql.Driver"); config.datasourceDefaults(); - return dockerProperties(config); } private Properties dockerProperties(Config config) { - if (!config.isUseDocker()) { return new Properties(); } - - config.setDockerVersion("12"); + config.setDockerVersion("14"); config.setExtensions("hstore,pgcrypto"); return config.getDockerProperties(); } @Override public void setupExtraDbDataSource(Config config) { - int defaultPort = config.isUseDocker() ? 6432 : 5432; - config.setDefaultPort(defaultPort); config.setExtraUsernameDefault(); config.setExtraDbPasswordDefault(); From 17fed0ebd80b21337c7df17e4dbb628b7a92bbdd Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 1 Feb 2022 15:18:06 +1300 Subject: [PATCH 35/48] Tidy test only - TestNestedBeginRequiresNew --- .../TestNestedBeginRequiresNew.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/transaction/TestNestedBeginRequiresNew.java b/ebean-test/src/test/java/org/tests/transaction/TestNestedBeginRequiresNew.java index b7c7fd3e0..ca6b62bc7 100644 --- a/ebean-test/src/test/java/org/tests/transaction/TestNestedBeginRequiresNew.java +++ b/ebean-test/src/test/java/org/tests/transaction/TestNestedBeginRequiresNew.java @@ -4,54 +4,42 @@ import io.ebean.*; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.tests.model.basic.Address; import org.tests.model.basic.Country; -import org.tests.model.basic.Customer; import org.tests.model.basic.Product; -public class TestNestedBeginRequiresNew extends BaseTestCase { +class TestNestedBeginRequiresNew extends BaseTestCase { Logger logger = LoggerFactory.getLogger(TestNestedBeginRequiresNew.class); Database server = DB.getDefault(); @Test - public void test() { - + void test() { someOuterMethod(); } private void someOuterMethod() { - Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - - server.find(Country.class).findCount(); - - someInnerMethod(); - server.find(Product.class).findCount(); - + someInnerMethod(); + server.find(Address.class).findCount(); txn.commit(); - } finally { txn.end(); } - } private void someInnerMethod() { - logger.debug("someInnerMethod() ..."); Transaction txn = server.beginTransaction(TxScope.requiresNew()); try { - - server.find(Customer.class).findCount(); + server.find(Country.class).findCount(); txn.commit(); - } finally { txn.end(); } logger.debug("someInnerMethod() ... done"); - } } From fddcc647416b69443e19c48ab8ce1aa3be845c46 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 08:59:41 +1300 Subject: [PATCH 36/48] #2521 - Move horrible DB2 hack into DB2GetKeys --- .../server/persist/BatchedPstmt.java | 58 +++---------------- .../server/persist/DB2GetKeys.java | 56 ++++++++++++++++++ 2 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java index 0a14d485a..6a1a8afd2 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java @@ -6,8 +6,6 @@ import io.ebeaninternal.api.SpiTransaction; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -23,18 +21,12 @@ import java.util.List; */ public final class BatchedPstmt implements SpiProfileTransactionEvent { - /** - * The underlying statement. - */ + private static final DB2GetKeys DB2_HACK = new DB2GetKeys(); + private PreparedStatement pstmt; - - /** - * True if an insert that uses generated keys. - */ private final boolean isGenKeys; - /** - * The list of BatchPostExecute used to perform post processing. + * The list of BatchPostExecute used to perform post-processing. */ private final List list = new ArrayList<>(); private final String sql; @@ -44,18 +36,6 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent { private int[] results; private List inputStreams; - private static Class DB2_PREPARED_STATEMENT; - private static Method GET_DB_GENERATED_KEYS; - - static { - try { - DB2_PREPARED_STATEMENT = (Class) Class.forName("com.ibm.db2.jcc.DB2PreparedStatement"); - GET_DB_GENERATED_KEYS = DB2_PREPARED_STATEMENT.getDeclaredMethod("getDBGeneratedKeys"); - } catch (ClassNotFoundException | NoSuchMethodException | SecurityException cnf) { - // NOP - } - - } /** * Create with a given statement. */ @@ -183,35 +163,11 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent { } } - protected void getGeneratedKeys() throws SQLException { - int index = 0; - if (DB2_PREPARED_STATEMENT != null) { - PreparedStatement db2Stmt = null; - if (DB2_PREPARED_STATEMENT.isInstance(pstmt)) { - db2Stmt = pstmt; - } else if (pstmt.isWrapperFor(DB2_PREPARED_STATEMENT)) { - db2Stmt = pstmt.unwrap(DB2_PREPARED_STATEMENT); - } - if (db2Stmt != null) { - // WTF: https://stackoverflow.com/questions/41725492/how-to-get-auto-generated-keys-of-batch-insert-statement - ResultSet[] result; - try { - result = (ResultSet[]) GET_DB_GENERATED_KEYS.invoke(db2Stmt); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new SQLException("Could not get generated keys for DB2", e); - } - for (int i = 0; i < result.length; i++) { - while (result[i].next()) { - ResultSet rset = result[i]; - Object idValue = rset.getObject(1); - list.get(index).setGeneratedKey(idValue); - index++; - } - } - return; - } + private void getGeneratedKeys() throws SQLException { + if (DB2_HACK.getGeneratedKeys(pstmt, list)) { + return; } - + int index = 0; try (ResultSet rset = pstmt.getGeneratedKeys()) { while (rset.next()) { Object idValue = rset.getObject(1); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java new file mode 100644 index 000000000..38d0fe7b4 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java @@ -0,0 +1,56 @@ +package io.ebeaninternal.server.persist; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * Horrible DB2 hack. + */ +final class DB2GetKeys { + + private static Class DB2_PREPARED_STATEMENT; + private static Method GET_DB_GENERATED_KEYS; + + static { + try { + DB2_PREPARED_STATEMENT = (Class) Class.forName("com.ibm.db2.jcc.DB2PreparedStatement"); + GET_DB_GENERATED_KEYS = DB2_PREPARED_STATEMENT.getDeclaredMethod("getDBGeneratedKeys"); + } catch (ClassNotFoundException | NoSuchMethodException | SecurityException cnf) { + // NOP + } + } + + static boolean getGeneratedKeys(PreparedStatement pstmt, List list) throws SQLException { + if (DB2_PREPARED_STATEMENT != null) { + PreparedStatement db2Stmt = null; + if (DB2_PREPARED_STATEMENT.isInstance(pstmt)) { + db2Stmt = pstmt; + } else if (pstmt.isWrapperFor(DB2_PREPARED_STATEMENT)) { + db2Stmt = pstmt.unwrap(DB2_PREPARED_STATEMENT); + } + if (db2Stmt != null) { + // WTF: https://stackoverflow.com/questions/41725492/how-to-get-auto-generated-keys-of-batch-insert-statement + ResultSet[] result; + try { + result = (ResultSet[]) GET_DB_GENERATED_KEYS.invoke(db2Stmt); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new SQLException("Could not get generated keys for DB2", e); + } + int index = 0; + for (ResultSet resultSet : result) { + while (resultSet.next()) { + Object idValue = resultSet.getObject(1); + list.get(index).setGeneratedKey(idValue); + index++; + } + } + return true; + } + } + return false; + } +} From 15f1bd310bee6edddbf11dd51feb2f43c4f85528 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 09:05:14 +1300 Subject: [PATCH 37/48] #2521 - Refactor inline index++ --- .../java/io/ebeaninternal/server/persist/BatchedPstmt.java | 3 +-- .../main/java/io/ebeaninternal/server/persist/DB2GetKeys.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java index 6a1a8afd2..7b3e74085 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchedPstmt.java @@ -171,8 +171,7 @@ public final class BatchedPstmt implements SpiProfileTransactionEvent { try (ResultSet rset = pstmt.getGeneratedKeys()) { while (rset.next()) { Object idValue = rset.getObject(1); - list.get(index).setGeneratedKey(idValue); - index++; + list.get(index++).setGeneratedKey(idValue); } } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java index 38d0fe7b4..a077be908 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/DB2GetKeys.java @@ -44,8 +44,7 @@ final class DB2GetKeys { for (ResultSet resultSet : result) { while (resultSet.next()) { Object idValue = resultSet.getObject(1); - list.get(index).setGeneratedKey(idValue); - index++; + list.get(index++).setGeneratedKey(idValue); } } return true; From cbe133dd685a3d9cb61526c61da4da8afa91f618 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 10:56:59 +1300 Subject: [PATCH 38/48] #2509 - Bump jedis client to 4.1.1 --- ebean-redis/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 125a68c32..b289858a4 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -16,7 +16,7 @@ redis.clients jedis - 4.1.0 + 4.1.1 From a1c0e21234fe1f189eb7a30a3fa8275e70f9b111 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 10:59:04 +1300 Subject: [PATCH 39/48] Bump to 12.15.0-SNAPSHOT --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 4 ++-- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 8 ++++---- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 8 ++++---- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- pom.xml | 2 +- querybean-generator/pom.xml | 2 +- tests/test-java16/pom.xml | 6 +++--- tests/test-kotlin/pom.xml | 4 ++-- 17 files changed, 60 insertions(+), 60 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index b914e2c2b..4acf975e8 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 835b74dbe..b6d34046c 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 6d9110a91..59b70521f 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean bom @@ -71,88 +71,88 @@ io.ebean ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-core-type - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-ddl-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-externalmapping-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-autotune - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-querybean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean querybean-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean ebean-postgis - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-redis - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 0dd19215f..45d6a9109 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 1adcaf362..d02997395 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean-core @@ -41,19 +41,19 @@ io.ebean ebean-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-core-type - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-externalmapping-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index b0e8138dc..b58337b2a 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index d9c3b9e62..ad4bf5abb 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index f7568dc73..79fe81ef2 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean ebean-ddl-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index caa1ccf81..96b3f75b8 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 210e2249e..674598683 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided @@ -56,21 +56,21 @@ io.ebean ebean-ddl-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean querybean-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index b289858a4..aeaba78e8 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean ebean-querybean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean querybean-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index caeaaa5f7..2d3eba06a 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index e399daa25..f178b31dc 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT io.ebean ebean-querybean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 2ddf524ee..317584b9d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT pom ebean parent diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 98d196530..cc6947200 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT querybean generator diff --git a/tests/test-java16/pom.xml b/tests/test-java16/pom.xml index 7ac83574a..aac324f0e 100644 --- a/tests/test-java16/pom.xml +++ b/tests/test-java16/pom.xml @@ -20,7 +20,7 @@ io.ebean ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT @@ -32,7 +32,7 @@ io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test @@ -58,7 +58,7 @@ io.ebean querybean-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index c4138a900..ea863acf4 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -36,14 +36,14 @@ io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test From 26a4feb5ba95f91d5d1f91e54450af6e1011a9e9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 11:14:36 +1300 Subject: [PATCH 40/48] Bump to 12.15.0-SNAPSHOT --- kotlin-querybean-generator/pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index cb1fcce36..af382c110 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test From 1035d741136f546be8a05b5fe97be3333378f079 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 11:20:59 +1300 Subject: [PATCH 41/48] Bump to 12.15.0-SNAPSHOT --- ebean-kotlin/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ebean-kotlin/pom.xml b/ebean-kotlin/pom.xml index 8d8a3d3b9..e8b06e92d 100644 --- a/ebean-kotlin/pom.xml +++ b/ebean-kotlin/pom.xml @@ -5,7 +5,7 @@ ebean-parent io.ebean - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT 4.0.0 @@ -29,7 +29,7 @@ io.ebean ebean-core - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT provided @@ -51,7 +51,7 @@ io.ebean ebean-test - 12.14.2-SNAPSHOT + 12.15.0-SNAPSHOT test From 886f539fc455a04e8d6bfad707d08eefe464423f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 11:30:56 +1300 Subject: [PATCH 42/48] Refactor tidy SqlTreeNodeBean --- .../server/query/SqlTreeLoadBean.java | 10 ++++----- .../server/query/SqlTreeNodeBean.java | 21 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java index 516a00537..aa3cf9d1f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java @@ -46,12 +46,12 @@ class SqlTreeLoadBean implements SqlTreeLoad { this.temporalMode = node.temporalMode; this.temporalVersions = node.temporalVersions; this.nodeBeanProp = node.nodeBeanProp; - this.readId = node.readId;//!aggregationRoot && withId && desc.hasId(); + this.readId = node.readId; this.readIdNormal = readId && !temporalVersions; - this.disableLazyLoad = node.disableLazyLoad;// disableLazyLoad || !readIdNormal || desc.isRawSqlBased(); - this.partialObject = node.partialObject;//props.isPartialObject(); - this.properties = node.properties;//props.getProps(); - this.pathMap = node.pathMap;//createPathMap(prefix, desc); + this.disableLazyLoad = node.disableLazyLoad; + this.partialObject = node.partialObject; + this.properties = node.properties; + this.pathMap = node.pathMap; this.children = node.createLoadChildren(); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 6214137c1..6c62116fc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -15,14 +15,13 @@ import java.util.*; class SqlTreeNodeBean implements SqlTreeNode { private static final SqlTreeLoad[] NO_LOAD_CHILDREN = new SqlTreeLoad[0]; - private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0]; final STreeType desc; final IdBinder idBinder; /** * The children which will be other SelectBean or SelectProxyBean. */ - final SqlTreeNode[] children; + final List children; /** * Set to true if this is a partial object fetch. */ @@ -94,8 +93,8 @@ class SqlTreeNodeBean implements SqlTreeNode { this.disableLazyLoad = disableLazyLoad || !readIdNormal || desc.isRawSqlBased(); this.partialObject = props.isPartialObject(); this.properties = props.getProps(); - this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[0]); - pathMap = createPathMap(prefix, desc); + this.children = myChildren == null ? Collections.emptyList() : myChildren; + this.pathMap = createPathMap(prefix, desc); } @Override @@ -104,10 +103,10 @@ class SqlTreeNodeBean implements SqlTreeNode { } protected SqlTreeLoad[] createLoadChildren() { - if (children.length == 0) { + if (children.isEmpty()) { return NO_LOAD_CHILDREN; } - List loadChildren = new ArrayList<>(children.length); + List loadChildren = new ArrayList<>(children.size()); for (SqlTreeNode child : children) { SqlTreeLoad load = child.createLoad(); if (load != null) { @@ -119,19 +118,19 @@ class SqlTreeNodeBean implements SqlTreeNode { @Override public final boolean isSingleProperty() { - return properties != null && properties.length == 1 && children.length == 0; + return properties != null && properties.length == 1 && children.isEmpty(); } private Map createPathMap(String prefix, STreeType desc) { HashMap m = new HashMap<>(); for (STreePropertyAssocMany many : desc.propsMany()) { String name = many.name(); - m.put(name, getPath(prefix, name)); + m.put(name, path(prefix, name)); } return m; } - private String getPath(String prefix, String propertyName) { + private String path(String prefix, String propertyName) { if (prefix == null) { return propertyName; } else { @@ -144,7 +143,7 @@ class SqlTreeNodeBean implements SqlTreeNode { if (readId) { if (inheritInfo != null) { // discriminator column always proceeds id column - selectChain.add(getPath(prefix, inheritInfo.getDiscriminatorColumn())); + selectChain.add(path(prefix, inheritInfo.getDiscriminatorColumn())); } idBinder.buildRawSqlSelectChain(prefix, selectChain); } @@ -399,7 +398,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } return false; } - + @Override public void unselectLobs() { From 43af5343a43ef98ce233634ba99d2b052fa59115 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 12:10:02 +1300 Subject: [PATCH 43/48] Performance - cache the path maps used for load context - Cache the path maps - Include the ToOne paths - Use empty map for null prefix --- .../server/deploy/BeanDescriptor.java | 18 ++++++++++++++++++ .../io/ebeaninternal/server/query/CQuery.java | 14 +++++--------- .../ebeaninternal/server/query/STreeType.java | 6 ++++++ .../server/query/SqlTreeNodeBean.java | 13 ++----------- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index eba1eea95..c06dfce3e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -86,6 +86,8 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { private final ConcurrentHashMap elDeployCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap> comparatorCache = new ConcurrentHashMap<>(); private final ConcurrentHashMap dynamicProperty = new ConcurrentHashMap<>(); + private final ConcurrentHashMap> pathMaps = new ConcurrentHashMap<>(); + private final Map namedRawSql; private final Map namedQuery; private final boolean multiValueSupported; @@ -2775,6 +2777,22 @@ public class BeanDescriptor implements BeanType, STreeType, SpiBeanType { return draftableElement; } + @Override + public Map pathMap(String prefix) { + return pathMaps.computeIfAbsent(prefix, s -> { + HashMap m = new HashMap<>(); + for (STreePropertyAssocMany many : propsMany()) { + String name = many.name(); + m.put(name, prefix + "." + name); + } + for (STreePropertyAssocOne one : propsOne()) { + String name = one.name(); + m.put(name, prefix + "." + name); + } + return m.isEmpty() ? Collections.emptyMap() : m; + }); + } + @Override public boolean isEmbeddedPath(String propertyPath) { ElPropertyDeploy elProp = elPropertyDeploy(propertyPath); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java index 1870c1b6f..634591fec 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -581,19 +581,19 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi @Override public void registerBeanInherit(BeanPropertyAssocOne property, EntityBeanIntercept ebi) { - String path = getPath(property.name()); + String path = path(property.name()); request.loadContext().register(path, ebi, property); } @Override public void register(String path, EntityBeanIntercept ebi) { - path = getPath(path); + path = path(path); request.loadContext().register(path, ebi); } @Override public void register(BeanPropertyAssocMany many, BeanCollection bc) { - String path = getPath(many.name()); + String path = path(many.name()); request.loadContext().register(path, many, bc); } @@ -663,18 +663,14 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi return autoTuneProfiling && query.isUsageProfiling(); } - private String getPath(String propertyName) { + private String path(String propertyName) { if (currentPrefix == null) { return propertyName; } else if (propertyName == null) { return currentPrefix; } String path = currentPathMap.get(propertyName); - if (path != null) { - return path; - } else { - return currentPrefix + "." + propertyName; - } + return path != null ? path : currentPrefix + "." + propertyName; } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeType.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeType.java index 3bb58dd1c..88e3b851a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeType.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeType.java @@ -7,6 +7,8 @@ import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.id.IdBinder; +import java.util.Map; + /** * Bean type interface for Sql query tree. */ @@ -136,4 +138,8 @@ public interface STreeType { */ void markAsDeleted(EntityBean bean); + /** + * Return the "path map" to toMany or toOne properties using the given prefix. + */ + Map pathMap(String prefix); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 6c62116fc..d5ec71aa4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -122,20 +122,11 @@ class SqlTreeNodeBean implements SqlTreeNode { } private Map createPathMap(String prefix, STreeType desc) { - HashMap m = new HashMap<>(); - for (STreePropertyAssocMany many : desc.propsMany()) { - String name = many.name(); - m.put(name, path(prefix, name)); - } - return m; + return prefix == null ? Collections.emptyMap() : desc.pathMap(prefix); } private String path(String prefix, String propertyName) { - if (prefix == null) { - return propertyName; - } else { - return prefix + "." + propertyName; - } + return prefix == null ? propertyName : prefix + "." + propertyName; } @Override From 376b3a9f13ae336d8375681f4ca1fce4163ad59c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 12:20:33 +1300 Subject: [PATCH 44/48] #2538 - Tidy CQuery use of path() --- .../main/java/io/ebeaninternal/server/query/CQuery.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java index 634591fec..22e2e1f37 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -581,20 +581,17 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi @Override public void registerBeanInherit(BeanPropertyAssocOne property, EntityBeanIntercept ebi) { - String path = path(property.name()); - request.loadContext().register(path, ebi, property); + request.loadContext().register(path(property.name()), ebi, property); } @Override public void register(String path, EntityBeanIntercept ebi) { - path = path(path); - request.loadContext().register(path, ebi); + request.loadContext().register(path(path), ebi); } @Override public void register(BeanPropertyAssocMany many, BeanCollection bc) { - String path = path(many.name()); - request.loadContext().register(path, many, bc); + request.loadContext().register(path(many.name()), many, bc); } /** From 170e323ee9465fa58677800ee51f40baf912fef7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 13:02:49 +1300 Subject: [PATCH 45/48] #2507 - Script runner does not work with file system path --- .../src/main/java/io/ebean/ScriptRunner.java | 19 ++++-- .../server/core/DScriptRunner.java | 53 ++++++++++------ .../java/io/ebean/EbeanServer_refresh.java | 61 ++++++++++--------- 3 files changed, 79 insertions(+), 54 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/ScriptRunner.java b/ebean-api/src/main/java/io/ebean/ScriptRunner.java index 15057741e..ff2e9d668 100644 --- a/ebean-api/src/main/java/io/ebean/ScriptRunner.java +++ b/ebean-api/src/main/java/io/ebean/ScriptRunner.java @@ -1,6 +1,7 @@ package io.ebean; import java.net.URL; +import java.nio.file.Path; import java.util.Map; /** @@ -23,10 +24,10 @@ public interface ScriptRunner { /** * Run a script given the resource path (that should start with "/"). */ - void run(String path); + void run(String resourcePath); /** - * Run a script given the resource path (that should start with "/") and place holders. + * Run a script given the resource path (that should start with "/") and place-holders. * *

{@code
    *
@@ -38,7 +39,7 @@ public interface ScriptRunner {
    *
    * }
*/ - void run(String path, Map placeholderMap); + void run(String resourcePath, Map placeholderMap); /** * Run a DDL or SQL script given the resource. @@ -46,10 +47,20 @@ public interface ScriptRunner { void run(URL resource); /** - * Run a DDL or SQL script given the resource and place holders. + * Run a DDL or SQL script given the resource and place-holders. */ void run(URL resource, Map placeholderMap); + /** + * Run a DDL or SQL script given the file. + */ + void run(Path file); + + /** + * Run a DDL or SQL script given the file and place-holders. + */ + void run(Path file, Map placeholderMap); + /** * Run the raw provided DDL or SQL script. * diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java index fb2fbd0a2..fdb24bd0d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java @@ -8,15 +8,15 @@ import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.util.UrlHelper; import javax.persistence.PersistenceException; -import java.io.IOException; -import java.io.InputStream; -import java.io.LineNumberReader; -import java.io.Reader; +import java.io.*; import java.net.URL; +import java.nio.file.Path; import java.sql.Connection; import java.sql.SQLException; import java.util.Map; +import static java.util.Objects.requireNonNull; + final class DScriptRunner implements ScriptRunner { private static final String NEWLINE = "\n"; @@ -30,8 +30,8 @@ final class DScriptRunner implements ScriptRunner { } @Override - public void run(String path) { - run(path, null); + public void run(String resourcePath) { + run(resourcePath, null); } @Override @@ -49,27 +49,42 @@ final class DScriptRunner implements ScriptRunner { run(resource, null, placeholderMap); } + @Override + public void run(Path file) { + run(file, null); + } + + @Override + public void run(Path file, Map placeholderMap) { + requireNonNull(file); + String scriptName = file.toFile().getName(); + String content = fileContent(file); + runScript(content, scriptName, placeholderMap, false); + } + private void run(URL resource, String scriptName, Map placeholderMap) { - if (resource == null) { - throw new IllegalArgumentException("resource is null?"); - } + requireNonNull(resource); if (scriptName == null) { scriptName = resource.getFile(); } - String content = content(resource); runScript(content, scriptName, placeholderMap, false); } - private String content(URL resource) { - if (resource == null) { - throw new IllegalArgumentException("resource is null?"); - } - - try (InputStream inputStream = UrlHelper.openNoCache(resource); - Reader reader = IOUtils.newReader(inputStream)) { + private String fileContent(Path file) { + try (InputStream inputStream = new FileInputStream(file.toFile()); + Reader reader = IOUtils.newReader(inputStream)) { return readContent(reader); + } catch (IOException e) { + throw new PersistenceException("Failed to read script content", e); + } + } + private String content(URL resource) { + requireNonNull(resource); + try (InputStream inputStream = UrlHelper.openNoCache(resource); + Reader reader = IOUtils.newReader(inputStream)) { + return readContent(reader); } catch (IOException e) { throw new PersistenceException("Failed to read script content", e); } @@ -85,10 +100,9 @@ final class DScriptRunner implements ScriptRunner { */ private void runScript(String content, String scriptName, Map placeholderMap, boolean useAutoCommit) { try { - if (placeholderMap != null) { + if (placeholderMap != null && !placeholderMap.isEmpty()) { content = ScriptTransform.build(null, placeholderMap).transform(content); } - try (Connection connection = obtainConnection()) { DdlRunner runner = new DdlRunner(useAutoCommit, scriptName, platformName); runner.runAll(content, connection); @@ -110,7 +124,6 @@ final class DScriptRunner implements ScriptRunner { } private String readContent(Reader reader) throws IOException { - StringBuilder buf = new StringBuilder(); try (LineNumberReader lineReader = new LineNumberReader(reader)) { String line; diff --git a/ebean-test/src/test/java/io/ebean/EbeanServer_refresh.java b/ebean-test/src/test/java/io/ebean/EbeanServer_refresh.java index 86c25de9b..1ff650b7d 100644 --- a/ebean-test/src/test/java/io/ebean/EbeanServer_refresh.java +++ b/ebean-test/src/test/java/io/ebean/EbeanServer_refresh.java @@ -6,18 +6,39 @@ import org.tests.model.basic.Order; import org.tests.model.basic.OrderDetail; import org.tests.model.basic.ResetBasicData; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.*; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; -public class EbeanServer_refresh { +class EbeanServer_refresh { + + private Path createSqlFile() throws IOException { + File f = File.createTempFile("test-script", ".sql"); + Path path = f.toPath(); + List lines = new ArrayList<>(); + lines.add("select * from o_customer;"); + Files.write(path, lines, StandardOpenOption.TRUNCATE_EXISTING); + return path; + } @Test - public void basic() { + void script_run_asFile() throws IOException { + ResetBasicData.reset(); + Path path = createSqlFile(); + DB.script().run(path); + DB.script().run(path, Collections.emptyMap()); + } + + @Test + void basic() { Map map = new HashMap<>(); map.put("tableName", "e_basic"); @@ -47,8 +68,7 @@ public class EbeanServer_refresh { } @Test - public void refresh_when_oneToManyLoaded() { - + void refresh_when_oneToManyLoaded() { ResetBasicData.reset(); Order order = DB.find(Order.class, 1); @@ -59,8 +79,7 @@ public class EbeanServer_refresh { } @Test - public void refresh_when_oneToManyVanilla() { - + void refresh_when_oneToManyVanilla() { ResetBasicData.reset(); Order order = DB.find(Order.class, 1); @@ -71,8 +90,7 @@ public class EbeanServer_refresh { } @Test - public void refresh_when_oneToManyNull() { - + void refresh_when_oneToManyNull() { ResetBasicData.reset(); Order order = DB.find(Order.class, 1); @@ -82,15 +100,11 @@ public class EbeanServer_refresh { DB.refresh(order); } - - @Test - public void refresh_on_details_new() { - + void refresh_on_details_new() { ResetBasicData.reset(); Order order = DB.find(Order.class, 1); - DB.refresh(order); // call refresh BEFORE first access on "getDetail"; assertThat(order.getDetails()).hasSize(3); @@ -100,13 +114,9 @@ public class EbeanServer_refresh { DB.save(detail); try { - assertThat(order.getDetails()).hasSize(3); - DB.refresh(order); - assertThat(order.getDetails()).hasSize(4); - } finally { DB.delete(detail); // restore old state } @@ -116,13 +126,9 @@ public class EbeanServer_refresh { assertThat(order.getDetails()).hasSize(3); } - - @Test - public void refresh_on_details_changed() { - + void refresh_on_details_changed() { ResetBasicData.reset(); - Order order = DB.find(Order.class, 1); DB.refresh(order); // call refresh BEFORE first access on "getDetail" @@ -139,11 +145,8 @@ public class EbeanServer_refresh { try { assertThat(order.getDetails().get(0).getOrderQty()).isEqualTo(5); - DB.refresh(order); - assertThat(order.getDetails().get(0).getOrderQty()).isEqualTo(42); - } finally { // restore old value detail.setOrderQty(5); @@ -151,8 +154,6 @@ public class EbeanServer_refresh { } DB.refresh(order); - assertThat(order.getDetails().get(0).getOrderQty()).isEqualTo(5); - } } From f7c83411c2b6b937a22ae1c817cc154a4c317461 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 17:12:18 +1300 Subject: [PATCH 46/48] #2415 - SQL for Index and Foreign Key didn't get generated if I map ID column after @ManyToOne Allow declaring the column twice with scalar type after ManyToOne type --- .../dbmigration/model/MTable.java | 10 +++ .../build/ModelBuildPropertyVisitor.java | 8 +-- .../dbmigration/model/MTableTest.java | 62 +++++++++++-------- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index 5bc946fa7..90fd27228 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -561,6 +561,16 @@ public class MTable { return newCol; } + public MColumn addColumnScalar(String dbColumn, String columnDefn) { + MColumn existingColumn = getColumn(dbColumn); + if (existingColumn != null) { + return existingColumn; + } + MColumn newCol = new MColumn(dbColumn, columnDefn); + addColumn(newCol); + return newCol; + } + /** * Add a 'new column' to the AddColumn migration object. */ diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index 398bee86f..56748d993 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -246,14 +246,13 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { lastColumn = null; return; } - // using non-strict mode to render the DB type such that we have a // "logical" type like jsonb(200) that can map to JSONB or VARCHAR(200) - MColumn col = new MColumn(p.dbColumn(), ctx.getColumnDefn(p, false)); + MColumn col = table.addColumnScalar(p.dbColumn(), ctx.getColumnDefn(p, false)); + //MColumn col = new MColumn(p.dbColumn(), ctx.getColumnDefn(p, false)); col.setComment(p.dbComment()); col.setDraftOnly(p.isDraftOnly()); col.setHistoryExclude(p.isExcludedFromHistory()); - if (p.isId() || p.isImportedPrimaryKey()) { col.setPrimaryKey(true); if (p.descriptor().isUseIdGenerator()) { @@ -279,7 +278,6 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { } col.setDbMigrationInfos(p.dbMigrationInfos()); - if (p.isUnique() && !p.isId()) { col.setUnique(uniqueConstraintName(col.getName())); indexSetAdd(col.getName()); @@ -293,9 +291,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { col.setCheckConstraint(buildCheckConstraint(p.dbColumn(), checkConstraintValues)); col.setCheckConstraintName(checkConstraintName(col.getName())); } - lastColumn = col; - table.addColumn(col); } /** diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MTableTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MTableTest.java index f3e2d5648..012df7d49 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MTableTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/model/MTableTest.java @@ -13,14 +13,13 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; -public class MTableTest { +class MTableTest { static MTable base() { MTable table = new MTable("tab"); table.addColumn(new MColumn("id", "bigint")); table.addColumn(new MColumn("name", "varchar(20)")); table.addColumn(new MColumn("status", "varchar(3)")); - return table; } @@ -29,7 +28,6 @@ public class MTableTest { table.addColumn(new MColumn("id", "bigint")); table.addColumn(new MColumn("name", "varchar(20)")); table.addColumn(new MColumn("comment", "varchar(1000)")); - return table; } @@ -55,7 +53,7 @@ public class MTableTest { } @Test - public void schema() { + void schema() { MTable table = new MTable("tab"); assertNull(table.getSchema()); @@ -65,8 +63,29 @@ public class MTableTest { } @Test - public void test_allHistoryColumns() throws Exception { + void addColumnScalar_when_new() { + MTable table = new MTable("tab"); + MColumn mColumn = table.addColumnScalar("billing_id", "bigint"); + assertThat(mColumn).isNotNull(); + assertThat(mColumn.getName()).isEqualTo("billing_id"); + assertThat(mColumn.getType()).isEqualTo("bigint"); + } + + @Test + void addColumnScalar_when_existingColumnDefined() { + MTable table = new MTable("tab"); + MColumn col = new MColumn("billing_id", "bigint"); + col.setForeignKeyName("fk_tab_billing_id"); + col.setForeignKeyIndex("ix_tab_billing_id"); + table.addColumn(col); + + MColumn mColumn = table.addColumnScalar("billing_id", "bigint"); + assertThat(mColumn).isSameAs(col); + } + + @Test + void test_allHistoryColumns() { MTable base = base(); base.registerPendingDropColumn("fullName"); base.registerPendingDropColumn("last"); @@ -76,16 +95,14 @@ public class MTableTest { } @Test - public void test_dropTable() { - + void test_dropTable() { MTable base = base(); DropTable dropTable = base.dropTable(); assertThat(dropTable.getName()).isEqualTo(base.getName()); } @Test - public void test_compare_addColumnDropColumn() throws Exception { - + void test_compare_addColumnDropColumn() { ModelDiff diff = new ModelDiff(); diff.compareTables(base(), newTable()); @@ -104,8 +121,7 @@ public class MTableTest { } @Test - public void test_compare_addTwoColumnsToSameTable() throws Exception { - + void test_compare_addTwoColumnsToSameTable() { ModelDiff diff = new ModelDiff(); diff.compareTables(base(), newTableAdd2Columns()); @@ -117,12 +133,10 @@ public class MTableTest { assertThat(addColumn.getColumn()).extracting("type").contains("varchar(1000)", "varchar(2000)"); assertThat(diff.getDropChanges()).hasSize(0); - } @Test - public void test_compare_modifyColumn() throws Exception { - + void test_compare_modifyColumn() { ModelDiff diff = new ModelDiff(); diff.compareTables(base(), newTableModifiedColumn()); @@ -138,12 +152,10 @@ public class MTableTest { assertThat(alterColumn.getReferences()).isNull(); assertThat(diff.getDropChanges()).hasSize(0); - } @Test - public void test_apply_dropColumn() { - + void test_apply_dropColumn() { MTable base = base(); DropColumn dropColumn = new DropColumn(); @@ -155,7 +167,7 @@ public class MTableTest { } @Test - public void test_apply_dropColumn_doesNotExist() { + void test_apply_dropColumn_doesNotExist() { MTable base = base(); DropColumn dropColumn = new DropColumn(); @@ -165,7 +177,7 @@ public class MTableTest { } @Test - public void test_apply_alterColumn_doesNotExist() { + void test_apply_alterColumn_doesNotExist() { MTable base = base(); AlterColumn alterColumn = new AlterColumn(); @@ -177,8 +189,7 @@ public class MTableTest { } @Test - public void test_apply_alterColumn_type() { - + void test_apply_alterColumn_type() { MTable base = base(); AlterColumn alterColumn = new AlterColumn(); @@ -191,8 +202,7 @@ public class MTableTest { } @Test - public void test_compare_addAndDropColumn() throws Exception { - + void test_compare_addAndDropColumn() { MTable base = base(); MTable newTable = newTable(); @@ -204,8 +214,7 @@ public class MTableTest { } @Test - public void test_compare_addHistoryToTable() { - + void test_compare_addHistoryToTable() { MTable base = base(); MTable withHistory = base(); withHistory.setWithHistory(true); @@ -219,8 +228,7 @@ public class MTableTest { } @Test - public void test_compare_removeHistoryFromTable() throws Exception { - + void test_compare_removeHistoryFromTable() { MTable withHistory = base(); withHistory.setWithHistory(true); From 5a12cc58d13d814e625ba1e65a3b1afe0ae07260 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 17:18:14 +1300 Subject: [PATCH 47/48] Bump Postgres test dependencies to 42.3.2 --- ebean-core/pom.xml | 2 +- ebean-postgis/pom.xml | 4 ++-- ebean-test/pom.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index d02997395..8c5c1f2b7 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -136,7 +136,7 @@ org.postgresql postgresql - 42.2.24 + 42.3.2 true diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 96b3f75b8..c2610ec63 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -44,7 +44,7 @@ org.postgresql postgresql - 42.2.24 + 42.3.2 provided @@ -52,7 +52,7 @@ org.slf4j slf4j-api - 1.7.30 + 1.7.33 provided diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 2d3eba06a..4e97195c6 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -147,7 +147,7 @@ org.postgresql postgresql - 42.2.24 + 42.3.2 org.checkerframework From 9d506b4397605f3ae4980e849c761f0b5b3dfa86 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 2 Feb 2022 20:48:55 +1300 Subject: [PATCH 48/48] Bump test dependencies --- ebean-autotune/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 2 +- ebean-kotlin/pom.xml | 2 +- ebean-postgis/pom.xml | 2 +- ebean-querybean/pom.xml | 2 +- ebean-redis/pom.xml | 2 +- ebean-test/pom.xml | 10 +++++----- pom.xml | 6 +++--- tests/test-java16/pom.xml | 2 +- tests/test-kotlin/pom.xml | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index b6d34046c..efab75026 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -63,7 +63,7 @@ true - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 79fe81ef2..aea54405e 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -89,7 +89,7 @@ - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-kotlin/pom.xml b/ebean-kotlin/pom.xml index e8b06e92d..4a29c69bd 100644 --- a/ebean-kotlin/pom.xml +++ b/ebean-kotlin/pom.xml @@ -93,7 +93,7 @@ true - io.ebean.tile:enhancement:12.13.1 + io.ebean.tile:enhancement:12.15.0 diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index c2610ec63..ac99bf2e1 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -105,7 +105,7 @@ true - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 674598683..9c9f3ad93 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -100,7 +100,7 @@ true - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index aeaba78e8..d0b3ad2f1 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -80,7 +80,7 @@ true - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 4e97195c6..7844288da 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -62,14 +62,14 @@ org.assertj assertj-core - 3.14.0 + 3.22.0 org.glassfish.jaxb jaxb-runtime - 2.3.2 + 2.3.6 @@ -98,7 +98,7 @@ io.avaje mod-uuid - 1.1 + 1.3 test @@ -226,7 +226,7 @@ ch.qos.logback logback-classic - 1.2.9 + 1.2.10 test @@ -249,7 +249,7 @@ true - io.ebean.tile:enhancement:12.14.1 + io.ebean.tile:enhancement:12.15.0 io.avaje.tile:moditech-module:1.0 diff --git a/pom.xml b/pom.xml index 317584b9d..da2cfe4f3 100644 --- a/pom.xml +++ b/pom.xml @@ -43,11 +43,11 @@ 2.1.210 1.2 1.1 - 12.13.1 + 12.15.0 4.2 7.5 - 12.14.1 - 12.14.1 + 12.15.0 + 12.15.0
diff --git a/tests/test-java16/pom.xml b/tests/test-java16/pom.xml index aac324f0e..a45c0ca20 100644 --- a/tests/test-java16/pom.xml +++ b/tests/test-java16/pom.xml @@ -26,7 +26,7 @@ ch.qos.logback logback-classic - 1.2.9 + 1.2.10 diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index ea863acf4..07d81c933 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -50,7 +50,7 @@ ch.qos.logback logback-classic - 1.2.9 + 1.2.10 test