From 091b5fbf2608be1a8576448becbe4ded7e7dadb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Mon, 27 Sep 2021 17:08:22 +0200 Subject: [PATCH 01/47] Optionally allow use of stored procedures for MySql to drop columns in db migration --- .../java/io/ebean/config/PlatformConfig.java | 18 ++++ .../config/dbplatform/DatabasePlatform.java | 14 +++ .../sqlserver/SqlServerBasePlatform.java | 5 ++ .../dbmigration/DdlGenerator.java | 7 +- .../dbmigration/DefaultDbMigration.java | 16 ++-- .../ddlgeneration/platform/MySqlDdl.java | 12 +++ .../dbmigration/builtin-extra-ddl.xml | 83 +++++++++++++++++ .../MysqlGenerateMigrationTest.java | 78 ++++++++++++++++ .../misc/migration/mysql_v1_0/EBasic.java | 89 +++++++++++++++++++ .../misc/migration/mysql_v1_1/EBasic.java | 64 +++++++++++++ .../procedures/model/1.0__initial.model.xml | 12 +++ .../mysql/procedures/model/1.1.model.xml | 7 ++ .../model/1.2__dropsFor_1.1.model.xml | 7 ++ .../mysql/procedures/mysql/1.0__initial.sql | 11 +++ .../procedures/mysql/1.2__dropsFor_1.1.sql | 6 ++ .../procedures/mysql/I__create_procs.sql | 48 ++++++++++ .../procedures/mysql/idx_mysql.migrations | 4 + 17 files changed, 474 insertions(+), 7 deletions(-) create mode 100644 ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java create mode 100644 ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_0/EBasic.java create mode 100644 ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_1/EBasic.java create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.0__initial.model.xml create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.1.model.xml create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.2__dropsFor_1.1.model.xml create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.0__initial.sql create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.2__dropsFor_1.1.sql create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/I__create_procs.sql create mode 100644 ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/idx_mysql.migrations diff --git a/ebean-api/src/main/java/io/ebean/config/PlatformConfig.java b/ebean-api/src/main/java/io/ebean/config/PlatformConfig.java index bcb97158d..065af2393 100644 --- a/ebean-api/src/main/java/io/ebean/config/PlatformConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/PlatformConfig.java @@ -66,6 +66,8 @@ public class PlatformConfig { private boolean caseSensitiveCollation = true; + private boolean useMigrationStoredProcedures = false; + /** * Modify the default mapping of standard types such as default precision for DECIMAL etc. */ @@ -90,6 +92,7 @@ public class PlatformConfig { this.geometrySRID = platformConfig.geometrySRID; this.dbUuid = platformConfig.dbUuid; this.caseSensitiveCollation = platformConfig.caseSensitiveCollation; + this.useMigrationStoredProcedures = platformConfig.useMigrationStoredProcedures; this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers; this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar; this.customDbTypeMappings = platformConfig.customDbTypeMappings; @@ -139,6 +142,20 @@ public class PlatformConfig { this.caseSensitiveCollation = caseSensitiveCollation; } + /** + * Return true if force use of helper stored procedures for migrations. + */ + public boolean isUseMigrationStoredProcedures() { + return useMigrationStoredProcedures; + } + + /** + * Set true to force use of helper stored procedures for migrations. + */ + public void setUseMigrationStoredProcedures(boolean useMigrationStoredProcedures) { + this.useMigrationStoredProcedures = useMigrationStoredProcedures; + } + /** * Return true if Postgres FOR UPDATE should use the NO KEY option. */ @@ -314,6 +331,7 @@ public class PlatformConfig { databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse); databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar); caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation); + useMigrationStoredProcedures = p.getBoolean("useMigrationStoredProcedures", useMigrationStoredProcedures); DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null); if (dbUuid != null) { diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 205bdf2b6..8a6d570f6 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -53,6 +53,8 @@ public class DatabasePlatform { protected boolean supportsSavepointId = true; + protected boolean useMigrationStoredProcedures = false; + /** * The behaviour used when ending a read only transaction at read committed isolation level. */ @@ -237,6 +239,7 @@ public class DatabasePlatform { public void configure(PlatformConfig config) { this.sequenceBatchSize = config.getDatabaseSequenceBatchSize(); this.caseSensitiveCollation = config.isCaseSensitiveCollation(); + this.useMigrationStoredProcedures = config.isUseMigrationStoredProcedures(); configureIdType(config.getIdType()); configure(config, config.isAllQuotedIdentifiers()); } @@ -343,6 +346,13 @@ public class DatabasePlatform { return supportsSavepointId; } + /** + * Return true if migrations should use stored procedures. + */ + public boolean isUseMigrationStoredProcedures() { + return useMigrationStoredProcedures; + } + /** * Return true if the platform supports LIMIT with sql update. */ @@ -573,6 +583,10 @@ public class DatabasePlatform { this.supportsResultSetConcurrencyModeUpdatable = supportsResultSetConcurrencyModeUpdatable; } + public void setUseMigrationStoredProcedures(final boolean useMigrationStoredProcedures) { + this.useMigrationStoredProcedures = useMigrationStoredProcedures; + } + /** * Normally not needed - overridden in CockroachPlatform. */ diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index bc14ab0c6..eb3dad7be 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -119,4 +119,9 @@ abstract class SqlServerBasePlatform extends DatabasePlatform { // for update are hints on from clause of base table return sql; } + + @Override + public boolean isUseMigrationStoredProcedures() { + return true; + } } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java index 69a4af033..60c5f6bd3 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java @@ -50,6 +50,7 @@ public class DdlGenerator implements SpiDdlGenerator { private final ScriptTransform scriptTransform; private final Platform platform; private final String platformName; + private final boolean useMigrationStoredProcedures; private CurrentModel currentModel; private String dropAllContent; @@ -71,9 +72,11 @@ public class DdlGenerator implements SpiDdlGenerator { log.warn("DDL can't be run on startup with TenantMode " + config.getTenantMode()); this.runDdl = false; this.ddlAutoCommit = false; + this.useMigrationStoredProcedures = false; } else { this.runDdl = config.isDdlRun(); this.ddlAutoCommit = databasePlatform.isDdlAutoCommit(); + this.useMigrationStoredProcedures = config.getDatabasePlatform().isUseMigrationStoredProcedures(); } this.scriptTransform = createScriptTransform(config); this.baseDir = initBaseDir(); @@ -187,7 +190,7 @@ public class DdlGenerator implements SpiDdlGenerator { protected void runDropSql(Connection connection) throws IOException { if (!createOnly) { - if (extraDdl && jaxbPresent) { + if (extraDdl && jaxbPresent && useMigrationStoredProcedures) { String extraApply = ExtraDdlXmlReader.buildExtra(platform, true); if (extraApply != null) { runScript(connection, false, extraApply, "extra-ddl"); @@ -210,7 +213,7 @@ public class DdlGenerator implements SpiDdlGenerator { if (extraDdl && jaxbPresent) { if (currentModel().isTablePartitioning()) { String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(platform); - if (extraPartitioning != null && !extraPartitioning.isEmpty()) { + if (extraPartitioning != null && !extraPartitioning.isEmpty() && useMigrationStoredProcedures) { runScript(connection, false, extraPartitioning, "builtin-partitioning-ddl"); } } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index a7a3703d7..47ceffc6a 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -392,19 +392,25 @@ public class DefaultDbMigration implements DbMigration { private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform, boolean tablePartitioning) throws IOException { if (dbPlatform != null) { if (tablePartitioning && includeBuiltInPartitioning) { - generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltinTablePartitioning()); + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltinTablePartitioning(), true); } - generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin()); - generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.read()); + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin(), true); + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.read(), false); } } - private void generateExtraDdlFor(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl) throws IOException { + private void generateExtraDdlFor(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl, boolean isBuiltin) throws IOException { if (extraDdl != null) { List ddlScript = extraDdl.getDdlScript(); for (DdlScript script : ddlScript) { if (!script.isDrop() && matchPlatform(dbPlatform.getPlatform(), script.getPlatforms())) { - writeExtraDdl(migrationDir, script); + if (script.isInit()) { + if (!isBuiltin || dbPlatform.isUseMigrationStoredProcedures()) { + writeExtraDdl(migrationDir, script); + } + } else { + writeExtraDdl(migrationDir, script); + } } } } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java index f5658c3ec..c772a30aa 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MySqlDdl.java @@ -18,12 +18,15 @@ public class MySqlDdl extends PlatformDdl { // this flag is for compatibility. Use it with care. private static final boolean USE_CHECK_CONSTRAINT = Boolean.getBoolean("ebean.mysql.useCheckConstraint"); + private final boolean useMigrationStoredProcedures; + public MySqlDdl(DatabasePlatform platform) { super(platform); this.alterColumn = "modify"; this.dropUniqueConstraint = "drop index"; this.historyDdl = new MySqlHistoryDdl(); this.inlineComments = true; + this.useMigrationStoredProcedures = platform.isUseMigrationStoredProcedures(); } /** @@ -34,6 +37,15 @@ public class MySqlDdl extends PlatformDdl { return "drop index " + maxConstraintName(indexName) + " on " + tableName; } + @Override + public void alterTableDropColumn(final DdlBuffer buffer, final String tableName, final String columnName) throws IOException { + if (this.useMigrationStoredProcedures) { + buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')").endOfStatement(); + } else { + super.alterTableDropColumn(buffer, tableName, columnName); + } + } + /** * Return the drop foreign key clause. */ diff --git a/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml b/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml index 66d23b702..402c51f94 100644 --- a/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml +++ b/ebean-ddl-generator/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml @@ -112,5 +112,88 @@ BEGIN END GO +-- Inital script to create stored procedures etc for mysql platform +DROP PROCEDURE IF EXISTS usp_ebean_drop_foreign_keys; +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN +-- deletes all constraints and foreign keys referring to TABLE.COLUMN +-- +CREATE PROCEDURE usp_ebean_drop_foreign_keys(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255)) +BEGIN +DECLARE done INT DEFAULT FALSE; +DECLARE c_fk_name CHAR(255); +DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE +WHERE TABLE_SCHEMA = DATABASE() and TABLE_NAME = p_table_name and COLUMN_NAME = p_column_name +AND REFERENCED_TABLE_NAME IS NOT NULL; +DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + +OPEN curs; + +read_loop: LOOP +FETCH curs INTO c_fk_name; +IF done THEN +LEAVE read_loop; +END IF; +SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP FOREIGN KEY ', c_fk_name); +PREPARE stmt FROM @sql; +EXECUTE stmt; +END LOOP; + +CLOSE curs; +END +$$ + +DROP PROCEDURE IF EXISTS usp_ebean_drop_column; + +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN +-- deletes the column and ensures that all indices and constraints are dropped first +-- +CREATE PROCEDURE usp_ebean_drop_column(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255)) +BEGIN +CALL usp_ebean_drop_foreign_keys(p_table_name, p_column_name); +SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP COLUMN ', p_column_name); +PREPARE stmt FROM @sql; +EXECUTE stmt; +END +$$ + + +-- Inital script to create stored procedures etc for the hana platform +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN +-- deletes all constraints and foreign keys referring to TABLE.COLUMN +-- +CREATE OR REPLACE PROCEDURE usp_ebean_drop_foreign_keys(IN table_name NVARCHAR(256), IN column_name NVARCHAR(256)) +AS +BEGIN +DECLARE foreign_key_names TABLE(CONSTRAINT_NAME NVARCHAR(256), TABLE_NAME NVARCHAR(256)); +DECLARE i INT; + +foreign_key_names = SELECT CONSTRAINT_NAME, TABLE_NAME FROM SYS.REFERENTIAL_CONSTRAINTS WHERE SCHEMA_NAME=CURRENT_SCHEMA AND TABLE_NAME=UPPER(:table_name) AND COLUMN_NAME=UPPER(:column_name); + +FOR I IN 1 .. RECORD_COUNT(:foreign_key_names) DO +EXEC 'ALTER TABLE "' || ESCAPE_DOUBLE_QUOTES(:foreign_key_names.TABLE_NAME[i]) || '" DROP CONSTRAINT "' || ESCAPE_DOUBLE_QUOTES(:foreign_key_names.CONSTRAINT_NAME[i]) || '"'; +END FOR; + +END; +$$ + +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN +-- deletes the column and ensures that all indices and constraints are dropped first +-- +CREATE OR REPLACE PROCEDURE usp_ebean_drop_column(IN table_name NVARCHAR(256), IN column_name NVARCHAR(256)) +AS +BEGIN +CALL usp_ebean_drop_foreign_keys(table_name, column_name); +EXEC 'ALTER TABLE "' || UPPER(ESCAPE_DOUBLE_QUOTES(table_name)) || '" DROP ("' || UPPER(ESCAPE_DOUBLE_QUOTES(column_name)) || '")'; +END; +$$ + diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java new file mode 100644 index 000000000..cc356d1b6 --- /dev/null +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java @@ -0,0 +1,78 @@ +package io.ebeaninternal.dbmigration; + +import io.ebean.Database; +import io.ebean.DatabaseFactory; +import io.ebean.annotation.Platform; +import io.ebean.config.DatabaseConfig; +import io.ebean.config.PlatformConfig; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Class to test the alternative drop behaviour using stored procedures for MySql databases . + * + * @author Jonas Pöhler, FOCONIS AG + */ +public class MysqlGenerateMigrationTest { + + @Test + public void testMysqlStoredProcedures() throws Exception { + DefaultDbMigration migration = new DefaultDbMigration(); + migration.setIncludeIndex(true); + // We use src/test/resources as output directory (so we see in GIT if files will change) + migration.setPathToResources("src/test/resources"); + + migration.addPlatform(Platform.MYSQL, "mysql"); + + final PlatformConfig platformConfig = new PlatformConfig(); + platformConfig.setUseMigrationStoredProcedures(true); + + DatabaseConfig config = new DatabaseConfig(); + config.setName("migrationtest"); + config.loadFromProperties(); + config.setPlatformConfig(platformConfig); + config.setRegister(false); + config.setDefaultServer(false); + config.getProperties().put("ebean.migration.migrationPath", "db/migration/mysql"); + + config.setPackages(Arrays.asList("misc.migration.mysql_v1_0")); + Database server = DatabaseFactory.create(config); + migration.setServer(server); + migration.setMigrationPath("mysql/procedures"); + + // First, we clean up the output-directory + assertThat(migration.migrationDirectory().getAbsolutePath()).contains("procedures"); + Files.walk(migration.migrationDirectory().toPath()) + .filter(Files::isRegularFile) + .map(Path::toFile).forEach(File::delete); + + // then we generate migration scripts for v1_0 + assertThat(migration.generateMigration()).isEqualTo("1.0__initial"); + + config.setPackages(Arrays.asList("misc.migration.mysql_v1_1")); + server.shutdown(); + server = DatabaseFactory.create(config); + migration.setServer(server); + migration.setMigrationPath("mysql/procedures"); + assertThat(migration.generateMigration()).isEqualTo("1.1"); + + System.setProperty("ddl.migration.pendingDropsFor", "1.1"); + assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1"); + + final Path sqlFile = migration.migrationDirectory().toPath() + .resolve("mysql/1.2__dropsFor_1.1.sql"); + + assertThat(sqlFile).isNotEmptyFile(); + assertThat(Files.readAllLines(sqlFile, StandardCharsets.UTF_8)) + .contains("CALL usp_ebean_drop_column('migtest_e_basic', 'status2');") + .contains("CALL usp_ebean_drop_column('migtest_e_basic', 'description');"); + + } +} diff --git a/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_0/EBasic.java b/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_0/EBasic.java new file mode 100644 index 000000000..b11fb4a8c --- /dev/null +++ b/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_0/EBasic.java @@ -0,0 +1,89 @@ +package misc.migration.mysql_v1_0; + +import io.ebean.annotation.DbDefault; +import io.ebean.annotation.EnumValue; +import io.ebean.annotation.NotNull; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.Size; + +@Entity +@Table(name = "migtest_e_basic") +public class EBasic { + + public enum Status { + @EnumValue("N") + NEW, + + @EnumValue("A") + ACTIVE, + + @EnumValue("I") + INACTIVE, + } + + @Id + Integer id; + + Status status; + + @DbDefault("N") + @NotNull + Status status2; + + @Size(max=127) + String name; + + @Size(max=127) + String description; + + public EBasic() { + + } + + public EBasic(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Status getStatus2() { + return status2; + } + + public void setStatus2(final Status status2) { + this.status2 = status2; + } +} diff --git a/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_1/EBasic.java b/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_1/EBasic.java new file mode 100644 index 000000000..739332226 --- /dev/null +++ b/ebean-ddl-generator/src/test/java/misc/migration/mysql_v1_1/EBasic.java @@ -0,0 +1,64 @@ +package misc.migration.mysql_v1_1; + +import io.ebean.annotation.EnumValue; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.validation.constraints.Size; + +@Entity +@Table(name = "migtest_e_basic") +public class EBasic { + + public enum Status { + @EnumValue("N") + NEW, + + @EnumValue("A") + ACTIVE, + + @EnumValue("I") + INACTIVE, + } + + @Id + Integer id; + + Status status; + + @Size(max=127) + String name; + + public EBasic() { + + } + + public EBasic(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.0__initial.model.xml b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.0__initial.model.xml new file mode 100644 index 000000000..4cb2aea38 --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.0__initial.model.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.1.model.xml b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.1.model.xml new file mode 100644 index 000000000..27ec6c42a --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.1.model.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.2__dropsFor_1.1.model.xml b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.2__dropsFor_1.1.model.xml new file mode 100644 index 000000000..7b89fb0e0 --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/model/1.2__dropsFor_1.1.model.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.0__initial.sql b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.0__initial.sql new file mode 100644 index 000000000..9e44107be --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.0__initial.sql @@ -0,0 +1,11 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create table migtest_e_basic ( + id integer auto_increment not null, + status varchar(1), + status2 varchar(1) default 'N' not null, + name varchar(127), + description varchar(127), + constraint pk_migtest_e_basic primary key (id) +); + diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.2__dropsFor_1.1.sql b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.2__dropsFor_1.1.sql new file mode 100644 index 000000000..38b133086 --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/1.2__dropsFor_1.1.sql @@ -0,0 +1,6 @@ +-- Migrationscripts for ebean unittest +-- apply changes +CALL usp_ebean_drop_column('migtest_e_basic', 'status2'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'description'); + diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/I__create_procs.sql b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/I__create_procs.sql new file mode 100644 index 000000000..d13ec2708 --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/I__create_procs.sql @@ -0,0 +1,48 @@ +-- Inital script to create stored procedures etc for mysql platform +DROP PROCEDURE IF EXISTS usp_ebean_drop_foreign_keys; + +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_foreign_keys TABLE, COLUMN +-- deletes all constraints and foreign keys referring to TABLE.COLUMN +-- +CREATE PROCEDURE usp_ebean_drop_foreign_keys(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255)) +BEGIN +DECLARE done INT DEFAULT FALSE; +DECLARE c_fk_name CHAR(255); +DECLARE curs CURSOR FOR SELECT CONSTRAINT_NAME from information_schema.KEY_COLUMN_USAGE +WHERE TABLE_SCHEMA = DATABASE() and TABLE_NAME = p_table_name and COLUMN_NAME = p_column_name +AND REFERENCED_TABLE_NAME IS NOT NULL; +DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + +OPEN curs; + +read_loop: LOOP +FETCH curs INTO c_fk_name; +IF done THEN +LEAVE read_loop; +END IF; +SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP FOREIGN KEY ', c_fk_name); +PREPARE stmt FROM @sql; +EXECUTE stmt; +END LOOP; + +CLOSE curs; +END +$$ + +DROP PROCEDURE IF EXISTS usp_ebean_drop_column; + +delimiter $$ +-- +-- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN +-- deletes the column and ensures that all indices and constraints are dropped first +-- +CREATE PROCEDURE usp_ebean_drop_column(IN p_table_name VARCHAR(255), IN p_column_name VARCHAR(255)) +BEGIN +CALL usp_ebean_drop_foreign_keys(p_table_name, p_column_name); +SET @sql = CONCAT('ALTER TABLE ', p_table_name, ' DROP COLUMN ', p_column_name); +PREPARE stmt FROM @sql; +EXECUTE stmt; +END +$$ diff --git a/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/idx_mysql.migrations b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/idx_mysql.migrations new file mode 100644 index 000000000..1cb8a087c --- /dev/null +++ b/ebean-ddl-generator/src/test/resources/mysql/procedures/mysql/idx_mysql.migrations @@ -0,0 +1,4 @@ +1835064798, I__create_procs.sql +1968521526, 1.0__initial.sql +-728933533, 1.2__dropsFor_1.1.sql + From b60f9201a90c8d9e209cf355351d209502400e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20P=C3=B6hler?= Date: Fri, 26 Nov 2021 15:57:03 +0100 Subject: [PATCH 02/47] FIX: MysqlGenerateMigrationTest now clears pendingDrops System-Property --- .../dbmigration/MysqlGenerateMigrationTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java index cc356d1b6..2601582f0 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/MysqlGenerateMigrationTest.java @@ -5,6 +5,8 @@ import io.ebean.DatabaseFactory; import io.ebean.annotation.Platform; import io.ebean.config.DatabaseConfig; import io.ebean.config.PlatformConfig; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.io.File; @@ -22,6 +24,11 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class MysqlGenerateMigrationTest { + @AfterEach + public void resetPendingDropsProperty() { + System.clearProperty("ddl.migration.pendingDropsFor"); + } + @Test public void testMysqlStoredProcedures() throws Exception { DefaultDbMigration migration = new DefaultDbMigration(); From 860aad11ce59adb80162509bb62ccc7d416dc7c4 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 17 Dec 2021 23:22:25 +1300 Subject: [PATCH 03/47] WIP h2database v2 --- ebean-api/pom.xml | 2 +- .../java/io/ebean/config/dbplatform/h2/H2Platform.java | 1 + .../ebean/config/dbplatform/h2/H2SequenceIdGenerator.java | 3 +-- ebean-core/pom.xml | 2 +- .../ebeaninternal/server/deploy/parse/DeployInherit.java | 8 ++++++-- .../ebeaninternal/server/type/ScalarTypeEnumStandard.java | 7 ++++++- .../dbmigration/ddlgeneration/platform/H2Ddl.java | 8 +++++++- .../dbmigration/ddlgeneration/BaseDdlHandlerTest.java | 4 ++-- .../platform/PlatformDdl_AlterColumnTest.java | 8 ++++---- .../ddlgeneration/platform/PlatformTypeConverterTest.java | 2 +- ebean-test/pom.xml | 6 +++--- .../org/tests/inheritance/abstrakt/AbstractBaseBlock.java | 2 +- ebean-test/src/test/resources/ebean.properties | 2 +- pom.xml | 4 ++-- 14 files changed, 37 insertions(+), 22 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index a27749023..b681c1a70 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -85,7 +85,7 @@ com.h2database h2 - 1.4.199 + 2.0.202 true diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java index cdc923824..4f81f4eb2 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java @@ -39,6 +39,7 @@ public class H2Platform extends DatabasePlatform { this.dbIdentity.setSupportsIdentity(true); dbTypeMap.put(DbType.UUID, new DbPlatformType("uuid", false)); + dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false)); } /** diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java index b4e875511..5ef08c059 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java @@ -18,13 +18,12 @@ public class H2SequenceIdGenerator extends SequenceBatchIdGenerator { */ public H2SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { super(be, ds, seqName, batchSize); - this.baseSql = "select " + seqName + ".nextval"; + this.baseSql = "select nextval('" + seqName + "')"; this.unionBaseSql = " union " + baseSql; } @Override public String getSql(int batchSize) { - StringBuilder sb = new StringBuilder(); sb.append(baseSql); for (int i = 1; i < batchSize; i++) { diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 08752f040..af55c2c6a 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -78,7 +78,7 @@ com.h2database h2 - 1.4.199 + 2.0.202 provided diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java index 2dd13f993..4eb2fa640 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java @@ -6,6 +6,7 @@ import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; import javax.persistence.Inheritance; import java.util.LinkedHashMap; @@ -105,8 +106,11 @@ public final class DeployInherit { if (da != null) { // lowercase the discriminator column for RawSql and JSON info.setColumnName(da.name().toLowerCase()); - info.setColumnType(da.discriminatorType()); - info.setColumnLength(da.length()); + DiscriminatorType discriminatorType = da.discriminatorType(); + info.setColumnType(discriminatorType); + if (discriminatorType == DiscriminatorType.STRING) { + info.setColumnLength(da.length()); + } info.setColumnDefn(da.columnDefinition()); } if (!info.isAbstract()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java index 8545bc9a7..969bfd016 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -189,7 +189,12 @@ final class ScalarTypeEnumStandard { if (dbValue == null || dbValue instanceof Enum) { return dbValue; } - int ordinal = (Integer) dbValue; + int ordinal; + if (dbValue instanceof Integer) { + ordinal = (Integer) dbValue; + } else { + ordinal = Integer.parseInt(dbValue.toString()); + } if (ordinal < 0 || ordinal >= enumArray.length) { String m = "Unexpected ordinal [" + ordinal + "] out of range [" + enumArray.length + "]"; throw new IllegalStateException(m); 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 13298faeb..542bc695a 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 @@ -22,6 +22,12 @@ public class H2Ddl extends PlatformDdl { @Override protected String convertArrayType(String logicalArrayType) { - return "array"; + int pos = logicalArrayType.indexOf('['); + if (pos == -1) { + return logicalArrayType; + } else { + // trim of the fallback varchar length + return logicalArrayType.substring(0, pos) + " array"; + } } } 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 8de6ac22b..87c48bb85 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 @@ -107,7 +107,7 @@ 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 array;\n\n"); + 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 +127,7 @@ 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 array;\n\n"); + 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 5da1a25a8..3141eef74 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 @@ -57,10 +57,10 @@ public class PlatformDdl_AlterColumnTest { @Test public void convertArrayType_h2() { - 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"); + 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-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformTypeConverterTest.java b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformTypeConverterTest.java index 45dbd60b6..25a4621d5 100644 --- a/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformTypeConverterTest.java +++ b/ebean-ddl-generator/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformTypeConverterTest.java @@ -61,7 +61,7 @@ public class PlatformTypeConverterTest { assertThat(converter.convert("clob")).isEqualTo("clob"); assertThat(converter.convert("blob")).isEqualTo("blob"); assertThat(converter.convert("tinyint")).isEqualTo("tinyint"); - assertThat(converter.convert("integer(8)")).isEqualTo("integer(8)"); + assertThat(converter.convert("integer(8)")).isEqualTo("integer"); assertThat(converter.convert("funky")).isEqualTo("funky"); // unknown } diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index c91ff68b9..f0fb26900 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -16,7 +16,7 @@ org.slf4j slf4j-api - 1.7.30 + 1.7.32 provided @@ -187,8 +187,8 @@ com.oracle.database.jdbc - ojdbc8 19.12.0.0 diff --git a/ebean-test/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java b/ebean-test/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java index c4c3d0202..ecd0c2e39 100644 --- a/ebean-test/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java +++ b/ebean-test/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java @@ -3,7 +3,7 @@ package org.tests.inheritance.abstrakt; import javax.persistence.*; @Entity -@Table(name = "block") +@Table(name = "blockt") @Inheritance @DiscriminatorColumn(name = "case_type", discriminatorType = DiscriminatorType.INTEGER) public abstract class AbstractBaseBlock { 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/pom.xml b/pom.xml index 1b48a5474..fc3905d89 100644 --- a/pom.xml +++ b/pom.xml @@ -61,14 +61,14 @@ ch.qos.logback logback-classic - 1.2.3 + 1.2.8 test com.h2database h2 - 1.4.199 + 2.0.202 test From 356dc5eb19cc1da60cd59925bc521315d8c67bf8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 13 Jan 2022 15:02:38 +1300 Subject: [PATCH 04/47] #2487 - ebean-test support Docker In Docker - docker container's hostname rather than hardcoded "localhost" --- .../test/config/platform/ClickHouseSetup.java | 2 +- .../test/config/platform/CockroachSetup.java | 2 +- .../io/ebean/test/config/platform/Config.java | 22 +++++++++++++++++-- .../ebean/test/config/platform/Db2Setup.java | 2 +- .../ebean/test/config/platform/HanaSetup.java | 2 +- .../test/config/platform/MariaDBSetup.java | 2 +- .../test/config/platform/MySqlSetup.java | 2 +- .../test/config/platform/PostgisSetup.java | 2 +- .../test/config/platform/PostgresSetup.java | 4 ++-- .../test/config/platform/SqlServerSetup.java | 2 +- 10 files changed, 30 insertions(+), 12 deletions(-) diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java index 4dcb472b4..a2a6ca0e0 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java @@ -11,7 +11,7 @@ class ClickHouseSetup implements PlatformSetup { config.setDefaultPort(8123); config.setUsername("default"); config.setPassword(""); - config.setUrl("jdbc:clickhouse://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:clickhouse://${host}:${port}/${databaseName}"); config.setDriver("ru.yandex.clickhouse.ClickHouseDriver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java index 879f895ee..b68ca912e 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java @@ -11,7 +11,7 @@ class CockroachSetup implements PlatformSetup { config.setDefaultPort(26257); config.setUsername("root"); config.setPassword(""); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}?sslmode=disable"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}?sslmode=disable"); config.setDriver("org.postgresql.Driver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java index cefae4ce4..7fdd44a07 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java @@ -4,8 +4,8 @@ import io.ebean.config.DatabaseConfig; import io.ebean.datasource.DataSourceConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.io.File; +import java.util.Locale; import java.util.Properties; /** @@ -26,7 +26,6 @@ class Config { private final String db; private final String platform; private String dockerPlatform; - private String databaseName; private final Properties properties; @@ -231,11 +230,30 @@ class Config { void setUrl(String urlPattern) { String val = getPlatformKey("url", urlPattern); + val = val.replace("${host}", host()); val = val.replace("${port}", String.valueOf(port)); val = val.replace("${databaseName}", databaseName); this.url = val; } + String host() { + String defaultHost = isInDocker() ? dockerHost() : "localhost"; + return getPlatformKey("host", defaultHost); + } + + static String dockerHost() { + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { + return "host.docker.internal"; + } else { + return "172.17.0.1"; + } + } + + boolean isInDocker() { + return new File("/.dockerenv").exists(); + } + /** * Append to the connection URL. */ diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java index fd65472ef..70fa4fc2c 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java @@ -11,7 +11,7 @@ class Db2Setup implements PlatformSetup { config.setDefaultPort(50000); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:db2://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:db2://${host}:${port}/${databaseName}"); config.setDriver("com.ibm.db2.jcc.DB2Driver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java index 8ad014b70..a5137686f 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java @@ -20,7 +20,7 @@ class HanaSetup implements PlatformSetup { config.setUsername("SYSTEM"); config.setPassword("HXEHana1"); config.setDatabaseName("HXE"); - config.setUrl("jdbc:sap://localhost:${port}/?databaseName=${databaseName}"); + config.setUrl("jdbc:sap://${host}:${port}/?databaseName=${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { config.urlAppend("¤tSchema=" + schema); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java index 4e242d4b0..f2ff22cc4 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java @@ -13,7 +13,7 @@ class MariaDBSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:mariadb://localhost:${port}/${databaseName}?useLegacyDatetimeCode=false"); + config.setUrl("jdbc:mariadb://${host}:${port}/${databaseName}?useLegacyDatetimeCode=false"); config.datasourceDefaults(); return dockerProperties(config); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java index 3939ffbec..c865c41b7 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java @@ -13,7 +13,7 @@ class MySqlSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:mysql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:mysql://${host}:${port}/${databaseName}"); config.setDriver(defaultDriver()); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java index 8180dc425..bd5a38387 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java @@ -20,7 +20,7 @@ class PostgisSetup implements PlatformSetup { config.setUsernameDefault(); config.setPasswordDefault(); config.setDriver("org.postgis.DriverWrapperLW"); - config.setUrl("jdbc:postgresql_lwgis://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql_lwgis://${host}:${port}/${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { 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 8e9045408..e5d1206f7 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 @@ -13,7 +13,7 @@ class PostgresSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { @@ -44,7 +44,7 @@ class PostgresSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setExtraUsernameDefault(); config.setExtraDbPasswordDefault(); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); config.setDriver("org.postgresql.Driver"); config.extraDatasourceDefaults(); } diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java index 09b76323e..3428fb43e 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java @@ -13,7 +13,7 @@ class SqlServerSetup implements PlatformSetup { config.setDefaultPort(1433); config.setUsernameDefault(); config.setPassword("SqlS3rv#r"); - config.setUrl("jdbc:sqlserver://localhost:${port};databaseName=${databaseName};sendTimeAsDateTime=false"); + config.setUrl("jdbc:sqlserver://${host}:${port};databaseName=${databaseName};sendTimeAsDateTime=false"); config.setDriver("com.microsoft.sqlserver.jdbc.SQLServerDriver"); config.datasourceDefaults(); From 38bc5b2fea13a841f4ce5eb2650d3b7be1444059 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 14 Jan 2022 16:27:04 +1300 Subject: [PATCH 05/47] #2488 - refactor extract logic into DockerHost helper, fix RedisSetup, pass docker host to ebean-test-docker --- ebean-test/pom.xml | 2 +- .../io/ebean/test/config/platform/Config.java | 28 ++---- .../test/config/platform/DockerHost.java | 55 ++++++++++++ .../test/config/platform/RedisSetup.java | 6 +- .../test/config/platform/DockerHostTest.java | 87 +++++++++++++++++++ 5 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java create mode 100644 ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 4a2cdf3be..17041e36c 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -56,7 +56,7 @@ io.ebean ebean-test-docker - 4.3 + 4.4 diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java index 7fdd44a07..117c04a18 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java @@ -29,7 +29,6 @@ class Config { private String databaseName; private final Properties properties; - private int port; private String url; @@ -37,12 +36,10 @@ class Config { private String schema; private String username; private String password; - private final DatabaseConfig config; - private boolean containerDropCreate; - private final Properties dockerProperties = new Properties(); + private final DockerHost dockerHost = new DockerHost(); Config(String db, String platform, String databaseName, DatabaseConfig config) { this.db = db; @@ -237,21 +234,8 @@ class Config { } String host() { - String defaultHost = isInDocker() ? dockerHost() : "localhost"; - return getPlatformKey("host", defaultHost); - } - - static String dockerHost() { - String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); - if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { - return "host.docker.internal"; - } else { - return "172.17.0.1"; - } - } - - boolean isInDocker() { - return new File("/.dockerenv").exists(); + String explicitDockerHost = getKey("dockerHost", null); + return getKey("host", dockerHost.dockerHost(explicitDockerHost)); } /** @@ -340,7 +324,6 @@ class Config { void setDockerVersion(String version) { String val = getPlatformKey("version", version); dockerProperties.setProperty(dockerKey("version"), val); - if (containerDropCreate) { dockerProperties.setProperty(dockerKey("startMode"), "dropCreate"); } @@ -387,7 +370,10 @@ class Config { } private void initDockerProperties() { - + if (dockerHost.runningInDocker()) { + // tell ebean-docker-test we are not using localhost (for jdbc DB setup commands) + dockerProperties.setProperty(dockerKey("host"), dockerHost.dockerHost()); + } dockerProperties.setProperty(dockerKey("port"), String.valueOf(port)); dockerProperties.setProperty(dockerKey("dbName"), databaseName); if (schema != null) { diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java b/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java new file mode 100644 index 000000000..5e3f0ce94 --- /dev/null +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java @@ -0,0 +1,55 @@ +package io.ebean.test.config.platform; + +import java.io.File; +import java.util.Locale; + +/** + * Helper to detect if running inside docker and determine host name for that case. + */ +class DockerHost { + + private final boolean runningInDocker; + private String dockerHost; + + DockerHost() { + runningInDocker = initInDocker(); + } + + boolean runningInDocker() { + return runningInDocker; + } + + String dockerHost() { + return dockerHost; + } + + String dockerHost(String explicitHost) { + if (!runningInDocker) { + return "localhost"; + } + dockerHost = explicitHost != null ? explicitHost : defaultDockerHost(); + return dockerHost; + } + + /** + * Return true if running inside a docker container (we are using docker in docker). + */ + boolean initInDocker() { + return new File("/.dockerenv").exists(); + } + + /** + * Return the default host name to use when running in docker. + *

+ * Can instead be explicitly specified via ebean.test.dockerHost. + */ + String defaultDockerHost() { + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { + return "host.docker.internal"; + } else { + return "172.17.0.1"; + } + } + +} diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java index 70580bd81..c8fc01671 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java @@ -8,10 +8,14 @@ import java.util.Properties; class RedisSetup { static void run(Properties properties) { - String version = properties.getProperty("ebean.test.redis"); version = properties.getProperty("ebean.test.redis.version", version); if (version != null) { + DockerHost dockerHost = new DockerHost(); + if (dockerHost.runningInDocker()) { + String host = dockerHost.dockerHost(properties.getProperty("ebean.test.dockerHost")); + properties.setProperty("redis.host", host); + } RedisConfig redisConfig = new RedisConfig(version, properties); RedisContainer container = new RedisContainer(redisConfig); container.start(); diff --git a/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java b/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java new file mode 100644 index 000000000..0be8a5d43 --- /dev/null +++ b/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java @@ -0,0 +1,87 @@ +package io.ebean.test.config.platform; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DockerHostTest { + + @Test + void runningInDocker_when_false_alwaysUseLocalhost() { + DockerHost dockerHost = new DockerHost(); + assertFalse(dockerHost.runningInDocker()); + assertEquals("localhost", dockerHost.dockerHost("foo")); + } + + @Test + void runningInDocker_when_true_useExplicit() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + assertEquals("my-host", dockerHost.dockerHost("my-host")); + } + + @Disabled + @Test + void runningInDocker_when_trueAndLinux_useDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + assertEquals("172.17.0.1", dockerHost.dockerHost(null)); + } + + @Test + void runningInDocker_when_windowsDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "win"); + try { + assertEquals("host.docker.internal",dockerHost.defaultDockerHost()); + assertEquals("host.docker.internal", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + @Test + void runningInDocker_when_macDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "mac"); + try { + assertEquals("host.docker.internal",dockerHost.defaultDockerHost()); + assertEquals("host.docker.internal", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + + @Test + void runningInDocker_when_linuxDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "linux"); + try { + assertEquals("172.17.0.1",dockerHost.defaultDockerHost()); + assertEquals("172.17.0.1", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + static class TDDockerHost extends DockerHost { + + @Override + boolean initInDocker() { + return true; + } + } +} From 1c83bbe0b09683e0a9a07a99b0b573b604c2b522 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 15:33:13 +1300 Subject: [PATCH 06/47] #2476 - Failing test for element collection on bean with default constructor --- .../model/elementcollection/EcblPerson2.java | 61 +++++++++++ ...stElementCollectionEmbeddedListCache2.java | 100 ++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 ebean-test/src/test/java/org/tests/model/elementcollection/EcblPerson2.java create mode 100644 ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java diff --git a/ebean-test/src/test/java/org/tests/model/elementcollection/EcblPerson2.java b/ebean-test/src/test/java/org/tests/model/elementcollection/EcblPerson2.java new file mode 100644 index 000000000..7ce82c393 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/EcblPerson2.java @@ -0,0 +1,61 @@ +package org.tests.model.elementcollection; + +import io.ebean.annotation.Cache; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Cache +@Entity +public class EcblPerson2 { + + @Id + long id; + + String name; + + @ElementCollection + @CollectionTable(joinColumns = @JoinColumn(name = "person_id")) + List phoneNumbers = new ArrayList<>(); + + @Version + long version; + + @Override + public String toString() { + return "person id:" + id + " name:" + name + " phs:" + phoneNumbers; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(List phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} 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 new file mode 100644 index 000000000..ad2531e20 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache2.java @@ -0,0 +1,100 @@ +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; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { + + @Disabled + @Test + public void test() { + + EcblPerson2 person = new EcblPerson2(); + person.setName("CacheL"); + 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) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + LoggedSql.start(); + + one.getPhoneNumbers().size(); + + List sql = LoggedSql.collect(); + assertThat(sql).isEmpty(); + + EcblPerson2 two = DB.find(EcblPerson2.class ) + .setId(person.getId()) + .findOne(); + + two.getPhoneNumbers().size(); + assertThat(two.getPhoneNumbers().toString()).contains("64-021-1234", "64-021-4321"); + + sql = LoggedSql.collect(); + assertThat(sql).isEmpty(); // cache hit + + two.getPhoneNumbers().add(new EcPhone("61", "07", "11")); + two.getPhoneNumbers().remove(1); + + DB.save(two); + + sql = LoggedSql.collect(); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(5); // update of collection only + assertSql(sql.get(0)).contains("delete from ecbl_person2_phone_numbers where person_id=?"); + assertSqlBind(sql.get(1)); + assertSql(sql.get(2)).contains("insert into ecbl_person2_phone_numbers (person_id,country_code,area,phnum) values (?,?,?,?)"); + assertSqlBind(sql, 3, 4); + } else { + assertThat(sql).hasSize(3); // update of collection only + assertSql(sql.get(0)).contains("delete from ecbl_person2_phone_numbers where person_id=?"); + assertSql(sql.get(1)).contains("insert into ecbl_person2_phone_numbers (person_id,country_code,area,phnum) values (?,?,?,?)"); + assertSql(sql.get(2)).contains("insert into ecbl_person2_phone_numbers (person_id,country_code,area,phnum) values (?,?,?,?)"); + } + + 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); + + sql = LoggedSql.collect(); + assertThat(sql).isEmpty(); // cache hit + + + three.setName("mod-3"); + three.getPhoneNumbers().remove(0); + + DB.save(three); + + sql = LoggedSql.collect(); + assertThat(sql).hasSize(5); + + 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(); + } +} From 82862deccc46b835bd90bfed1b7988c03f05488d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 15:36:26 +1300 Subject: [PATCH 07/47] #2476 - Fix for element collection on bean with default constructor Note that we can look for a better longer term fix which might would look at treating element collection more like ToMany collections in terms of enhancement. --- .../server/deploy/BeanPropertyAssocMany.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 73765d43d..09851725f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -226,7 +226,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST */ @Override public void addBeanToCollectionWithCreate(EntityBean parentBean, EntityBean detailBean, boolean withCheck) { - BeanCollection bc = (BeanCollection) super.getValue(parentBean); + BeanCollection bc = beanCollection(parentBean); if (bc == null) { bc = help.createEmpty(parentBean); setValue(parentBean, bc); @@ -234,6 +234,15 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST help.add(bc, detailBean, withCheck); } + private BeanCollection beanCollection(EntityBean parentBean) { + try { + return (BeanCollection) super.getValue(parentBean); + } catch (ClassCastException e) { + // fetching element collection, ok for now + return null; + } + } + /** * Return true if this is considered 'empty' from a save perspective. */ From 9b116c9bf69693b322a9dea3fe59c96dab4e9f6e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 15:38:41 +1300 Subject: [PATCH 08/47] #2476 - tidy tests --- .../TestElementCollectionEmbeddedListCache.java | 6 ++---- .../TestElementCollectionEmbeddedListCache2.java | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) 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 f3ec4b24b..80e2d9bd1 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 @@ -9,10 +9,10 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -public class TestElementCollectionEmbeddedListCache extends BaseTestCase { +class TestElementCollectionEmbeddedListCache extends BaseTestCase { @Test - public void test() { + void test() { EcblPerson person = new EcblPerson("CacheL"); person.getPhoneNumbers().add(new EcPhone("64", "021","1234")); @@ -86,12 +86,10 @@ public class TestElementCollectionEmbeddedListCache extends BaseTestCase { 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(); } } 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 ad2531e20..1a361c33b 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 @@ -10,11 +10,10 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -public class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { +class TestElementCollectionEmbeddedListCache2 extends BaseTestCase { - @Disabled @Test - public void test() { + void test() { EcblPerson2 person = new EcblPerson2(); person.setName("CacheL"); From e65876e8edb6b9560b5008161e1e9501fafe6dcb Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 20:58:19 +1300 Subject: [PATCH 09/47] #2477 - Add failing test case (disable for the moment) --- .../tests/model/embedded/EmbArrayMaster.java | 31 +++++++++++++++++++ .../model/embedded/TestEmbeddedDbArray.java | 21 +++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 ebean-test/src/test/java/org/tests/model/embedded/EmbArrayMaster.java create mode 100644 ebean-test/src/test/java/org/tests/model/embedded/TestEmbeddedDbArray.java diff --git a/ebean-test/src/test/java/org/tests/model/embedded/EmbArrayMaster.java b/ebean-test/src/test/java/org/tests/model/embedded/EmbArrayMaster.java new file mode 100644 index 000000000..09ff8312f --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/embedded/EmbArrayMaster.java @@ -0,0 +1,31 @@ +package org.tests.model.embedded; + +import io.ebean.annotation.DbArray; + +import javax.persistence.*; +import java.util.List; + +@Entity +public class EmbArrayMaster { + + @Embeddable + public static class EmbArrayDetail { + @DbArray + List vals; + + public EmbArrayDetail(List vals) { + this.vals = vals; + } + } + + @Id + int id; + + @ElementCollection + @CollectionTable(name = "test_array_detail", joinColumns = {@JoinColumn(name = "master_id")}) + List details; + + public EmbArrayMaster(List details) { + this.details = details; + } +} diff --git a/ebean-test/src/test/java/org/tests/model/embedded/TestEmbeddedDbArray.java b/ebean-test/src/test/java/org/tests/model/embedded/TestEmbeddedDbArray.java new file mode 100644 index 000000000..6bf121032 --- /dev/null +++ b/ebean-test/src/test/java/org/tests/model/embedded/TestEmbeddedDbArray.java @@ -0,0 +1,21 @@ +package org.tests.model.embedded; + +import io.ebean.DB; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +class TestEmbeddedDbArray { + + /** + * Failing test case for #2477 + */ + @Disabled + @Test + void testArrayInsert() { + EmbArrayMaster t = new EmbArrayMaster(singletonList(new EmbArrayMaster.EmbArrayDetail(emptyList()))); + DB.insert(t); + } +} From ec45fc1c86814e9e37e17a5addad91289a3ab220 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:26:19 +1300 Subject: [PATCH 10/47] Fix tests for Oracle - BITADD in @Where clause expression --- ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java b/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java index edbd87cc0..fabb58040 100644 --- a/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java +++ b/ebean-test/src/test/java/org/tests/model/m2m/MnyNode.java @@ -33,7 +33,7 @@ public class MnyNode { joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id")) @Where(clause = "${mta}.flags & 1 != 0") - @Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = Platform.H2) + @Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = {Platform.H2, Platform.ORACLE}) List bit1Relations; @ManyToMany @@ -41,7 +41,7 @@ public class MnyNode { joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id")) @Where(clause = "${mta}.flags & 1 != 0") - @Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = Platform.H2) + @Where(clause = "BITAND(${mta}.flags, 1) != 0", platforms = {Platform.H2, Platform.ORACLE}) List bit1ReverseRelations; @ManyToMany @@ -49,7 +49,7 @@ public class MnyNode { joinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id")) @Where(clause = "${mta}.flags & 2 != 0") - @Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = Platform.H2) + @Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = {Platform.H2, Platform.ORACLE}) List bit2Relations; @ManyToMany @@ -57,7 +57,7 @@ public class MnyNode { joinColumns = @JoinColumn(name = "to_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "from_id", referencedColumnName = "id")) @Where(clause = "${mta}.flags & 2 != 0") - @Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = Platform.H2) + @Where(clause = "BITAND(${mta}.flags, 2) != 0", platforms = {Platform.H2, Platform.ORACLE}) List bit2ReverseRelations; @ManyToMany From b57733152451538939db6ac1635b6ceb3d3a92e1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:27:42 +1300 Subject: [PATCH 11/47] #2492 - Fix for Oracle platform when insert only default values --- .../server/persist/dml/InsertMeta.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) 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 64b7d6f3a..2ebba4d05 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 @@ -13,11 +13,8 @@ import io.ebeaninternal.server.persist.dmlbind.BindableList; import java.sql.SQLException; -import static io.ebean.annotation.Platform.MARIADB; -import static io.ebean.annotation.Platform.MYSQL; - /** - * Meta data for insert handler. The meta data is for a particular bean type. It + * Metadata for insert handler. The metadata is for a particular bean type. It * is considered immutable and is thread safe. */ final class InsertMeta { @@ -153,31 +150,25 @@ final class InsertMeta { private String genSql(boolean nullId, String table, boolean draftTable) { GenerateDmlRequest request = new GenerateDmlRequest(); request.setInsertSetMode(); - request.append("insert into ").append(table); if (nullId && noColumnsForInsert(draftTable)) { return request.append(defaultValues()).toString(); } - request.append(" ("); if (!nullId) { id.dmlAppend(request); } - if (shadowFKey != null) { shadowFKey.dmlAppend(request); } - if (discriminator != null) { discriminator.dmlAppend(request); } - if (draftTable) { all.dmlAppend(request); } else { allExcludeDraftOnly.dmlAppend(request); } - request.append(") values ("); request.append(request.getInsertBindBuffer()); request.append(")"); @@ -185,7 +176,14 @@ final class InsertMeta { } private String defaultValues() { - return platform.base() == MYSQL || platform.base() == MARIADB ? " values (default)" : " default values"; + switch (platform.base()) { + case MYSQL: + case MARIADB: + case ORACLE: + return " values (default)"; + default: + return " default values"; + } } /** From 88ab852855cb96092eaaae478e257385331e43d6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:28:45 +1300 Subject: [PATCH 12/47] No real change, tidy DbExpressionHandlerFactory only --- .../expression/platform/DbExpressionHandlerFactory.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 6f773b270..c555e33c5 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 @@ -10,23 +10,18 @@ public final class DbExpressionHandlerFactory { * Create and return the appropriate platform specific handing of expressions. */ public static DbExpressionHandler from(DatabasePlatform databasePlatform) { - Platform platform = databasePlatform.getPlatform(); + Platform platform = databasePlatform.getPlatform().base(); switch (platform) { case H2: return new H2DbExpression(); case POSTGRES: - case POSTGRES9: return new PostgresDbExpression(); case MARIADB: return new MariaDbExpression(); - case MYSQL55: case MYSQL: return new MySqlDbExpression(); case ORACLE: - case ORACLE11: return new OracleDbExpression(); - case SQLSERVER16: - case SQLSERVER17: case SQLSERVER: return new SqlServerDbExpression(); case HANA: From 874c2f5231c2242aa78d5445c827591775e2b6c7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:42:09 +1300 Subject: [PATCH 13/47] #2492 - Fix for Oracle platform when insert only default values --- .../src/test/java/org/tests/defaultvalues/TestDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 828fc2b35..170584d5b 100644 --- a/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java +++ b/ebean-test/src/test/java/org/tests/defaultvalues/TestDefaults.java @@ -26,7 +26,7 @@ public class TestDefaults extends BaseTestCase { final List current = LoggedSql.collect(); assertThat(current).isNotEmpty(); - if (isMySql() || isMariaDB()) { + if (isMySql() || isMariaDB() || isOracle()) { assertThat(current.get(0)).contains("insert into defaults_model_draft values (default);"); } else if (isSqlServer()) { assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (?)"); From 1165d857d8af3b4fdf6ae8ce19634817ba543ca5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:57:14 +1300 Subject: [PATCH 14/47] Fix test ParentQueryTest --- .../java/org/tests/rawsql/inherit/ParentQueryTest.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/rawsql/inherit/ParentQueryTest.java b/ebean-test/src/test/java/org/tests/rawsql/inherit/ParentQueryTest.java index b3e879e71..5e45b8130 100644 --- a/ebean-test/src/test/java/org/tests/rawsql/inherit/ParentQueryTest.java +++ b/ebean-test/src/test/java/org/tests/rawsql/inherit/ParentQueryTest.java @@ -12,14 +12,12 @@ import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -public class ParentQueryTest extends BaseTestCase { +class ParentQueryTest extends BaseTestCase { @Test - public void QueryParentCollectionFetch() { - + void queryParentCollectionFetch() { List exampleData = new ArrayList<>(); exampleData.add(new Data(0)); exampleData.add(new Data(1)); @@ -40,7 +38,7 @@ public class ParentQueryTest extends BaseTestCase { List partial = DB.find(Parent.class).where().ge("val", 1001).findList(); assertNotNull(partial.get(0).getData()); assertThat(partial.get(0).getMore()).startsWith("PQT-"); - assertEquals(partial.get(0).getData().get(0).getVal().intValue(), 0); + assertThat(partial.get(0).getData()).hasSize(3); } } From 6eb8eb0dd2fd69d836d53d21f2249660a1808ef6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 21:58:33 +1300 Subject: [PATCH 15/47] #2473 Tidy BasicSqlAnsiLimiter only, no functional change --- .../java/io/ebean/config/dbplatform/BasicSqlAnsiLimiter.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/BasicSqlAnsiLimiter.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/BasicSqlAnsiLimiter.java index 378f029fb..968d16a3f 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/BasicSqlAnsiLimiter.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/BasicSqlAnsiLimiter.java @@ -7,13 +7,10 @@ public class BasicSqlAnsiLimiter implements BasicSqlLimiter { @Override public String limit(String dbSql, int firstRow, int maxRows) { - StringBuilder sb = new StringBuilder(50 + dbSql.length()); - sb.append(dbSql); if (firstRow > 0) { - sb.append(" ").append("offset"); - sb.append(" ").append(firstRow).append(" rows"); + sb.append(" offset ").append(firstRow).append(" rows"); } if (maxRows > 0) { sb.append(" fetch next ").append(maxRows).append(" rows only"); From 38f1967e608032ce47701025f466ae31530456b3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 22:10:21 +1300 Subject: [PATCH 16/47] #2473 - Oracle - column alias - Change such that OraclePlatform doesn't use column alias So with #2254 we regressed OraclePlatform to use column alias. This really should have introduced an Oracle12 platform instead. 18c onwards and we don't want the column alias. --- .../dbplatform/oracle/Oracle11Platform.java | 1 + .../dbplatform/oracle/Oracle12Platform.java | 13 ++++++++++++ .../dbplatform/oracle/OraclePlatform.java | 1 - .../server/core/DatabasePlatformFactory.java | 18 ++++++++++------ .../config/dbplatform/OraclePlatformTest.java | 21 ++++++++++++------- 5 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle12Platform.java diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java index 5934b6dd4..cb32a7470 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle11Platform.java @@ -11,6 +11,7 @@ public class Oracle11Platform extends OraclePlatform { public Oracle11Platform() { super(); this.platform = Platform.ORACLE11; + this.columnAliasPrefix = "c"; this.sqlLimiter = new OracleRownumSqlLimiter(); this.basicSqlLimiter = new OracleRownumBasicLimiter(); dbIdentity.setIdType(IdType.SEQUENCE); diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle12Platform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle12Platform.java new file mode 100644 index 000000000..479c5f229 --- /dev/null +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/Oracle12Platform.java @@ -0,0 +1,13 @@ +package io.ebean.config.dbplatform.oracle; + +/** + * Oracle 12 platform using column alias. + */ +public class Oracle12Platform extends OraclePlatform { + + public Oracle12Platform() { + super(); + //this.platform = Platform.ORACLE12; + this.columnAliasPrefix = "c"; + } +} diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java index d6896ad3e..c12ca8c74 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java @@ -22,7 +22,6 @@ public class OraclePlatform extends DatabasePlatform { public OraclePlatform() { super(); this.platform = Platform.ORACLE; - this.columnAliasPrefix = "c"; this.supportsDeleteTableAlias = true; this.maxTableNameLength = 30; this.maxConstraintNameLength = 30; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index dcfca1310..96600609a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -13,6 +13,7 @@ import io.ebean.config.dbplatform.mysql.MySql55Platform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.nuodb.NuoDbPlatform; import io.ebean.config.dbplatform.oracle.Oracle11Platform; +import io.ebean.config.dbplatform.oracle.Oracle12Platform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.Postgres9Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; @@ -25,11 +26,7 @@ import io.ebeaninternal.api.DbOffline; import javax.persistence.PersistenceException; import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.sql.*; /** * Create a DatabasePlatform from the configuration. @@ -87,6 +84,9 @@ public class DatabasePlatformFactory { if (dbName.equals("oracle11") || dbName.equals("oracle10") || dbName.equals("oracle9")) { return new Oracle11Platform(); } + if (dbName.equals("oracle12")) { + return new Oracle12Platform(); + } if (dbName.equals("oracle")) { return new OraclePlatform(); } @@ -173,7 +173,13 @@ public class DatabasePlatformFactory { } private DatabasePlatform oracleVersion(int majorVersion) { - return majorVersion < 12 ? new Oracle11Platform() : new OraclePlatform(); + if (majorVersion < 12) { + return new Oracle11Platform(); + } + if (majorVersion < 13) { + return new Oracle12Platform(); + } + return new OraclePlatform(); } private DatabasePlatform mysqlVersion(int majorVersion, int minorVersion) { diff --git a/ebean-test/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java b/ebean-test/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java index cf6b513ee..47d8fa0dd 100644 --- a/ebean-test/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java +++ b/ebean-test/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java @@ -2,28 +2,34 @@ package io.ebean.config.dbplatform; import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.oracle.Oracle11Platform; +import io.ebean.config.dbplatform.oracle.Oracle12Platform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -public class OraclePlatformTest { +class OraclePlatformTest { @Test - public void columnAliasPrefix_Oracle11Platform() { + void columnAliasPrefix_Oracle11Platform() { Oracle11Platform platform11 = new Oracle11Platform(); assertThat(platform11.columnAliasPrefix).isEqualTo("c"); } @Test - public void columnAliasPrefix_OraclePlatform() { - OraclePlatform platform = new OraclePlatform(); - assertThat(platform.columnAliasPrefix).isEqualTo("c"); + void columnAliasPrefix_Oracle12Platform() { + Oracle12Platform platform12 = new Oracle12Platform(); + assertThat(platform12.columnAliasPrefix).isEqualTo("c"); } @Test - public void uuid_default() { + void columnAliasPrefix_OraclePlatform() { + OraclePlatform platform = new OraclePlatform(); + assertThat(platform.columnAliasPrefix).isNull(); + } + @Test + void uuid_default() { OraclePlatform platform = new OraclePlatform(); platform.configure(new PlatformConfig(), false); DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); @@ -31,8 +37,7 @@ public class OraclePlatformTest { } @Test - public void uuid_as_binary() { - + void uuid_as_binary() { OraclePlatform platform = new OraclePlatform(); PlatformConfig config = new PlatformConfig(); config.setDbUuid(PlatformConfig.DbUuid.AUTO_BINARY); From 263f6cdeba51a0305d4eddc78f74d3d71aa8dae1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 22:10:53 +1300 Subject: [PATCH 17/47] Tidy OraclePlatform only --- .../io/ebean/config/dbplatform/oracle/OraclePlatform.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java index c12ca8c74..e9dd57207 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java @@ -34,11 +34,9 @@ public class OraclePlatform extends DatabasePlatform { dbIdentity.setSupportsSequence(true); dbIdentity.setSupportsIdentity(true); dbIdentity.setSupportsGetGeneratedKeys(true); - this.dbDefaultValue.setFalse("0"); this.dbDefaultValue.setTrue("1"); this.dbDefaultValue.setNow("current_timestamp"); - this.treatEmptyStringsAsNull = true; this.likeClauseRaw = "like ?"; @@ -55,7 +53,6 @@ public class OraclePlatform extends DatabasePlatform { booleanDbType = Types.INTEGER; dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1)")); - dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10)); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19)); dbTypeMap.put(DbType.REAL, new DbPlatformType("number", 19, 4)); @@ -64,12 +61,10 @@ public class OraclePlatform extends DatabasePlatform { dbTypeMap.put(DbType.TINYINT, new DbPlatformType("number", 3)); dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("number", 16, 3)); dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar2", 255)); - dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob")); dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("clob")); dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("raw", 255)); dbTypeMap.put(DbType.BINARY, new DbPlatformType("raw", 255)); - dbTypeMap.put(DbType.TIME, new DbPlatformType("timestamp")); } From 25eea42211882c9ddc01f426e2da3b96b67377fc Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 22:28:36 +1300 Subject: [PATCH 18/47] Bump to ebean-migration 12.13.0 and ebean-agent 12.14.1 --- ebean-ddl-generator/pom.xml | 2 +- ebean-test/pom.xml | 2 +- pom.xml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 6d009ead8..f1d792515 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -22,7 +22,7 @@ io.ebean ebean-migration - 12.12.1 + 12.13.0 diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 17041e36c..282142c75 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -91,7 +91,7 @@ io.ebean ebean-migration - 12.12.1 + 12.13.0 test diff --git a/pom.xml b/pom.xml index 9d8573072..7e2f27707 100644 --- a/pom.xml +++ b/pom.xml @@ -42,11 +42,11 @@ 2.12.1 1.2 1.1 - 12.12.1 + 12.13.1 4.2 7.3 - 12.13.0 - 12.13.0 + 12.14.1 + 12.14.1 From 8edaabf755ef1ab980be36892f12acda9c8cb2e7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 22:30:53 +1300 Subject: [PATCH 19/47] [maven-release-plugin] prepare release ebean-parent-12.14.1 --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index ca0b583c5..a3c6d52de 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index dedf2e053..022b1655f 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-parent-12.14.1 ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 47f0f4ce4..44c55f527 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean bom @@ -71,88 +71,88 @@ io.ebean ebean - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-api - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-core-type - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-ddl-generator - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-externalmapping-api - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-externalmapping-xml - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-autotune - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-querybean - 12.14.1-SNAPSHOT + 12.14.1 io.ebean querybean-generator - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean kotlin-querybean-generator - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean ebean-postgis - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-redis - 12.14.1-SNAPSHOT + 12.14.1 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 9eb1859c9..f6ff80ff4 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.14.1-SNAPSHOT + 12.14.1 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 89aa0e6e5..62867947a 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-parent-12.14.1 @@ -41,19 +41,19 @@ io.ebean ebean-api - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-core-type - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-externalmapping-api - 12.14.1-SNAPSHOT + 12.14.1 diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index f1d792515..28276ded2 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 1f7620729..7a89eb242 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index d9727054a..ef78fb6be 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-parent-12.14.1 ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.14.1-SNAPSHOT + 12.14.1 @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean ebean-ddl-generator - 12.14.1-SNAPSHOT + 12.14.1 test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 3e6e22ede..4d3b7f5c5 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.1 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index e04cb19ea..1b136c7a6 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided @@ -56,21 +56,21 @@ io.ebean ebean-ddl-generator - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean querybean-generator - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.1 test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 5acd9874b..2f15b08a8 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean ebean-querybean - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean querybean-generator - 12.14.1-SNAPSHOT + 12.14.1 test io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.1 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 282142c75..f1892a298 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 provided io.ebean ebean-ddl-generator - 12.14.1-SNAPSHOT + 12.14.1 diff --git a/ebean/pom.xml b/ebean/pom.xml index 751a7d829..4d04a3c18 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 io.ebean ebean-querybean - 12.14.1-SNAPSHOT + 12.14.1 diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index da44acb28..ef935b5cc 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.14.1-SNAPSHOT + 12.14.1 test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.1 test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.14.1-SNAPSHOT + 12.14.1 test diff --git a/pom.xml b/pom.xml index 7e2f27707..a86626155 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.14.1-SNAPSHOT + 12.14.1 pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-parent-12.14.1 diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 3e50a4758..142af2861 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.1 querybean generator From df8ae18bf613f1914cc476623b2404e23b690068 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 17 Jan 2022 22:31:00 +1300 Subject: [PATCH 20/47] [maven-release-plugin] prepare for next development iteration --- ebean-api/pom.xml | 2 +- ebean-autotune/pom.xml | 6 +++--- ebean-bom/pom.xml | 30 +++++++++++++++--------------- ebean-core-type/pom.xml | 4 ++-- ebean-core/pom.xml | 10 +++++----- ebean-ddl-generator/pom.xml | 6 +++--- ebean-externalmapping-api/pom.xml | 2 +- ebean-externalmapping-xml/pom.xml | 10 +++++----- ebean-postgis/pom.xml | 6 +++--- ebean-querybean/pom.xml | 10 +++++----- ebean-redis/pom.xml | 12 ++++++------ ebean-test/pom.xml | 6 +++--- ebean/pom.xml | 8 ++++---- kotlin-querybean-generator/pom.xml | 8 ++++---- pom.xml | 4 ++-- querybean-generator/pom.xml | 2 +- 16 files changed, 63 insertions(+), 63 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index a3c6d52de..3bffa4323 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean api diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 022b1655f..9dbe36921 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.14.1 + HEAD ebean autotune @@ -26,7 +26,7 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index 44c55f527..6d9110a91 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean bom @@ -71,88 +71,88 @@ io.ebean ebean - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-api - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-core-type - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-ddl-generator - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-externalmapping-api - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-externalmapping-xml - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-autotune - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-querybean - 12.14.1 + 12.14.2-SNAPSHOT io.ebean querybean-generator - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean kotlin-querybean-generator - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean ebean-test - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean ebean-postgis - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-redis - 12.14.1 + 12.14.2-SNAPSHOT diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index f6ff80ff4..0dd19215f 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 12.14.1 + 12.14.2-SNAPSHOT diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 62867947a..9c2a36f8e 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean-core @@ -15,7 +15,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.14.1 + HEAD @@ -41,19 +41,19 @@ io.ebean ebean-api - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-core-type - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-externalmapping-api - 12.14.1 + 12.14.2-SNAPSHOT diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index 28276ded2..b0e8138dc 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided diff --git a/ebean-externalmapping-api/pom.xml b/ebean-externalmapping-api/pom.xml index 7a89eb242..d9c3b9e62 100644 --- a/ebean-externalmapping-api/pom.xml +++ b/ebean-externalmapping-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean external mapping api diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index ef78fb6be..94047ec2e 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT @@ -14,7 +14,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.14.1 + HEAD ebean external mapping xml @@ -33,7 +33,7 @@ io.ebean ebean-externalmapping-api - 12.14.1 + 12.14.2-SNAPSHOT @@ -59,14 +59,14 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean ebean-ddl-generator - 12.14.1 + 12.14.2-SNAPSHOT test diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index 4d3b7f5c5..ac4553b77 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean postgis @@ -23,7 +23,7 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided @@ -74,7 +74,7 @@ io.ebean ebean-test - 12.14.1 + 12.14.2-SNAPSHOT test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 1b136c7a6..6ecbfafad 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided @@ -56,21 +56,21 @@ io.ebean ebean-ddl-generator - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean querybean-generator - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean ebean-test - 12.14.1 + 12.14.2-SNAPSHOT test diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index 2f15b08a8..e811c97ad 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean-redis @@ -22,35 +22,35 @@ io.ebean ebean-api - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean ebean-querybean - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean querybean-generator - 12.14.1 + 12.14.2-SNAPSHOT test io.ebean ebean-test - 12.14.1 + 12.14.2-SNAPSHOT test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index f1892a298..a11b27133 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean test @@ -29,14 +29,14 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT provided io.ebean ebean-ddl-generator - 12.14.1 + 12.14.2-SNAPSHOT diff --git a/ebean/pom.xml b/ebean/pom.xml index 4d04a3c18..e399daa25 100644 --- a/ebean/pom.xml +++ b/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT ebean composite @@ -22,20 +22,20 @@ io.ebean ebean-api - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT io.ebean ebean-querybean - 12.14.1 + 12.14.2-SNAPSHOT diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index ef935b5cc..cb1fcce36 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT kotlin querybean generator @@ -29,7 +29,7 @@ io.ebean ebean-querybean - 12.14.1 + 12.14.2-SNAPSHOT test @@ -43,7 +43,7 @@ io.ebean ebean-core - 12.14.1 + 12.14.2-SNAPSHOT test @@ -64,7 +64,7 @@ io.ebean ebean-ddl-generator - 12.14.1 + 12.14.2-SNAPSHOT test diff --git a/pom.xml b/pom.xml index a86626155..52a0a596e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean-parent - 12.14.1 + 12.14.2-SNAPSHOT pom ebean parent @@ -18,7 +18,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-parent-12.14.1 + HEAD diff --git a/querybean-generator/pom.xml b/querybean-generator/pom.xml index 142af2861..98d196530 100644 --- a/querybean-generator/pom.xml +++ b/querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 12.14.1 + 12.14.2-SNAPSHOT querybean generator From 0139ad891ea6ef32006e87a0b13744ecb9d790f3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 21 Jan 2022 17:20:21 +1300 Subject: [PATCH 21/47] #2403 - table partitioning (Postgres only at this point) is always included + simplify skip logic --- .../io/ebeaninternal/dbmigration/DdlGenerator.java | 2 +- .../ebeaninternal/dbmigration/DefaultDbMigration.java | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java index 167084842..b9fead35b 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java @@ -212,7 +212,7 @@ public class DdlGenerator implements SpiDdlGenerator { if (extraDdl && jaxbPresent) { if (currentModel().isTablePartitioning()) { String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(platform); - if (extraPartitioning != null && !extraPartitioning.isEmpty() && useMigrationStoredProcedures) { + if (extraPartitioning != null && !extraPartitioning.isEmpty()) { runScript(connection, false, extraPartitioning, "builtin-partitioning-ddl"); } } diff --git a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index 8d1bb22b4..4add6fe13 100644 --- a/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/ebean-ddl-generator/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -397,23 +397,20 @@ public class DefaultDbMigration implements DbMigration { private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform, boolean tablePartitioning) throws IOException { if (dbPlatform != null) { if (tablePartitioning && includeBuiltInPartitioning) { - generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltinTablePartitioning(), true); + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltinTablePartitioning(), false); } + // skip built-in migration stored procedures based on isUseMigrationStoredProcedures generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin(), true); generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.read(), false); } } - private void generateExtraDdlFor(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl, boolean isBuiltin) throws IOException { + private void generateExtraDdlFor(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl, boolean checkSkip) throws IOException { if (extraDdl != null) { List ddlScript = extraDdl.getDdlScript(); for (DdlScript script : ddlScript) { if (!script.isDrop() && matchPlatform(dbPlatform.getPlatform(), script.getPlatforms())) { - if (script.isInit()) { - if (!isBuiltin || dbPlatform.isUseMigrationStoredProcedures()) { - writeExtraDdl(migrationDir, script); - } - } else { + if (!checkSkip || dbPlatform.isUseMigrationStoredProcedures()) { writeExtraDdl(migrationDir, script); } } From e26e093680c2ff74a2845b4235775fd223ced68e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 21 Jan 2022 17:38:03 +1300 Subject: [PATCH 22/47] Bump test poms to 12.14.2-SNAPSHOT --- tests/test-java16/pom.xml | 6 +++--- tests/test-kotlin/pom.xml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test-java16/pom.xml b/tests/test-java16/pom.xml index 302af2a2f..7ac83574a 100644 --- a/tests/test-java16/pom.xml +++ b/tests/test-java16/pom.xml @@ -20,7 +20,7 @@ io.ebean ebean - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT @@ -32,7 +32,7 @@ io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT test @@ -58,7 +58,7 @@ io.ebean querybean-generator - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index 5e65046dd..ab8706f74 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -36,14 +36,14 @@ io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT test io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT test From 6a6b6b8200667ed46c72dd574305da7144662862 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 21 Jan 2022 17:38:59 +1300 Subject: [PATCH 23/47] Bump ebean-kotlin to 12.14.2-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 b9a3e50c4..35923973c 100644 --- a/ebean-kotlin/pom.xml +++ b/ebean-kotlin/pom.xml @@ -5,7 +5,7 @@ ebean-parent io.ebean - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT 4.0.0 @@ -29,7 +29,7 @@ io.ebean ebean-core - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT provided @@ -51,7 +51,7 @@ io.ebean ebean-test - 12.14.1-SNAPSHOT + 12.14.2-SNAPSHOT test From 9df96b0294309e3c83fc84d770e5f854a7be92ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:47:27 +0000 Subject: [PATCH 24/47] Bump h2 from 1.4.199 to 2.1.210 in /ebean-api Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210. - [Release notes](https://github.com/h2database/h2database/releases) - [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210) --- updated-dependencies: - dependency-name: com.h2database:h2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- ebean-api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 3bffa4323..56fd5d994 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -85,7 +85,7 @@ com.h2database h2 - 1.4.199 + 2.1.210 true From bbede04a56bc751e985b1065524b38604b505098 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:47:27 +0000 Subject: [PATCH 25/47] Bump h2 from 1.4.199 to 2.1.210 in /ebean-test Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210. - [Release notes](https://github.com/h2database/h2database/releases) - [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210) --- updated-dependencies: - dependency-name: com.h2database:h2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- ebean-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index a11b27133..002aeb43c 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -76,7 +76,7 @@ com.h2database h2 - 1.4.199 + 2.1.210 From ddab6e65b7afc855902080ae051ed32ae6eec910 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:47:28 +0000 Subject: [PATCH 26/47] Bump h2 from 1.4.199 to 2.1.210 in /ebean-core Bumps [h2](https://github.com/h2database/h2database) from 1.4.199 to 2.1.210. - [Release notes](https://github.com/h2database/h2database/releases) - [Commits](https://github.com/h2database/h2database/compare/version-1.4.199...version-2.1.210) --- updated-dependencies: - dependency-name: com.h2database:h2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- ebean-core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index 9c2a36f8e..d77e38d62 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -78,7 +78,7 @@ com.h2database h2 - 1.4.199 + 2.1.210 provided From 4158ac466580dfab672b800ee634d1ecd7784b5b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 25 Jan 2022 13:44:23 +1300 Subject: [PATCH 27/47] Refactor internals split result load functionality from SqlTreeNode into SqlTreeLoad --- .../io/ebeaninternal/server/query/CQuery.java | 2 +- .../server/query/CQueryBuilder.java | 8 +- .../server/query/CQueryPlan.java | 8 +- .../server/query/CQueryPlanRawSql.java | 2 +- .../ebeaninternal/server/query/SqlTree.java | 14 +- .../server/query/SqlTreeLoad.java | 28 ++ .../server/query/SqlTreeLoadBean.java | 373 ++++++++++++++++++ .../server/query/SqlTreeLoadManyRoot.java | 30 ++ .../server/query/SqlTreeLoadRoot.java | 43 ++ .../server/query/SqlTreeNode.java | 24 +- .../server/query/SqlTreeNodeBean.java | 365 ++--------------- .../server/query/SqlTreeNodeExtraJoin.java | 18 +- .../query/SqlTreeNodeFormulaWhereJoin.java | 14 +- .../server/query/SqlTreeNodeManyRoot.java | 22 +- .../query/SqlTreeNodeManyWhereJoin.java | 17 +- .../server/query/SqlTreeNodeRoot.java | 30 +- .../server/query/SqlTreePlan.java | 41 ++ 17 files changed, 588 insertions(+), 451 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java 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 45a5b5a11..1870c1b6f 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 @@ -193,7 +193,7 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi // set the generated sql back to the query // so its available to the user... query.setGeneratedSql(queryPlan.getSql()); - SqlTree sqlTree = queryPlan.getSqlTree(); + SqlTreePlan sqlTree = queryPlan.getSqlTree(); this.rootNode = sqlTree.getRootNode(); this.manyProperty = sqlTree.getManyProperty(); this.sql = queryPlan.getSql(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 278603f5b..3367fbfe4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -110,7 +110,7 @@ final class CQueryBuilder { sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree); } // cache the query plan - queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryUpdate(request, predicates, queryPlan); } @@ -197,7 +197,7 @@ final class CQueryBuilder { SqlTree sqlTree = createSqlTree(request, predicates); SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); - queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, s.getSql(), sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct()); } @@ -288,7 +288,7 @@ final class CQueryBuilder { } } // cache the query plan - queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryRowCount(queryPlan, request, predicates); } @@ -343,7 +343,7 @@ final class CQueryBuilder { if (rawSql) { queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql()); } else { - queryPlan = new CQueryPlan(request, res, sqlTree, false, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, res, sqlTree.plan(), false, predicates.getLogWhereSql()); } BeanDescriptor desc = request.descriptor(); if (desc.isReadAuditing()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java index bf84070f2..d07276920 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java @@ -55,7 +55,7 @@ public class CQueryPlan implements SpiQueryPlan { private final String sql; private final String hash; private final String logWhereSql; - private final SqlTree sqlTree; + private final SqlTreePlan sqlTree; /** * Encrypted properties required additional binding. @@ -76,7 +76,7 @@ public class CQueryPlan implements SpiQueryPlan { /** * Create a query plan based on a OrmQueryRequest. */ - CQueryPlan(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTree sqlTree, boolean rawSql, String logWhereSql) { + CQueryPlan(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTreePlan sqlTree, boolean rawSql, String logWhereSql) { this.server = request.server(); this.dataTimeZone = server.dataTimeZone(); this.beanType = request.descriptor().type(); @@ -101,7 +101,7 @@ public class CQueryPlan implements SpiQueryPlan { /** * Create a query plan for a raw sql query. */ - CQueryPlan(OrmQueryRequest request, String sql, SqlTree sqlTree, String logWhereSql) { + CQueryPlan(OrmQueryRequest request, String sql, SqlTreePlan sqlTree, String logWhereSql) { this.server = request.server(); this.dataTimeZone = server.dataTimeZone(); this.beanType = request.descriptor().type(); @@ -249,7 +249,7 @@ public class CQueryPlan implements SpiQueryPlan { return rawSql ? planKey.getPartialKey() + "_" + hash : planKey.getPartialKey(); } - final SqlTree getSqlTree() { + final SqlTreePlan getSqlTree() { return sqlTree; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java index f35702ee1..935f730ec 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java @@ -17,7 +17,7 @@ final class CQueryPlanRawSql extends CQueryPlan { private final int[] rsetIndexPositions; CQueryPlanRawSql(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) { - super(request, sqlRes, sqlTree, true, logWhereSql); + super(request, sqlRes, sqlTree.plan(), true, logWhereSql); this.rsetIndexPositions = createIndexPositions(request, sqlTree); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java index 27e35c365..5b11be657 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java @@ -56,6 +56,10 @@ final class SqlTree { this.noJoins = !includeJoins; } + SqlTreePlan plan() { + return new SqlTreePlan(rootNode.createLoad(), manyProperty, encryptedProps, dependentTables()); + } + /** * Return true if the query mandates SQL Distinct due to ToMany inclusion. */ @@ -123,10 +127,6 @@ final class SqlTree { return inheritanceWhereSql; } - SqlTreeRoot getRootNode() { - return (SqlTreeRoot)rootNode; - } - /** * Return the property that is associated with the many. There can only be one * per SqlSelect. This can be null. @@ -135,10 +135,6 @@ final class SqlTree { return manyProperty; } - STreeProperty[] getEncryptedProps() { - return encryptedProps; - } - /** * Return true if the query has a many join. */ @@ -153,7 +149,7 @@ final class SqlTree { /** * Return the tables that are joined in this query. */ - Set dependentTables() { + private Set dependentTables() { Set tables = new LinkedHashSet<>(); rootNode.dependentTables(tables); return tables; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java new file mode 100644 index 000000000..c5ac129b1 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java @@ -0,0 +1,28 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebean.core.type.ScalarDataReader; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; + +/** + * Tree node that loads an entity bean type. + */ +interface SqlTreeLoad { + + /** + * Load the appropriate information from the SqlSelectReader. + *

+ * At a high level this actually controls the reading of the data from the + * jdbc resultSet and putting it into the bean etc. + *

+ */ + EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException; + + /** + * Return the reader for the single attribute query. + */ + ScalarDataReader getSingleAttributeReader(); + +} 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 new file mode 100644 index 000000000..516a00537 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java @@ -0,0 +1,373 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; +import io.ebean.bean.PersistenceContext; +import io.ebean.core.type.ScalarDataReader; +import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.api.SpiQuery.Mode; +import io.ebeaninternal.server.deploy.DbReadContext; +import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.id.IdBinder; + +import java.sql.SQLException; +import java.util.Map; + +/** + * Normal bean included in the query. + */ +class SqlTreeLoadBean implements SqlTreeLoad { + + final STreeType desc; + final IdBinder idBinder; + final SqlTreeLoad[] children; + private final boolean partialObject; + private final STreeProperty[] properties; + private final STreePropertyAssoc nodeBeanProp; + final boolean readId; + private final boolean readIdNormal; + private final boolean disableLazyLoad; + private final InheritInfo inheritInfo; + final String prefix; + private final Map pathMap; + final STreePropertyAssocMany lazyLoadParent; + private final SpiQuery.TemporalMode temporalMode; + private final boolean temporalVersions; + final IdBinder lazyLoadParentIdBinder; + + SqlTreeLoadBean(SqlTreeNodeBean node) { + this.lazyLoadParent = node.lazyLoadParent; + this.lazyLoadParentIdBinder = node.lazyLoadParentIdBinder; + this.prefix = node.prefix; + this.desc = node.desc; + this.inheritInfo = desc.inheritInfo(); + this.idBinder = desc.idBinder(); + this.temporalMode = node.temporalMode; + this.temporalVersions = node.temporalVersions; + this.nodeBeanProp = node.nodeBeanProp; + this.readId = node.readId;//!aggregationRoot && withId && desc.hasId(); + 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.children = node.createLoadChildren(); + } + + boolean isRoot() { + return false; + } + + @Override + public final ScalarDataReader getSingleAttributeReader() { + if (properties == null || properties.length == 0) { + // if we have no property ask first children (in a distinct select with join) + if (children.length == 0) { + // expected to be a findIds query + return desc.idBinder().getBeanProperty(); + } + return children[0].getSingleAttributeReader(); + } + if (properties[0] instanceof STreePropertyAssocOne) { + STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0]; + if (assocOne.isAssocId()) { + return assocOne.idReader(); + } + } + return properties[0]; + } + + /** + * Load that takes into account inheritance. + */ + private final class LoadInherit extends Load { + + private LoadInherit(DbReadContext ctx, EntityBean parentBean) { + super(ctx, parentBean); + } + + @Override + void initBeanType() throws SQLException { + InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo(); + if (localInfo == null) { + // the bean must be null + localIdBinder = idBinder; + localDesc = desc; + } else { + localBean = localInfo.createEntityBean(); + localType = localInfo.getType(); + localIdBinder = localInfo.getIdBinder(); + localDesc = localInfo.desc(); + } + } + + @Override + void loadProperties() { + // take account of inheritance + for (STreeProperty property : properties) { + localDesc.inheritanceLoad(sqlBeanLoad, property, ctx); + } + } + } + + /** + * Load a bean instance. + */ + class Load { + + final DbReadContext ctx; + final EntityBean parentBean; + + Object lazyLoadParentId; + Class localType; + STreeType localDesc; + IdBinder localIdBinder; + EntityBean localBean; + + Mode queryMode; + PersistenceContext persistenceContext; + Object id; + EntityBean contextBean; + SqlBeanLoad sqlBeanLoad; + boolean lazyLoadMany; + + private Load(DbReadContext ctx, EntityBean parentBean) { + this.ctx = ctx; + this.parentBean = parentBean; + } + + private void initLazyParent() throws SQLException { + if (lazyLoadParentIdBinder != null) { + lazyLoadParentId = lazyLoadParentIdBinder.read(ctx); + } + } + + void initBeanType() throws SQLException { + localDesc = desc; + localBean = desc.createEntityBean(); + localIdBinder = idBinder; + } + + private void initPersistenceContext() { + queryMode = ctx.getQueryMode(); + persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext(); + } + + private void readId() throws SQLException { + if (readId) { + id = localIdBinder.readSet(ctx, localBean); + if (id == null) { + readIdNullBean(); + } else if (!temporalVersions) { + readIdBean(); + } + } + } + + private void readIdBean() { + // check the PersistenceContext to see if the bean already exists + contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean); + if (contextBean == null) { + // bean just added to the persistenceContext + contextBean = localBean; + } else { + // bean already exists in persistenceContext + + if (queryMode.isLoadContextBean()) { + // if explicitly set loadContextBean to true, then reload + localBean = contextBean; + } else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) { + // reload if contextBean is partial object + localBean = contextBean; + // and switch to lazyLoad query mode in order not to overwrite + // existing properties in SqlBeanLoad::load + queryMode = Mode.LAZYLOAD_BEAN; + } else { + // ignore the DB data... + localBean = null; + } + } + } + + private void readIdNullBean() { + // bean must be null... + localBean = null; + // ... but there may exist as reference bean in parent which has to be marked as deleted. + if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) { + contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean); + if (contextBean != null) { + desc.markAsDeleted(contextBean); + } + } + } + + private void initSqlLoadBean() { + ctx.setCurrentPrefix(prefix, pathMap); + ctx.propagateState(localBean); + sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode); + } + + void loadProperties() { + for (STreeProperty property : properties) { + property.load(sqlBeanLoad); + } + } + + private void loadChildren() throws SQLException { + if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) { + // batch lazy load many into existing contextBean + localBean = contextBean; + lazyLoadMany = true; + } + for (SqlTreeLoad child : children) { + child.load(ctx, localBean, contextBean); + } + } + + private boolean isLazyLoadManyRoot() { + return queryMode == Mode.LAZYLOAD_MANY && isRoot(); + } + + private EntityBean getContextBean() { + return contextBean; + } + + private void postLoad() { + if (!lazyLoadMany && localBean != null) { + ctx.setCurrentPrefix(prefix, pathMap); + if (readIdNormal) { + createListProxies(); + } + if (temporalMode == SpiQuery.TemporalMode.DRAFT) { + localDesc.setDraft(localBean); + } + localDesc.postLoad(localBean); + + EntityBeanIntercept ebi = localBean._ebean_getIntercept(); + ebi.setPersistenceContext(persistenceContext); + if (Mode.LAZYLOAD_BEAN == queryMode) { + // Lazy Load does not reset the dirty state + ebi.setLoadedLazy(); + } else if (readId) { + // normal bean loading + ebi.setLoaded(); + } + + if (disableLazyLoad) { + // bean does not have an Id or is SqlSelect based + ebi.setDisableLazyLoad(true); + } else if (partialObject) { + if (readId) { + // register for lazy loading + ctx.register(null, ebi); + } + } else { + ebi.setFullyLoadedBean(true); + } + + if (ctx.isAutoTuneProfiling() && !disableLazyLoad) { + // collect autoTune profiling for this bean... + ctx.profileBean(ebi, prefix); + } + } + } + + /** + * Create lazy loading proxies for the Many's except for the one that is + * included in the actual query. + */ + private void createListProxies() { + STreePropertyAssocMany fetchedMany = ctx.getManyProperty(); + boolean forceNewReference = queryMode == Mode.REFRESH_BEAN; + for (STreePropertyAssocMany many : localDesc.propsMany()) { + if (many != fetchedMany) { + // create a proxy for the many (deferred fetching) + BeanCollection ref = many.createReference(localBean, forceNewReference); + if (ref != null) { + if (disableLazyLoad) { + ref.setDisableLazyLoad(true); + } + if (!ref.isRegisteredWithLoadContext()) { + ctx.register(many.asMany(), ref); + } + } + } + } + } + + private void setBeanToParent() { + if (parentBean != null) { + // set this back to the parentBean + nodeBeanProp.setValue(parentBean, contextBean); + } + } + + private EntityBean complete() { + if (!readIdNormal) { + // a bean with no Id (never found in context) + if (lazyLoadParentId != null) { + ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); + } + return localBean; + } else { + if (lazyLoadParentId != null) { + ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId); + } + return contextBean; + } + } + + private void initialise() throws SQLException { + initLazyParent(); + initBeanType(); + initPersistenceContext(); + readId(); + initSqlLoadBean(); + loadProperties(); + loadChildren(); + } + + /** + * Perform the load returning the loaded bean. + */ + final EntityBean perform() throws SQLException { + initialise(); + if (isLazyLoadManyRoot()) { + return getContextBean(); + } + postLoad(); + setBeanToParent(); + return complete(); + } + + /** + * Return true if this bean was already in the context. If already in the + * context we need to check if it is already contained in the collection. + */ + final boolean isContextBean() { + return localBean == null; + } + } + + /** + * read the properties from the resultSet. + */ + @Override + public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException { + return createLoad(ctx, parentBean).perform(); + } + + /** + * Create the loader with or without inheritance. + */ + final Load createLoad(DbReadContext ctx, EntityBean parentBean) { + return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean); + } + + @Override + public String toString() { + return "SqlTreeLoadBean: " + desc; + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java new file mode 100644 index 000000000..3622e770e --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java @@ -0,0 +1,30 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; + +final class SqlTreeLoadManyRoot extends SqlTreeLoadBean { + + private final STreePropertyAssocMany manyProp; + + SqlTreeLoadManyRoot(SqlTreeNodeManyRoot node) { + super(node); + this.manyProp = node.manyProp; + } + + @Override + public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { + // pass in null for parentBean because added to a collection rather than set to the parentBean + Load load = createLoad(cquery, null); + EntityBean detailBean = load.perform(); + if (contextParent != null) { + // Add to the collection and initialise collection if needed + // A null detailBean may initialise an empty collection + // Check for bean existing in collection based on load.isContextBean() + manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean()); + } + return detailBean; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java new file mode 100644 index 000000000..d1792ecbe --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java @@ -0,0 +1,43 @@ +package io.ebeaninternal.server.query; + +import io.ebean.Version; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; +import java.sql.Timestamp; + +/** + * Represents the root node of the Sql Tree. + */ +final class SqlTreeLoadRoot extends SqlTreeLoadBean implements SqlTreeRoot { + + SqlTreeLoadRoot(SqlTreeNodeBean node) { + super(node); + } + + @Override + protected boolean isRoot() { + return true; + } + + @Override + public EntityBean load(DbReadContext ctx) throws SQLException { + return load(ctx, null, null); + } + + /** + * Read the version bean. + */ + @Override + @SuppressWarnings("unchecked") + public Version loadVersion(DbReadContext ctx) throws SQLException { + // read the sys period lower and upper bounds + // these are always the first 2 columns in the resultSet + Timestamp start = ctx.getDataReader().getTimestamp(); + Timestamp end = ctx.getDataReader().getTimestamp(); + T bean = (T) load(ctx, null, null); + return new Version<>(bean, start, end); + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java index 39844cb59..54632d9ca 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java @@ -1,13 +1,8 @@ package io.ebeaninternal.server.query; -import io.ebean.Version; -import io.ebean.bean.EntityBean; -import io.ebean.core.type.ScalarDataReader; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; -import java.sql.SQLException; import java.util.List; import java.util.Set; @@ -64,25 +59,11 @@ interface SqlTreeNode { */ void addSoftDeletePredicate(SpiQuery query); - /** - * Load the appropriate information from the SqlSelectReader. - *

- * At a high level this actually controls the reading of the data from the - * jdbc resultSet and putting it into the bean etc. - *

- */ - EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException; - /** * Return true if the query has a many join. */ boolean hasMany(); - /** - * Return the reader for the single attribute query. - */ - ScalarDataReader getSingleAttributeReader(); - /** * Return true if the query is known to only have a single property selected. */ @@ -92,4 +73,9 @@ interface SqlTreeNode { * Add dependent tables to the given set. */ void dependentTables(Set tables); + + /** + * Create the loader for this node. + */ + SqlTreeLoad createLoad(); } 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 547eededc..4836fa3fd 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 @@ -1,30 +1,20 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.BeanCollection; -import io.ebean.bean.EntityBean; -import io.ebean.bean.EntityBeanIntercept; -import io.ebean.bean.PersistenceContext; -import io.ebean.core.type.ScalarDataReader; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.api.SpiQuery.Mode; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.id.IdBinder; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Normal bean included in the query. */ 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; @@ -36,33 +26,33 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * Set to true if this is a partial object fetch. */ - private final boolean partialObject; - private final STreeProperty[] properties; + final boolean partialObject; + final STreeProperty[] properties; /** * Extra where clause added by Where annotation on associated many. */ - private final String extraWhere; - private final STreePropertyAssoc nodeBeanProp; + final String extraWhere; + final STreePropertyAssoc nodeBeanProp; /** * False if report bean and has no id property. */ final boolean readId; - private final boolean readIdNormal; - private final boolean disableLazyLoad; - private final InheritInfo inheritInfo; + final boolean readIdNormal; + final boolean disableLazyLoad; + final InheritInfo inheritInfo; final String prefix; - private final Map pathMap; + final Map pathMap; final STreePropertyAssocMany lazyLoadParent; - private final SpiQuery.TemporalMode temporalMode; - private final boolean temporalVersions; - private final IdBinder lazyLoadParentIdBinder; + final SpiQuery.TemporalMode temporalMode; + final boolean temporalVersions; + final IdBinder lazyLoadParentIdBinder; String baseTableAlias; /** * Table alias set if this bean node includes a join to a intersection * table and that table has history support. */ - private boolean intersectionAsOfTableAlias; - private final boolean aggregation; + boolean intersectionAsOfTableAlias; + final boolean aggregation; /** * Construct for leaf node. @@ -108,8 +98,23 @@ class SqlTreeNodeBean implements SqlTreeNode { pathMap = createPathMap(prefix, desc); } - boolean isRoot() { - return false; + @Override + public SqlTreeLoad createLoad() { + return new SqlTreeLoadBean(this); + } + + protected SqlTreeLoad[] createLoadChildren() { + if (children.length == 0) { + return NO_LOAD_CHILDREN; + } + List loadChildren = new ArrayList<>(children.length); + for (SqlTreeNode child : children) { + SqlTreeLoad load = child.createLoad(); + if (load != null) { + loadChildren.add(load); + } + } + return loadChildren.toArray(new SqlTreeLoad[0]); } @Override @@ -117,25 +122,6 @@ class SqlTreeNodeBean implements SqlTreeNode { return properties != null && properties.length == 1 && children.length == 0; } - @Override - public final ScalarDataReader getSingleAttributeReader() { - if (properties == null || properties.length == 0) { - // if we have no property ask first children (in a distinct select with join) - if (children.length == 0) { - // expected to be a findIds query - return desc.idBinder().getBeanProperty(); - } - return children[0].getSingleAttributeReader(); - } - if (properties[0] instanceof STreePropertyAssocOne) { - STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0]; - if (assocOne.isAssocId()) { - return assocOne.idReader(); - } - } - return properties[0]; - } - private Map createPathMap(String prefix, STreeType desc) { HashMap m = new HashMap<>(); for (STreePropertyAssocMany many : desc.propsMany()) { @@ -173,293 +159,6 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - /** - * Load that takes into account inheritance. - */ - private final class LoadInherit extends Load { - - private LoadInherit(DbReadContext ctx, EntityBean parentBean) { - super(ctx, parentBean); - } - - @Override - void initBeanType() throws SQLException { - InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo(); - if (localInfo == null) { - // the bean must be null - localIdBinder = idBinder; - localDesc = desc; - } else { - localBean = localInfo.createEntityBean(); - localType = localInfo.getType(); - localIdBinder = localInfo.getIdBinder(); - localDesc = localInfo.desc(); - } - } - - @Override - void loadProperties() { - // take account of inheritance - for (STreeProperty property : properties) { - localDesc.inheritanceLoad(sqlBeanLoad, property, ctx); - } - } - } - - /** - * Load a bean instance. - */ - class Load { - - final DbReadContext ctx; - final EntityBean parentBean; - - Object lazyLoadParentId; - Class localType; - STreeType localDesc; - IdBinder localIdBinder; - EntityBean localBean; - - Mode queryMode; - PersistenceContext persistenceContext; - Object id; - EntityBean contextBean; - SqlBeanLoad sqlBeanLoad; - boolean lazyLoadMany; - - private Load(DbReadContext ctx, EntityBean parentBean) { - this.ctx = ctx; - this.parentBean = parentBean; - } - - private void initLazyParent() throws SQLException { - if (lazyLoadParentIdBinder != null) { - lazyLoadParentId = lazyLoadParentIdBinder.read(ctx); - } - } - - void initBeanType() throws SQLException { - localDesc = desc; - localBean = desc.createEntityBean(); - localIdBinder = idBinder; - } - - private void initPersistenceContext() { - queryMode = ctx.getQueryMode(); - persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext(); - } - - private void readId() throws SQLException { - if (readId) { - id = localIdBinder.readSet(ctx, localBean); - if (id == null) { - readIdNullBean(); - } else if (!temporalVersions) { - readIdBean(); - } - } - } - - private void readIdBean() { - // check the PersistenceContext to see if the bean already exists - contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean); - if (contextBean == null) { - // bean just added to the persistenceContext - contextBean = localBean; - } else { - // bean already exists in persistenceContext - - if (queryMode.isLoadContextBean()) { - // if explicitly set loadContextBean to true, then reload - localBean = contextBean; - } else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) { - // reload if contextBean is partial object - localBean = contextBean; - // and switch to lazyLoad query mode in order not to overwrite - // existing properties in SqlBeanLoad::load - queryMode = Mode.LAZYLOAD_BEAN; - } else { - // ignore the DB data... - localBean = null; - } - } - } - - private void readIdNullBean() { - // bean must be null... - localBean = null; - // ... but there may exist as reference bean in parent which has to be marked as deleted. - if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) { - contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean); - if (contextBean != null) { - desc.markAsDeleted(contextBean); - } - } - } - - private void initSqlLoadBean() { - ctx.setCurrentPrefix(prefix, pathMap); - ctx.propagateState(localBean); - sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode); - } - - void loadProperties() { - for (STreeProperty property : properties) { - property.load(sqlBeanLoad); - } - } - - private void loadChildren() throws SQLException { - if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) { - // batch lazy load many into existing contextBean - localBean = contextBean; - lazyLoadMany = true; - } - for (SqlTreeNode child : children) { - child.load(ctx, localBean, contextBean); - } - } - - private boolean isLazyLoadManyRoot() { - return queryMode == Mode.LAZYLOAD_MANY && isRoot(); - } - - private EntityBean getContextBean() { - return contextBean; - } - - private void postLoad() { - if (!lazyLoadMany && localBean != null) { - ctx.setCurrentPrefix(prefix, pathMap); - if (readIdNormal) { - createListProxies(); - } - if (temporalMode == SpiQuery.TemporalMode.DRAFT) { - localDesc.setDraft(localBean); - } - localDesc.postLoad(localBean); - - EntityBeanIntercept ebi = localBean._ebean_getIntercept(); - ebi.setPersistenceContext(persistenceContext); - if (Mode.LAZYLOAD_BEAN == queryMode) { - // Lazy Load does not reset the dirty state - ebi.setLoadedLazy(); - } else if (readId) { - // normal bean loading - ebi.setLoaded(); - } - - if (disableLazyLoad) { - // bean does not have an Id or is SqlSelect based - ebi.setDisableLazyLoad(true); - } else if (partialObject) { - if (readId) { - // register for lazy loading - ctx.register(null, ebi); - } - } else { - ebi.setFullyLoadedBean(true); - } - - if (ctx.isAutoTuneProfiling() && !disableLazyLoad) { - // collect autoTune profiling for this bean... - ctx.profileBean(ebi, prefix); - } - } - } - - /** - * Create lazy loading proxies for the Many's except for the one that is - * included in the actual query. - */ - private void createListProxies() { - STreePropertyAssocMany fetchedMany = ctx.getManyProperty(); - boolean forceNewReference = queryMode == Mode.REFRESH_BEAN; - for (STreePropertyAssocMany many : localDesc.propsMany()) { - if (many != fetchedMany) { - // create a proxy for the many (deferred fetching) - BeanCollection ref = many.createReference(localBean, forceNewReference); - if (ref != null) { - if (disableLazyLoad) { - ref.setDisableLazyLoad(true); - } - if (!ref.isRegisteredWithLoadContext()) { - ctx.register(many.asMany(), ref); - } - } - } - } - } - - private void setBeanToParent() { - if (parentBean != null) { - // set this back to the parentBean - nodeBeanProp.setValue(parentBean, contextBean); - } - } - - private EntityBean complete() { - if (!readIdNormal) { - // a bean with no Id (never found in context) - if (lazyLoadParentId != null) { - ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); - } - return localBean; - } else { - if (lazyLoadParentId != null) { - ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId); - } - return contextBean; - } - } - - private void initialise() throws SQLException { - initLazyParent(); - initBeanType(); - initPersistenceContext(); - readId(); - initSqlLoadBean(); - loadProperties(); - loadChildren(); - } - - /** - * Perform the load returning the loaded bean. - */ - final EntityBean perform() throws SQLException { - initialise(); - if (isLazyLoadManyRoot()) { - return getContextBean(); - } - postLoad(); - setBeanToParent(); - return complete(); - } - - /** - * Return true if this bean was already in the context. If already in the - * context we need to check if it is already contained in the collection. - */ - final boolean isContextBean() { - return localBean == null; - } - } - - /** - * read the properties from the resultSet. - */ - @Override - public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException { - return createLoad(ctx, parentBean).perform(); - } - - /** - * Create the loader with or without inheritance. - */ - final Load createLoad(DbReadContext ctx, EntityBean parentBean) { - return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean); - } - @Override public final void appendGroupBy(DbSqlContext ctx, boolean subQuery) { ctx.pushJoin(prefix); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index e7ca5d9ab..42d2395b5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -38,6 +38,11 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany; } + @Override + public SqlTreeLoad createLoad() { + return null; + } + @Override public boolean isSingleProperty() { return false; @@ -73,11 +78,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { // nothing to do here } - @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); - } - /** * Return true if the extra join is a many join. *

@@ -184,14 +184,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { public void appendWhere(DbSqlContext ctx) { } - /** - * Does nothing. - */ - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - return null; - } - @Override public boolean hasMany() { return manyJoin; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java index 06a71133a..502c28a6d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java @@ -33,13 +33,13 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode { } @Override - public boolean isSingleProperty() { - return true; + public SqlTreeLoad createLoad() { + return null; } @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); + public boolean isSingleProperty() { + return true; } @Override @@ -98,12 +98,6 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode { // nothing to do here } - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - // nothing to do here - return null; - } - @Override public boolean hasMany() { return true; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java index c030e96bc..a8b323533 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java @@ -1,16 +1,13 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; -import java.sql.SQLException; import java.util.List; final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { - private final STreePropertyAssocMany manyProp; + final STreePropertyAssocMany manyProp; SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List myList, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { @@ -19,22 +16,13 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { } @Override - public boolean hasMany() { - return true; + public SqlTreeLoad createLoad() { + return new SqlTreeLoadManyRoot(this); } @Override - public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { - // pass in null for parentBean because added to a collection rather than set to the parentBean - SqlTreeNodeBean.Load load = createLoad(cquery, null); - EntityBean detailBean = load.perform(); - if (contextParent != null) { - // Add to the collection and initialise collection if needed - // A null detailBean may initialise an empty collection - // Check for bean existing in collection based on load.isContextBean() - manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean()); - } - return detailBean; + public boolean hasMany() { + return true; } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index 73c7a18b2..cb2ba54e7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -1,10 +1,7 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.EntityBean; -import io.ebean.core.type.ScalarType; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; @@ -37,13 +34,13 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode { } @Override - public boolean isSingleProperty() { - return false; + public SqlTreeLoad createLoad() { + return null; } @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); + public boolean isSingleProperty() { + return false; } @Override @@ -132,12 +129,6 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode { // nothing to do here } - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - // nothing to do here - return null; - } - @Override public boolean hasMany() { return true; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java index a58c51cc5..c25024624 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -1,21 +1,16 @@ package io.ebeaninternal.server.query; -import io.ebean.Version; -import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; -import java.sql.SQLException; -import java.sql.Timestamp; import java.util.List; import java.util.Set; /** * Represents the root node of the Sql Tree. */ -final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot { +final class SqlTreeNodeRoot extends SqlTreeNodeBean { private final TableJoin includeJoin; private final boolean sqlDistinct; @@ -34,27 +29,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot { } @Override - protected boolean isRoot() { - return true; - } - - @Override - public EntityBean load(DbReadContext ctx) throws SQLException { - return load(ctx, null, null); - } - - /** - * Read the version bean. - */ - @Override - @SuppressWarnings("unchecked") - public Version loadVersion(DbReadContext ctx) throws SQLException { - // read the sys period lower and upper bounds - // these are always the first 2 columns in the resultSet - Timestamp start = ctx.getDataReader().getTimestamp(); - Timestamp end = ctx.getDataReader().getTimestamp(); - T bean = (T) load(ctx, null, null); - return new Version<>(bean, start, end); + public SqlTreeLoad createLoad() { + return new SqlTreeLoadRoot(this); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java new file mode 100644 index 000000000..7a0e929ef --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java @@ -0,0 +1,41 @@ +package io.ebeaninternal.server.query; + +import java.util.Set; + +final class SqlTreePlan { + + private final SqlTreeLoad rootNode; + private final STreePropertyAssocMany manyProperty; + private final STreeProperty[] encryptedProps; + private final Set dependentTables; + + SqlTreePlan(SqlTreeLoad rootNode, STreePropertyAssocMany manyProperty, STreeProperty[] encryptedProps, Set dependentTables) { + this.rootNode = rootNode; + this.manyProperty = manyProperty; + this.encryptedProps = encryptedProps; + this.dependentTables = dependentTables; + } + + SqlTreeRoot getRootNode() { + return (SqlTreeRoot)rootNode; + } + + /** + * Return the property that is associated with the many. There can only be one + * per SqlSelect. This can be null. + */ + STreePropertyAssocMany getManyProperty() { + return manyProperty; + } + + STreeProperty[] getEncryptedProps() { + return encryptedProps; + } + + /** + * Return the tables that are joined in this query. + */ + Set dependentTables() { + return dependentTables; + } +} From 8d29a3a575776d00de15c81e3ddd0c5620ca0f11 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 25 Jan 2022 21:27:32 +1300 Subject: [PATCH 28/47] Bind LocalDate directly using JDBC driver to convert This addresses issues with dates before 1900-01-01 with H2Database --- .../java/io/ebean/core/type/DataReader.java | 2 ++ .../server/type/RsetDataReader.java | 5 +++++ .../server/type/ScalarTypeJodaLocalDate.java | 21 +++++++++++++++++-- .../server/type/ScalarTypeLocalDate.java | 17 +++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/ebean-core-type/src/main/java/io/ebean/core/type/DataReader.java b/ebean-core-type/src/main/java/io/ebean/core/type/DataReader.java index ef61b9122..d9a1ade92 100644 --- a/ebean-core-type/src/main/java/io/ebean/core/type/DataReader.java +++ b/ebean-core-type/src/main/java/io/ebean/core/type/DataReader.java @@ -47,6 +47,8 @@ public interface DataReader { Object getObject() throws SQLException; + T getObject(Class cls) throws SQLException; + InputStream getBinaryStream() throws SQLException; /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java index b85c8e688..574f37615 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/RsetDataReader.java @@ -73,6 +73,11 @@ public class RsetDataReader implements DataReader { return rset.getObject(pos()); } + @Override + public T getObject(Class cls) throws SQLException { + return rset.getObject(pos(), cls); + } + @Override public BigDecimal getBigDecimal() throws SQLException { return rset.getBigDecimal(pos()); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java index a7f385442..eb10a80bb 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaLocalDate.java @@ -1,11 +1,14 @@ package io.ebeaninternal.server.type; import io.ebean.config.JsonConfig; +import io.ebean.core.type.DataBinder; +import io.ebean.core.type.DataReader; import io.ebeaninternal.server.core.BasicTypeConverter; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; import java.sql.Date; +import java.sql.SQLException; import java.sql.Types; /** @@ -40,7 +43,7 @@ final class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate { @SuppressWarnings("deprecation") @Override public Date convertToDate(LocalDate value) { - return new Date(value .getYear() - 1900, value .getMonthOfYear() - 1, value .getDayOfMonth()); + return new Date(value.getYear() - 1900, value.getMonthOfYear() - 1, value.getDayOfMonth()); } @Override @@ -54,9 +57,23 @@ final class ScalarTypeJodaLocalDate extends ScalarTypeBaseDate { @Override public LocalDate toBeanType(Object value) { if (value instanceof java.util.Date) { - return LocalDate.fromDateFields((java.util.Date)value); + return LocalDate.fromDateFields((java.util.Date) value); } return (LocalDate) value; } + @Override + public void bind(DataBinder binder, LocalDate value) throws SQLException { + if (value == null) { + binder.setNull(Types.DATE); + } else { + binder.setObject(java.time.LocalDate.of(value.getYear(), value.getMonthOfYear(), value.getDayOfMonth())); + } + } + + @Override + public LocalDate read(DataReader reader) throws SQLException { + java.time.LocalDate jtDate = reader.getObject(java.time.LocalDate.class); + return jtDate == null ? null : new org.joda.time.LocalDate(jtDate.getYear(), jtDate.getMonthValue(), jtDate.getDayOfMonth()); + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDate.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDate.java index 630fe73a3..1e298ecac 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDate.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalDate.java @@ -1,9 +1,12 @@ package io.ebeaninternal.server.type; import io.ebean.config.JsonConfig; +import io.ebean.core.type.DataBinder; +import io.ebean.core.type.DataReader; import io.ebeaninternal.server.core.BasicTypeConverter; import java.sql.Date; +import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.time.LocalDate; @@ -61,4 +64,18 @@ final class ScalarTypeLocalDate extends ScalarTypeBaseDate { return (LocalDate) value; } + @Override + public void bind(DataBinder binder, LocalDate value) throws SQLException { + if (value == null) { + binder.setNull(Types.DATE); + } else { + binder.setObject(value); + } + } + + @Override + public LocalDate read(DataReader reader) throws SQLException { + return reader.getObject(LocalDate.class); + } + } From a9dbc036e9434393b7136ce830e34ae477680503 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 25 Jan 2022 21:28:09 +1300 Subject: [PATCH 29/47] Support H2database 2.x --- ebean-api/pom.xml | 2 +- ebean-core/pom.xml | 2 +- .../server/expression/platform/H2DbExpression.java | 3 ++- .../io/ebeaninternal/server/type/EnumToDbIntegerMap.java | 8 ++++++++ .../io/ebeaninternal/server/type/EnumToDbValueMap.java | 6 +++--- .../src/test/resources/application-test.properties | 4 ++-- ebean-test/pom.xml | 2 +- .../java/io/ebean/config/PlatformNoGeneratedKeysTest.java | 2 +- .../server/type/ScalarTypeLocalDateTest.java | 8 ++++++++ .../test/java/org/tests/update/TestSqlUpdateUpsert.java | 2 +- ebean-test/src/test/resources/test-ebean.properties | 2 +- pom.xml | 2 +- 12 files changed, 30 insertions(+), 13 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index b681c1a70..872acf7d4 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -85,7 +85,7 @@ com.h2database h2 - 2.0.202 + 2.1.210 true diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index af55c2c6a..2c3ff4ec4 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -78,7 +78,7 @@ com.h2database h2 - 2.0.202 + 2.1.210 provided diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java index 5eddb5d11..60cb180d3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -10,6 +10,7 @@ final class H2DbExpression extends BasicDbExpression { @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { - bitwiseFunction(request, propName, operator, compare); + String funcName = functionName(operator); + request.append(funcName).append("(").append(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbIntegerMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbIntegerMap.java index 2e2d2cc31..5f34e31fe 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbIntegerMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbIntegerMap.java @@ -34,6 +34,14 @@ final class EnumToDbIntegerMap extends EnumToDbValueMap { addInternal(beanValue, dbValue, name); } + @Override + public Object getBeanValue(Object dbValue) { + if (dbValue instanceof String) { + return super.getBeanValue(Integer.parseInt(dbValue.toString())); + } + return super.getBeanValue(dbValue); + } + @Override public EnumToDbIntegerMap add(Object beanValue, String stringDbValue, String name) { try { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbValueMap.java b/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbValueMap.java index 92ebc9334..5ff0f9ed6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbValueMap.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/type/EnumToDbValueMap.java @@ -116,7 +116,8 @@ abstract class EnumToDbValueMap { /** * Return the Bean value given the DB value. */ - public Object getBeanValue(T dbValue) { + @SuppressWarnings("SuspiciousMethodCalls") + public Object getBeanValue(Object dbValue) { if (dbValue == null) { return null; } @@ -125,8 +126,7 @@ abstract class EnumToDbValueMap { beanValue = nameMap.get(dbValue); } if (beanValue == null && !allowNulls) { - String msg = "Bean value for " + dbValue + " not found in " + valueMap; - throw new IllegalArgumentException(msg); + throw new IllegalArgumentException("Bean value for " + dbValue + " not found in " + valueMap); } return beanValue; } diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties index 76f2d661f..5b7b35ed3 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.databaseUrl=jdbc:h2:mem:tests +datasource.h2.databaseUrl=jdbc:h2:mem:tests;NON_KEYWORDS=KEY datasource.pg.username=sa datasource.pg.password= -datasource.pg.databaseUrl=jdbc:h2:mem:tests +datasource.pg.databaseUrl=jdbc:h2:mem:tests;NON_KEYWORDS=KEY diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index f0fb26900..b5940bab0 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -76,7 +76,7 @@ com.h2database h2 - 2.0.202 + 2.1.210 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 9d600fc56..6c57e56bb 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); diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTest.java index 076bad958..da18e2a3c 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/type/ScalarTypeLocalDateTest.java @@ -47,6 +47,14 @@ public class ScalarTypeLocalDateTest { assertTrue(o instanceof Date); } + @Test + public void olderDates_ToFromJdbcType() { + LocalDate localDate = LocalDate.of(1850,12,1); + Object o = type.toJdbcType(localDate); + LocalDate localDate1 = type.toBeanType(o); + assertThat(localDate1).isEqualTo(localDate); + } + @Test public void testToBeanType() { 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 9cd59bf23..515540ea3 100644 --- a/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java +++ b/ebean-test/src/test/java/org/tests/update/TestSqlUpdateUpsert.java @@ -39,7 +39,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { .setParameter("online", false); Object key2 = sqlUpdate2.executeGetKey(); - assertThat(key2).isNull(); + assertThat(key2).isEqualTo(key); EPersonOnline found2 = DB.find(EPersonOnline.class).where().eq("email", email).findOne(); 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 fc3905d89..e7de38588 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ com.h2database h2 - 2.0.202 + 2.1.210 test From 7733e9382cb054a98b32f53b06cea89ed4e78f2e Mon Sep 17 00:00:00 2001 From: Noemi Szemenyei Date: Tue, 25 Jan 2022 08:52:21 +0100 Subject: [PATCH 30/47] ADD: failing test with select distinct with composite key and T0.NULL (cherry picked from commit a08ba194b790c69c28b0907c87d378f22b565cca) --- ...ascadeDeleteChildrenWithCompositeKeys.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java b/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java index e637a0465..575671952 100644 --- a/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java +++ b/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java @@ -1,7 +1,9 @@ package org.tests.compositekeys; import io.ebean.BaseTestCase; +import io.ebean.CountDistinctOrder; import io.ebean.DB; +import io.ebean.Query; import io.ebean.annotation.Identity; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.server.deploy.BeanDescriptor; @@ -16,6 +18,7 @@ import java.util.List; import java.util.Set; import static io.ebean.annotation.IdentityGenerated.BY_DEFAULT; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -82,6 +85,31 @@ public class TestOnCascadeDeleteChildrenWithCompositeKeys extends BaseTestCase { beanProperty.findIdsByParentId(null, ids, null, null, true); beanProperty.findIdsByParentId(1L, null, null, null, true); } + + /** + * Test makes select and a select distinct of entities with composite keys. + */ + @Test + public void testSelectDistinctCountWithCompositeKey() { + + // first query with a simple findList + Query query1 = DB.find(UserRole.class); + query1.findList(); + + assertThat(query1.getGeneratedSql()).contains("select t0.user_id, t0.role_id, t0.user_id, t0.role_id from em_user_role t0"); + + // second query with count distinct + query1 = DB.find(UserRole.class); + query1.select(""); + query1.fetch("user", "name"); + query1.setDistinct(true).setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC).setMaxRows(20); + query1.findSingleAttributeList(); + + assertThat(query1.getGeneratedSql()).contains("select distinct r1.attribute_, count(*) from " + + "(select distinct t0.user_id, t0.role_id, t1.name as attribute_ " + + "from em_user_role t0 join em_user t1 on t1.id = t0.user_id) r1 " + + "group by r1.attribute_ order by count(*) desc, r1.attribute_ limit 20"); + } @Identity(generated = BY_DEFAULT) @Entity From dd26dc342d9bc16657548c199bb24a7b77ecce41 Mon Sep 17 00:00:00 2001 From: Noemi Szemenyei Date: Tue, 25 Jan 2022 08:53:21 +0100 Subject: [PATCH 31/47] FIX: select properties of the embedded Id (cherry picked from commit 58e952b1ec9125dfccedcb04485913fbcc67932f) --- .../io/ebeaninternal/server/query/CQueryBuilder.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 278603f5b..45657fb9c 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -568,8 +568,16 @@ final class CQueryBuilder { if (countSingleAttribute) { sb.append("r1.attribute_, count(*) from (select "); if (distinct) { - sb.append("distinct t0."); - sb.append(request.descriptor().idProperty().dbColumn()).append(", "); + sb.append("distinct "); + BeanProperty idProp = request.descriptor().idProperty(); + if (idProp.isEmbedded()) { + BeanProperty[] props = ((BeanPropertyAssocOne) idProp).properties(); + for (BeanProperty prop : props) { + sb.append("t0.").append(prop.dbColumn()).append(", "); + } + } else { + sb.append("t0.").append(idProp.dbColumn()).append(", "); + } } sb.append(select.getSelectSql()).append(" as attribute_"); } else { From 5cb486c74572671346f532e60270994bcbbd5a25 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 14:18:02 +1300 Subject: [PATCH 32/47] CI Build without maven cache --- .github/workflows/build.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf03d3b50..2bb559ac1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,14 +23,14 @@ jobs: with: java-version: ${{ matrix.java_version }} distribution: 'zulu' - - name: Maven cache - uses: actions/cache@v2 - env: - cache-name: maven-cache - with: - path: - ~/.m2 - key: build-${{ env.cache-name }} +# - name: Maven cache +# uses: actions/cache@v2 +# env: +# cache-name: maven-cache +# with: +# path: +# ~/.m2 +# key: build-${{ env.cache-name }} - name: Build with Maven - run: mvn package + run: mvn clean package From 4a8231a6ccad66b2a73be4478a3939e53bafad19 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 14:38:52 +1300 Subject: [PATCH 33/47] CI Build using adopt distribution --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2bb559ac1..0cd698dc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,8 @@ jobs: uses: actions/setup-java@v2 with: java-version: ${{ matrix.java_version }} - distribution: 'zulu' +# distribution: 'zulu' + distribution: 'adopt' # - name: Maven cache # uses: actions/cache@v2 # env: @@ -32,5 +33,5 @@ jobs: # ~/.m2 # key: build-${{ env.cache-name }} - name: Build with Maven - run: mvn clean package + run: mvn --batch-mode clean package From fa561e51974bf5ae6c506a2d19479eb85f3b9f95 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 14:52:32 +1300 Subject: [PATCH 34/47] CI Build with single test and bump enhancement tiles --- .github/workflows/build.yml | 6 +++++- 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 | 2 +- tests/test-kotlin/pom.xml | 2 +- 9 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0cd698dc0..3c38cb55e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,6 +32,10 @@ jobs: # path: # ~/.m2 # key: build-${{ env.cache-name }} + - name: Maven version + run: mvn --version + - name: Maven single test + run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false - name: Build with Maven - run: mvn --batch-mode clean package + run: mvn --batch-mode clean verify diff --git a/ebean-autotune/pom.xml b/ebean-autotune/pom.xml index 9dbe36921..835b74dbe 100644 --- a/ebean-autotune/pom.xml +++ b/ebean-autotune/pom.xml @@ -63,7 +63,7 @@ true - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-externalmapping-xml/pom.xml b/ebean-externalmapping-xml/pom.xml index 94047ec2e..f7568dc73 100644 --- a/ebean-externalmapping-xml/pom.xml +++ b/ebean-externalmapping-xml/pom.xml @@ -89,7 +89,7 @@ - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-kotlin/pom.xml b/ebean-kotlin/pom.xml index 35923973c..8d8a3d3b9 100644 --- a/ebean-kotlin/pom.xml +++ b/ebean-kotlin/pom.xml @@ -14,7 +14,7 @@ 1.8 1.8 - 12.13.0 + 12.14.1 1.6.0 diff --git a/ebean-postgis/pom.xml b/ebean-postgis/pom.xml index ac4553b77..caa1ccf81 100644 --- a/ebean-postgis/pom.xml +++ b/ebean-postgis/pom.xml @@ -105,7 +105,7 @@ true - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index 6ecbfafad..210e2249e 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -100,7 +100,7 @@ true - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index e811c97ad..f33064c74 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -80,7 +80,7 @@ true - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index a11b27133..b837a02d1 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -249,7 +249,7 @@ true - io.ebean.tile:enhancement:12.11.3 + io.ebean.tile:enhancement:12.14.1 io.avaje.tile:moditech-module:1.0 diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index ab8706f74..6bc7e47c7 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -19,7 +19,7 @@ 11 11 - 12.13.0 + 12.14.1 1.6.0 2.12.1 true From a1d6b280bca68190573d0b45b200796de3355cd2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 14:58:38 +1300 Subject: [PATCH 35/47] Bump test parent poms --- tests/pom.xml | 2 +- tests/test-kotlin/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pom.xml b/tests/pom.xml index b3592f647..ac7678298 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -4,7 +4,7 @@ org.avaje java8-oss - 2.3 + 3.3 diff --git a/tests/test-kotlin/pom.xml b/tests/test-kotlin/pom.xml index 6bc7e47c7..c4138a900 100644 --- a/tests/test-kotlin/pom.xml +++ b/tests/test-kotlin/pom.xml @@ -6,7 +6,7 @@ org.avaje java11-oss - 2.3 + 3.4 From 1a54fc12adf0ad3b3d30269892ab68fbd9d3d8b6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 15:48:03 +1300 Subject: [PATCH 36/47] Test logging enabled for investigating CI Build issue --- ebean-test/src/test/resources/logback-test.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ebean-test/src/test/resources/logback-test.xml b/ebean-test/src/test/resources/logback-test.xml index bfe4a1ede..f280298f8 100644 --- a/ebean-test/src/test/resources/logback-test.xml +++ b/ebean-test/src/test/resources/logback-test.xml @@ -79,11 +79,11 @@ - - + + - + From 2f824c99ea894bd9a5473fc9eb3fa2e381e7e96a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 16:53:38 +1300 Subject: [PATCH 37/47] Fix issues with test ordering --- .../server/core/DefaultServer_getReferenceTest.java | 4 ++-- .../server/deploy/BeanPropertyAssocManyTest.java | 11 +++++++---- .../tests/batchinsert/TestBatchSaveWithGetBeanId.java | 2 ++ .../java/org/tests/insert/TestInsertCollection.java | 8 +++++++- .../tests/query/other/TestQuerySingleAttribute.java | 6 +++--- .../java/org/tests/update/TestStatelessUpdate.java | 7 +++++++ .../test/java/org/tests/update/TestUpdatePartial.java | 7 +++++++ 7 files changed, 35 insertions(+), 10 deletions(-) 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 bbf2786b4..e638d9d00 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 @@ -24,8 +24,8 @@ public class DefaultServer_getReferenceTest extends BaseTestCase { ResetBasicData.reset(); DB.execute(() -> { - Customer loaded = DB.find(Customer.class, 1); - Customer reference = DB.reference(Customer.class, 1); + Customer loaded = DB.find(Customer.class).where().eq("name", "Rob").findOne(); + Customer reference = DB.reference(Customer.class, loaded.getId()); assertThat(loaded).isSameAs(reference); }); } diff --git a/ebean-test/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java b/ebean-test/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java index c63966f21..eadc01968 100644 --- a/ebean-test/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java +++ b/ebean-test/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; +import io.ebean.DB; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebean.common.BeanList; @@ -66,11 +67,13 @@ public class BeanPropertyAssocManyTest extends BaseTestCase { ResetBasicData.reset(); - List customerIds = new ArrayList<>(); - customerIds.add(1L); - customerIds.add(2L); + List ids = DB.find(Customer.class).orderBy("id").setMaxRows(2).findIds(); - List contactIdsForOne = contacts().findIdsByParentId(1L, null, null, null, true); + List customerIds = new ArrayList<>(); + customerIds.add(ids.get(0)); + customerIds.add(ids.get(1)); + + List contactIdsForOne = contacts().findIdsByParentId(ids.get(0), null, null, null, true); List contactIdsForMultiple = contacts().findIdsByParentId(null, customerIds, null, null, true); diff --git a/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java b/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java index 7239731d5..029bac16f 100644 --- a/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java +++ b/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java @@ -8,6 +8,7 @@ import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; +import org.tests.model.basic.ResetBasicData; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -22,6 +23,7 @@ public class TestBatchSaveWithGetBeanId extends BaseTestCase { @Test @IgnorePlatform(Platform.HANA) // HANA doesn't support insert batching public void test() { + ResetBasicData.reset(); Database server = DB.getDefault(); Customer model = new Customer(); diff --git a/ebean-test/src/test/java/org/tests/insert/TestInsertCollection.java b/ebean-test/src/test/java/org/tests/insert/TestInsertCollection.java index 0d3679d91..773bffb02 100644 --- a/ebean-test/src/test/java/org/tests/insert/TestInsertCollection.java +++ b/ebean-test/src/test/java/org/tests/insert/TestInsertCollection.java @@ -2,8 +2,10 @@ package org.tests.insert; import io.ebean.BaseTestCase; import io.ebean.DB; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; +import org.tests.model.basic.ResetBasicData; import java.util.ArrayList; import java.util.List; @@ -12,9 +14,13 @@ import static org.junit.jupiter.api.Assertions.*; public class TestInsertCollection extends BaseTestCase { + @BeforeAll + static void before() { + ResetBasicData.reset(); + } + @Test public void test() { - Customer cust1 = new Customer(); cust1.setName("jim"); 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 43f7162cb..8329e0d1e 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 @@ -131,7 +131,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { Query query = DB.find(Customer.class) .select("name") - .where().eq("id", 1).query(); + .where().eq("name", "Rob").query(); String name = query.findSingleAttribute(); @@ -248,7 +248,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { String name = DB.find(Customer.class) .select("name") - .where().eq("id", 1) + .where().eq("name", "Rob") .findSingleAttribute(); assertThat(name).isNotNull(); @@ -646,7 +646,7 @@ public class TestQuerySingleAttribute extends BaseTestCase { .findSingleAttributeList(); assertThat(list1.get(0)).isInstanceOf(CountedValue.class); //assertThat(list1.toString()).isEqualTo("[1: Tracy, 3: Jim1, 1: Jack, 3: Fred1, 1: Fiona, 3: Bugs1]"); - + query = DB.find(Contact.class).select("firstName"); list1 = query .setCountDistinct(CountDistinctOrder.NO_ORDERING) diff --git a/ebean-test/src/test/java/org/tests/update/TestStatelessUpdate.java b/ebean-test/src/test/java/org/tests/update/TestStatelessUpdate.java index e8243bdd1..d03da5ffb 100644 --- a/ebean-test/src/test/java/org/tests/update/TestStatelessUpdate.java +++ b/ebean-test/src/test/java/org/tests/update/TestStatelessUpdate.java @@ -3,11 +3,13 @@ package org.tests.update; import io.ebean.DB; import io.ebean.TransactionalTestCase; import io.ebean.test.LoggedSql; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.tests.model.basic.Contact; import org.tests.model.basic.Customer; import org.tests.model.basic.EBasic; import org.tests.model.basic.EBasic.Status; +import org.tests.model.basic.ResetBasicData; import javax.persistence.EntityNotFoundException; import java.util.*; @@ -17,6 +19,11 @@ import static org.junit.jupiter.api.Assertions.*; public class TestStatelessUpdate extends TransactionalTestCase { + @BeforeAll + static void before() { + ResetBasicData.reset(); + } + @Test public void test() { diff --git a/ebean-test/src/test/java/org/tests/update/TestUpdatePartial.java b/ebean-test/src/test/java/org/tests/update/TestUpdatePartial.java index 978ef0589..e4fecaed8 100644 --- a/ebean-test/src/test/java/org/tests/update/TestUpdatePartial.java +++ b/ebean-test/src/test/java/org/tests/update/TestUpdatePartial.java @@ -3,14 +3,21 @@ package org.tests.update; import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.SqlRow; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; +import org.tests.model.basic.ResetBasicData; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; public class TestUpdatePartial extends BaseTestCase { + @BeforeAll + static void before() { + ResetBasicData.reset(); + } + @Test public void test() { From 774cab327d1063497cac631c347787f46f970d72 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 17:23:18 +1300 Subject: [PATCH 38/47] Fix issues with test ordering - ordering in ResetBasicData --- .../src/test/java/org/tests/model/basic/ResetBasicData.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java b/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java index 6a01db649..80260a350 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java +++ b/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java @@ -2,6 +2,7 @@ package org.tests.model.basic; import io.ebean.DB; import io.ebean.Database; +import io.ebean.Transaction; import org.tests.model.basic.Order.Status; import java.sql.Date; @@ -47,6 +48,7 @@ public class ResetBasicData { // the test rely on the products being in there return; } + Transaction.current().setBatchMode(false); //me.deleteAll(); me.insertCountries(); me.insertProducts(); From dcf60a3d1c73c469c5b0666f8c8bf708a90f82a4 Mon Sep 17 00:00:00 2001 From: Noemi Szemenyei Date: Wed, 26 Jan 2022 08:09:42 +0100 Subject: [PATCH 39/47] Trigger Build From 008e1849a25e7f809baaf04d3b50fe166598ec6f Mon Sep 17 00:00:00 2001 From: Noemi Szemenyei Date: Wed, 26 Jan 2022 08:25:38 +0100 Subject: [PATCH 40/47] FIX: other queries for other platforms --- ...ascadeDeleteChildrenWithCompositeKeys.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java b/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java index 575671952..bddc156bb 100644 --- a/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java +++ b/ebean-test/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java @@ -5,6 +5,7 @@ import io.ebean.CountDistinctOrder; import io.ebean.DB; import io.ebean.Query; import io.ebean.annotation.Identity; +import io.ebean.annotation.Platform; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; @@ -105,10 +106,23 @@ public class TestOnCascadeDeleteChildrenWithCompositeKeys extends BaseTestCase { query1.setDistinct(true).setCountDistinct(CountDistinctOrder.COUNT_DESC_ATTR_ASC).setMaxRows(20); query1.findSingleAttributeList(); - assertThat(query1.getGeneratedSql()).contains("select distinct r1.attribute_, count(*) from " - + "(select distinct t0.user_id, t0.role_id, t1.name as attribute_ " - + "from em_user_role t0 join em_user t1 on t1.id = t0.user_id) r1 " - + "group by r1.attribute_ order by count(*) desc, r1.attribute_ limit 20"); + if (isH2() || isMariaDB() || isPostgres()) { + assertThat(query1.getGeneratedSql()).contains("select distinct r1.attribute_, count(*) from " + + "(select distinct t0.user_id, t0.role_id, t1.name as attribute_ " + + "from em_user_role t0 join em_user t1 on t1.id = t0.user_id) r1 " + + "group by r1.attribute_ order by count(*) desc, r1.attribute_ limit 20"); + } else if (isDb2()) { + assertThat(query1.getGeneratedSql()).contains("select distinct r1.attribute_, count(*) from " + + "(select distinct t0.user_id, t0.role_id, t1.name as attribute_ " + + "from em_user_role t0 join em_user t1 on t1.id = t0.user_id) r1 " + + "group by r1.attribute_ order by count(*) desc, r1.attribute_ fetch next 20 rows only"); + } else if (isSqlServer()) { + assertThat(query1.getGeneratedSql()).contains("select distinct top 20 r1.attribute_, count(*) " + + "from (select distinct t0.user_id, t0.role_id, t1.name as attribute_ from em_user_role t0 " + + "join em_user t1 on t1.id = t0.user_id) r1 group by r1.attribute_ order by count(*) desc, r1.attribute_"); + } else { + // no Oracle test yet + } } @Identity(generated = BY_DEFAULT) From 7e0ac5a73a080a0c0578a00b992aedda16de5df9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 21:47:00 +1300 Subject: [PATCH 41/47] Fix issues with tests - tidy ResetBasicData --- .../TestBatchSaveWithGetBeanId.java | 8 +- .../org/tests/model/basic/ResetBasicData.java | 142 +++++------------- 2 files changed, 42 insertions(+), 108 deletions(-) diff --git a/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java b/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java index 029bac16f..7495f8560 100644 --- a/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java +++ b/ebean-test/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java @@ -6,6 +6,7 @@ import io.ebean.Database; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; @@ -14,6 +15,11 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; public class TestBatchSaveWithGetBeanId extends BaseTestCase { + @BeforeAll + static void before() { + ResetBasicData.reset(); + } + /** * Making this transaction with batchSize means that the insert * below does not occur immediately ... and the getBeanId() @@ -23,8 +29,6 @@ public class TestBatchSaveWithGetBeanId extends BaseTestCase { @Test @IgnorePlatform(Platform.HANA) // HANA doesn't support insert batching public void test() { - ResetBasicData.reset(); - Database server = DB.getDefault(); Customer model = new Customer(); model.setName("foo"); diff --git a/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java b/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java index 80260a350..819bc406c 100644 --- a/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java +++ b/ebean-test/src/test/java/org/tests/model/basic/ResetBasicData.java @@ -58,100 +58,55 @@ public class ResetBasicData { } - public void deleteAll() { - DB.execute(() -> { + private void insertCountries() { + Country c = new Country(); + c.setCode("NZ"); + c.setName("New Zealand"); + server.save(c); - // orm update use bean name and bean properties - server.sqlUpdate("delete from o_cached_bean_child").execute(); - server.sqlUpdate("delete from o_cached_bean_country").execute(); - server.sqlUpdate("delete from o_cached_bean").execute(); - - server.createUpdate(OrderShipment.class, "delete from orderShipment").execute(); - - server.createUpdate(OrderDetail.class, "delete from orderDetail").execute(); - - server.createUpdate(Order.class, "delete from order").execute(); - - server.createUpdate(Contact.class, "delete from contact").execute(); - - server.createUpdate(Customer.class, "delete from Customer").execute(); - - server.createUpdate(Address.class, "delete from address").execute(); - - // sql update uses table and column names - server.sqlUpdate("delete from o_country").execute(); - server.sqlUpdate("delete from o_product").execute(); - - }); + Country au = new Country(); + au.setCode("AU"); + au.setName("Australia"); + server.save(au); } - public void insertCountries() { + private void insertProducts() { + Product p = new Product(); + p.setName("Chair"); + p.setSku("C001"); + server.save(p); - if (server.find(Country.class).findCount() > 0) { - return; - } + p = new Product(); + p.setName("Desk"); + p.setSku("DSK1"); + server.save(p); - server.execute(() -> { - Country c = new Country(); - c.setCode("NZ"); - c.setName("New Zealand"); - server.save(c); + p = new Product(); + p.setName("Computer"); + p.setSku("C002"); + server.save(p); - Country au = new Country(); - au.setCode("AU"); - au.setName("Australia"); - server.save(au); - }); + p = new Product(); + p.setName("Printer"); + p.setSku("C003"); + server.save(p); } + private void insertTestCustAndOrders() { + Customer cust1 = insertCustomer("Rob"); + Customer cust2 = insertCustomerNoAddress(); + insertCustomerFiona(); + insertCustomerNoContacts("NocCust"); - public void insertProducts() { - - if (server.find(Product.class).findCount() > 0) { - return; - } - server.execute(() -> { - Product p = new Product(); - p.setName("Chair"); - p.setSku("C001"); - server.save(p); - - p = new Product(); - p.setName("Desk"); - p.setSku("DSK1"); - server.save(p); - - p = new Product(); - p.setName("Computer"); - p.setSku("C002"); - server.save(p); - - p = new Product(); - p.setName("Printer"); - p.setSku("C003"); - server.save(p); - }); - } - - public void insertTestCustAndOrders() { - - DB.execute(() -> { - Customer cust1 = insertCustomer("Rob"); - Customer cust2 = insertCustomerNoAddress(); - insertCustomerFiona(); - insertCustomerNoContacts("NocCust"); - - createOrder1(cust1); - createOrder2(cust2); - createOrder3(cust1); - createOrder4(cust1); - createOrder5(cust2); - }); + createOrder1(cust1); + createOrder2(cust2); + createOrder3(cust1); + createOrder4(cust1); + createOrder5(cust2); } public static Customer createCustAndOrder(String custName) { - ResetBasicData me = new ResetBasicData(); Customer cust1 = insertCustomer(custName); me.createOrder1(cust1); @@ -159,7 +114,6 @@ public class ResetBasicData { } public static Order createOrderCustAndOrder(String custName) { - ResetBasicData me = new ResetBasicData(); Customer cust1 = insertCustomer(custName); return me.createOrder1(cust1); @@ -168,10 +122,8 @@ public class ResetBasicData { private static int contactEmailNum = 1; private Customer insertCustomerFiona() { - Customer c = createCustomer("Fiona", "12 Apple St", "West Coast Rd", 1, "2009-08-31"); c.setStatus(Customer.Status.ACTIVE); - c.addContact(createContact("Fiona", "Black")); c.addContact(createContact("Tracy", "Red")); @@ -187,22 +139,18 @@ public class ResetBasicData { } private Customer insertCustomerNoContacts(String name) { - Customer c = createCustomer("Roger", "15 Kumera Way", "Bos town", 1, "2010-04-10"); c.setName(name); c.setStatus(Customer.Status.ACTIVE); - DB.save(c); return c; } private Customer insertCustomerNoAddress() { - Customer c = new Customer(); c.setName("Cust NoAddress"); c.setStatus(Customer.Status.NEW); c.addContact(createContact("Jack", "Black")); - DB.save(c); return c; } @@ -218,7 +166,6 @@ public class ResetBasicData { } public static Customer createCustomer(String name, String shippingStreet, String billingStreet, int contactSuffix, String annDate) { - Customer c = new Customer(); c.setName(name); c.setStatus(Customer.Status.NEW); @@ -253,17 +200,14 @@ public class ResetBasicData { c.setBillingAddress(billingAddr); } - return c; } private Order createOrder1(Customer customer) { - Product product1 = DB.reference(Product.class, 1); Product product2 = DB.reference(Product.class, 2); Product product3 = DB.reference(Product.class, 3); - Order order = new Order(); order.setCustomer(customer); order.setOrderDate(Date.valueOf("2018-07-01")); @@ -273,16 +217,12 @@ public class ResetBasicData { details.add(new OrderDetail(product2, 3, 1.10)); details.add(new OrderDetail(product3, 1, 2.00)); order.setDetails(details); - - order.addShipment(new OrderShipment()); - DB.save(order); return order; } private void createOrder2(Customer customer) { - Product product1 = DB.reference(Product.class, 1); Order order = new Order(); @@ -293,14 +233,11 @@ public class ResetBasicData { List details = new ArrayList<>(); details.add(new OrderDetail(product1, 4, 10.50)); order.setDetails(details); - order.addShipment(new OrderShipment()); - DB.save(order); } private void createOrder3(Customer customer) { - Product product1 = DB.reference(Product.class, 1); Product product3 = DB.reference(Product.class, 3); @@ -314,30 +251,23 @@ public class ResetBasicData { details.add(new OrderDetail(product3, 40, 2.10)); details.add(new OrderDetail(product1, 5, 10.00)); order.setDetails(details); - order.addShipment(new OrderShipment()); - DB.save(order); } private void createOrder4(Customer customer) { - Order order = new Order(); order.setCustomer(customer); order.setOrderDate(Date.valueOf("2018-07-04")); - order.addShipment(new OrderShipment()); - DB.save(order); } private void createOrder5(Customer customer) { - Order order = new Order(); order.setCustomer(customer); order.setOrderDate(Date.valueOf("2018-06-28")); order.addShipment(new OrderShipment()); - DB.save(order); } } From 5466c6a350872e00f95fa74fba53dffe047a9443 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 21:51:48 +1300 Subject: [PATCH 42/47] Reduce logging when running Build tests --- .github/workflows/build.yml | 25 +++++++++---------- .../src/test/resources/logback-test.xml | 6 ++--- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c38cb55e..5e3fafdd4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,20 +22,19 @@ jobs: uses: actions/setup-java@v2 with: java-version: ${{ matrix.java_version }} -# distribution: 'zulu' - distribution: 'adopt' -# - name: Maven cache -# uses: actions/cache@v2 -# env: -# cache-name: maven-cache -# with: -# path: -# ~/.m2 -# key: build-${{ env.cache-name }} + distribution: 'zulu' + - name: Maven cache + uses: actions/cache@v2 + env: + cache-name: maven-cache + with: + path: + ~/.m2 + key: build-${{ env.cache-name }} - name: Maven version run: mvn --version - - name: Maven single test - run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false +# - name: Maven single test +# run: mvn --batch-mode clean verify -Dtest="io.ebeaninternal.server.core.DefaultServer_getReferenceTest" -DfailIfNoTests=false - name: Build with Maven - run: mvn --batch-mode clean verify + run: mvn clean package diff --git a/ebean-test/src/test/resources/logback-test.xml b/ebean-test/src/test/resources/logback-test.xml index f280298f8..bfe4a1ede 100644 --- a/ebean-test/src/test/resources/logback-test.xml +++ b/ebean-test/src/test/resources/logback-test.xml @@ -79,11 +79,11 @@ - - + + - + From ffdafc796ba7218138eb098d13f32c2f0d65714e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 21:54:19 +1300 Subject: [PATCH 43/47] Touch README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 30dc2c06b..a560d8c82 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,3 @@ Goto [https://ebean.io/docs/](https://ebean.io/docs/) [Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects") -## Other versions -* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent -* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin From 86768dfe4d72c89774395e1e1b3db57f4881cc7d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 21:57:41 +1300 Subject: [PATCH 44/47] Touch application-test.properties --- .../src/test/resources/application-test.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties index 5b7b35ed3..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.databaseUrl=jdbc:h2:mem:tests;NON_KEYWORDS=KEY +datasource.h2.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY datasource.pg.username=sa datasource.pg.password= -datasource.pg.databaseUrl=jdbc:h2:mem:tests;NON_KEYWORDS=KEY +datasource.pg.url=jdbc:h2:mem:tests;NON_KEYWORDS=KEY From 23061473c7a8905c4a3d92eee17d2b853fc44bb3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 25 Jan 2022 13:44:23 +1300 Subject: [PATCH 45/47] Refactor internals split result load functionality from SqlTreeNode into SqlTreeLoad --- .../io/ebeaninternal/server/query/CQuery.java | 2 +- .../server/query/CQueryBuilder.java | 8 +- .../server/query/CQueryPlan.java | 8 +- .../server/query/CQueryPlanRawSql.java | 2 +- .../ebeaninternal/server/query/SqlTree.java | 14 +- .../server/query/SqlTreeLoad.java | 28 ++ .../server/query/SqlTreeLoadBean.java | 373 ++++++++++++++++++ .../server/query/SqlTreeLoadManyRoot.java | 30 ++ .../server/query/SqlTreeLoadRoot.java | 43 ++ .../server/query/SqlTreeNode.java | 24 +- .../server/query/SqlTreeNodeBean.java | 365 ++--------------- .../server/query/SqlTreeNodeExtraJoin.java | 18 +- .../query/SqlTreeNodeFormulaWhereJoin.java | 14 +- .../server/query/SqlTreeNodeManyRoot.java | 22 +- .../query/SqlTreeNodeManyWhereJoin.java | 17 +- .../server/query/SqlTreeNodeRoot.java | 30 +- .../server/query/SqlTreePlan.java | 41 ++ 17 files changed, 588 insertions(+), 451 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java 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 45a5b5a11..1870c1b6f 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 @@ -193,7 +193,7 @@ public final class CQuery implements DbReadContext, CancelableQuery, SpiProfi // set the generated sql back to the query // so its available to the user... query.setGeneratedSql(queryPlan.getSql()); - SqlTree sqlTree = queryPlan.getSqlTree(); + SqlTreePlan sqlTree = queryPlan.getSqlTree(); this.rootNode = sqlTree.getRootNode(); this.manyProperty = sqlTree.getManyProperty(); this.sql = queryPlan.getSql(); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 278603f5b..3367fbfe4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -110,7 +110,7 @@ final class CQueryBuilder { sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree); } // cache the query plan - queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryUpdate(request, predicates, queryPlan); } @@ -197,7 +197,7 @@ final class CQueryBuilder { SqlTree sqlTree = createSqlTree(request, predicates); SqlLimitResponse s = buildSql(null, request, predicates, sqlTree); - queryPlan = new CQueryPlan(request, s.getSql(), sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, s.getSql(), sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryFetchSingleAttribute(request, predicates, queryPlan, query.isCountDistinct()); } @@ -288,7 +288,7 @@ final class CQueryBuilder { } } // cache the query plan - queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, sql, sqlTree.plan(), predicates.getLogWhereSql()); request.putQueryPlan(queryPlan); return new CQueryRowCount(queryPlan, request, predicates); } @@ -343,7 +343,7 @@ final class CQueryBuilder { if (rawSql) { queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql()); } else { - queryPlan = new CQueryPlan(request, res, sqlTree, false, predicates.getLogWhereSql()); + queryPlan = new CQueryPlan(request, res, sqlTree.plan(), false, predicates.getLogWhereSql()); } BeanDescriptor desc = request.descriptor(); if (desc.isReadAuditing()) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java index bf84070f2..d07276920 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java @@ -55,7 +55,7 @@ public class CQueryPlan implements SpiQueryPlan { private final String sql; private final String hash; private final String logWhereSql; - private final SqlTree sqlTree; + private final SqlTreePlan sqlTree; /** * Encrypted properties required additional binding. @@ -76,7 +76,7 @@ public class CQueryPlan implements SpiQueryPlan { /** * Create a query plan based on a OrmQueryRequest. */ - CQueryPlan(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTree sqlTree, boolean rawSql, String logWhereSql) { + CQueryPlan(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTreePlan sqlTree, boolean rawSql, String logWhereSql) { this.server = request.server(); this.dataTimeZone = server.dataTimeZone(); this.beanType = request.descriptor().type(); @@ -101,7 +101,7 @@ public class CQueryPlan implements SpiQueryPlan { /** * Create a query plan for a raw sql query. */ - CQueryPlan(OrmQueryRequest request, String sql, SqlTree sqlTree, String logWhereSql) { + CQueryPlan(OrmQueryRequest request, String sql, SqlTreePlan sqlTree, String logWhereSql) { this.server = request.server(); this.dataTimeZone = server.dataTimeZone(); this.beanType = request.descriptor().type(); @@ -249,7 +249,7 @@ public class CQueryPlan implements SpiQueryPlan { return rawSql ? planKey.getPartialKey() + "_" + hash : planKey.getPartialKey(); } - final SqlTree getSqlTree() { + final SqlTreePlan getSqlTree() { return sqlTree; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java index f35702ee1..935f730ec 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryPlanRawSql.java @@ -17,7 +17,7 @@ final class CQueryPlanRawSql extends CQueryPlan { private final int[] rsetIndexPositions; CQueryPlanRawSql(OrmQueryRequest request, SqlLimitResponse sqlRes, SqlTree sqlTree, String logWhereSql) { - super(request, sqlRes, sqlTree, true, logWhereSql); + super(request, sqlRes, sqlTree.plan(), true, logWhereSql); this.rsetIndexPositions = createIndexPositions(request, sqlTree); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java index 27e35c365..5b11be657 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTree.java @@ -56,6 +56,10 @@ final class SqlTree { this.noJoins = !includeJoins; } + SqlTreePlan plan() { + return new SqlTreePlan(rootNode.createLoad(), manyProperty, encryptedProps, dependentTables()); + } + /** * Return true if the query mandates SQL Distinct due to ToMany inclusion. */ @@ -123,10 +127,6 @@ final class SqlTree { return inheritanceWhereSql; } - SqlTreeRoot getRootNode() { - return (SqlTreeRoot)rootNode; - } - /** * Return the property that is associated with the many. There can only be one * per SqlSelect. This can be null. @@ -135,10 +135,6 @@ final class SqlTree { return manyProperty; } - STreeProperty[] getEncryptedProps() { - return encryptedProps; - } - /** * Return true if the query has a many join. */ @@ -153,7 +149,7 @@ final class SqlTree { /** * Return the tables that are joined in this query. */ - Set dependentTables() { + private Set dependentTables() { Set tables = new LinkedHashSet<>(); rootNode.dependentTables(tables); return tables; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java new file mode 100644 index 000000000..c5ac129b1 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoad.java @@ -0,0 +1,28 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebean.core.type.ScalarDataReader; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; + +/** + * Tree node that loads an entity bean type. + */ +interface SqlTreeLoad { + + /** + * Load the appropriate information from the SqlSelectReader. + *

+ * At a high level this actually controls the reading of the data from the + * jdbc resultSet and putting it into the bean etc. + *

+ */ + EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException; + + /** + * Return the reader for the single attribute query. + */ + ScalarDataReader getSingleAttributeReader(); + +} 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 new file mode 100644 index 000000000..516a00537 --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadBean.java @@ -0,0 +1,373 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; +import io.ebean.bean.PersistenceContext; +import io.ebean.core.type.ScalarDataReader; +import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.api.SpiQuery.Mode; +import io.ebeaninternal.server.deploy.DbReadContext; +import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.id.IdBinder; + +import java.sql.SQLException; +import java.util.Map; + +/** + * Normal bean included in the query. + */ +class SqlTreeLoadBean implements SqlTreeLoad { + + final STreeType desc; + final IdBinder idBinder; + final SqlTreeLoad[] children; + private final boolean partialObject; + private final STreeProperty[] properties; + private final STreePropertyAssoc nodeBeanProp; + final boolean readId; + private final boolean readIdNormal; + private final boolean disableLazyLoad; + private final InheritInfo inheritInfo; + final String prefix; + private final Map pathMap; + final STreePropertyAssocMany lazyLoadParent; + private final SpiQuery.TemporalMode temporalMode; + private final boolean temporalVersions; + final IdBinder lazyLoadParentIdBinder; + + SqlTreeLoadBean(SqlTreeNodeBean node) { + this.lazyLoadParent = node.lazyLoadParent; + this.lazyLoadParentIdBinder = node.lazyLoadParentIdBinder; + this.prefix = node.prefix; + this.desc = node.desc; + this.inheritInfo = desc.inheritInfo(); + this.idBinder = desc.idBinder(); + this.temporalMode = node.temporalMode; + this.temporalVersions = node.temporalVersions; + this.nodeBeanProp = node.nodeBeanProp; + this.readId = node.readId;//!aggregationRoot && withId && desc.hasId(); + 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.children = node.createLoadChildren(); + } + + boolean isRoot() { + return false; + } + + @Override + public final ScalarDataReader getSingleAttributeReader() { + if (properties == null || properties.length == 0) { + // if we have no property ask first children (in a distinct select with join) + if (children.length == 0) { + // expected to be a findIds query + return desc.idBinder().getBeanProperty(); + } + return children[0].getSingleAttributeReader(); + } + if (properties[0] instanceof STreePropertyAssocOne) { + STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0]; + if (assocOne.isAssocId()) { + return assocOne.idReader(); + } + } + return properties[0]; + } + + /** + * Load that takes into account inheritance. + */ + private final class LoadInherit extends Load { + + private LoadInherit(DbReadContext ctx, EntityBean parentBean) { + super(ctx, parentBean); + } + + @Override + void initBeanType() throws SQLException { + InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo(); + if (localInfo == null) { + // the bean must be null + localIdBinder = idBinder; + localDesc = desc; + } else { + localBean = localInfo.createEntityBean(); + localType = localInfo.getType(); + localIdBinder = localInfo.getIdBinder(); + localDesc = localInfo.desc(); + } + } + + @Override + void loadProperties() { + // take account of inheritance + for (STreeProperty property : properties) { + localDesc.inheritanceLoad(sqlBeanLoad, property, ctx); + } + } + } + + /** + * Load a bean instance. + */ + class Load { + + final DbReadContext ctx; + final EntityBean parentBean; + + Object lazyLoadParentId; + Class localType; + STreeType localDesc; + IdBinder localIdBinder; + EntityBean localBean; + + Mode queryMode; + PersistenceContext persistenceContext; + Object id; + EntityBean contextBean; + SqlBeanLoad sqlBeanLoad; + boolean lazyLoadMany; + + private Load(DbReadContext ctx, EntityBean parentBean) { + this.ctx = ctx; + this.parentBean = parentBean; + } + + private void initLazyParent() throws SQLException { + if (lazyLoadParentIdBinder != null) { + lazyLoadParentId = lazyLoadParentIdBinder.read(ctx); + } + } + + void initBeanType() throws SQLException { + localDesc = desc; + localBean = desc.createEntityBean(); + localIdBinder = idBinder; + } + + private void initPersistenceContext() { + queryMode = ctx.getQueryMode(); + persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext(); + } + + private void readId() throws SQLException { + if (readId) { + id = localIdBinder.readSet(ctx, localBean); + if (id == null) { + readIdNullBean(); + } else if (!temporalVersions) { + readIdBean(); + } + } + } + + private void readIdBean() { + // check the PersistenceContext to see if the bean already exists + contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean); + if (contextBean == null) { + // bean just added to the persistenceContext + contextBean = localBean; + } else { + // bean already exists in persistenceContext + + if (queryMode.isLoadContextBean()) { + // if explicitly set loadContextBean to true, then reload + localBean = contextBean; + } else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) { + // reload if contextBean is partial object + localBean = contextBean; + // and switch to lazyLoad query mode in order not to overwrite + // existing properties in SqlBeanLoad::load + queryMode = Mode.LAZYLOAD_BEAN; + } else { + // ignore the DB data... + localBean = null; + } + } + } + + private void readIdNullBean() { + // bean must be null... + localBean = null; + // ... but there may exist as reference bean in parent which has to be marked as deleted. + if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) { + contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean); + if (contextBean != null) { + desc.markAsDeleted(contextBean); + } + } + } + + private void initSqlLoadBean() { + ctx.setCurrentPrefix(prefix, pathMap); + ctx.propagateState(localBean); + sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode); + } + + void loadProperties() { + for (STreeProperty property : properties) { + property.load(sqlBeanLoad); + } + } + + private void loadChildren() throws SQLException { + if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) { + // batch lazy load many into existing contextBean + localBean = contextBean; + lazyLoadMany = true; + } + for (SqlTreeLoad child : children) { + child.load(ctx, localBean, contextBean); + } + } + + private boolean isLazyLoadManyRoot() { + return queryMode == Mode.LAZYLOAD_MANY && isRoot(); + } + + private EntityBean getContextBean() { + return contextBean; + } + + private void postLoad() { + if (!lazyLoadMany && localBean != null) { + ctx.setCurrentPrefix(prefix, pathMap); + if (readIdNormal) { + createListProxies(); + } + if (temporalMode == SpiQuery.TemporalMode.DRAFT) { + localDesc.setDraft(localBean); + } + localDesc.postLoad(localBean); + + EntityBeanIntercept ebi = localBean._ebean_getIntercept(); + ebi.setPersistenceContext(persistenceContext); + if (Mode.LAZYLOAD_BEAN == queryMode) { + // Lazy Load does not reset the dirty state + ebi.setLoadedLazy(); + } else if (readId) { + // normal bean loading + ebi.setLoaded(); + } + + if (disableLazyLoad) { + // bean does not have an Id or is SqlSelect based + ebi.setDisableLazyLoad(true); + } else if (partialObject) { + if (readId) { + // register for lazy loading + ctx.register(null, ebi); + } + } else { + ebi.setFullyLoadedBean(true); + } + + if (ctx.isAutoTuneProfiling() && !disableLazyLoad) { + // collect autoTune profiling for this bean... + ctx.profileBean(ebi, prefix); + } + } + } + + /** + * Create lazy loading proxies for the Many's except for the one that is + * included in the actual query. + */ + private void createListProxies() { + STreePropertyAssocMany fetchedMany = ctx.getManyProperty(); + boolean forceNewReference = queryMode == Mode.REFRESH_BEAN; + for (STreePropertyAssocMany many : localDesc.propsMany()) { + if (many != fetchedMany) { + // create a proxy for the many (deferred fetching) + BeanCollection ref = many.createReference(localBean, forceNewReference); + if (ref != null) { + if (disableLazyLoad) { + ref.setDisableLazyLoad(true); + } + if (!ref.isRegisteredWithLoadContext()) { + ctx.register(many.asMany(), ref); + } + } + } + } + } + + private void setBeanToParent() { + if (parentBean != null) { + // set this back to the parentBean + nodeBeanProp.setValue(parentBean, contextBean); + } + } + + private EntityBean complete() { + if (!readIdNormal) { + // a bean with no Id (never found in context) + if (lazyLoadParentId != null) { + ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); + } + return localBean; + } else { + if (lazyLoadParentId != null) { + ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId); + } + return contextBean; + } + } + + private void initialise() throws SQLException { + initLazyParent(); + initBeanType(); + initPersistenceContext(); + readId(); + initSqlLoadBean(); + loadProperties(); + loadChildren(); + } + + /** + * Perform the load returning the loaded bean. + */ + final EntityBean perform() throws SQLException { + initialise(); + if (isLazyLoadManyRoot()) { + return getContextBean(); + } + postLoad(); + setBeanToParent(); + return complete(); + } + + /** + * Return true if this bean was already in the context. If already in the + * context we need to check if it is already contained in the collection. + */ + final boolean isContextBean() { + return localBean == null; + } + } + + /** + * read the properties from the resultSet. + */ + @Override + public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException { + return createLoad(ctx, parentBean).perform(); + } + + /** + * Create the loader with or without inheritance. + */ + final Load createLoad(DbReadContext ctx, EntityBean parentBean) { + return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean); + } + + @Override + public String toString() { + return "SqlTreeLoadBean: " + desc; + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java new file mode 100644 index 000000000..3622e770e --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadManyRoot.java @@ -0,0 +1,30 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; + +final class SqlTreeLoadManyRoot extends SqlTreeLoadBean { + + private final STreePropertyAssocMany manyProp; + + SqlTreeLoadManyRoot(SqlTreeNodeManyRoot node) { + super(node); + this.manyProp = node.manyProp; + } + + @Override + public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { + // pass in null for parentBean because added to a collection rather than set to the parentBean + Load load = createLoad(cquery, null); + EntityBean detailBean = load.perform(); + if (contextParent != null) { + // Add to the collection and initialise collection if needed + // A null detailBean may initialise an empty collection + // Check for bean existing in collection based on load.isContextBean() + manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean()); + } + return detailBean; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java new file mode 100644 index 000000000..d1792ecbe --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeLoadRoot.java @@ -0,0 +1,43 @@ +package io.ebeaninternal.server.query; + +import io.ebean.Version; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbReadContext; + +import java.sql.SQLException; +import java.sql.Timestamp; + +/** + * Represents the root node of the Sql Tree. + */ +final class SqlTreeLoadRoot extends SqlTreeLoadBean implements SqlTreeRoot { + + SqlTreeLoadRoot(SqlTreeNodeBean node) { + super(node); + } + + @Override + protected boolean isRoot() { + return true; + } + + @Override + public EntityBean load(DbReadContext ctx) throws SQLException { + return load(ctx, null, null); + } + + /** + * Read the version bean. + */ + @Override + @SuppressWarnings("unchecked") + public Version loadVersion(DbReadContext ctx) throws SQLException { + // read the sys period lower and upper bounds + // these are always the first 2 columns in the resultSet + Timestamp start = ctx.getDataReader().getTimestamp(); + Timestamp end = ctx.getDataReader().getTimestamp(); + T bean = (T) load(ctx, null, null); + return new Version<>(bean, start, end); + } + +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java index 39844cb59..54632d9ca 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java @@ -1,13 +1,8 @@ package io.ebeaninternal.server.query; -import io.ebean.Version; -import io.ebean.bean.EntityBean; -import io.ebean.core.type.ScalarDataReader; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; -import java.sql.SQLException; import java.util.List; import java.util.Set; @@ -64,25 +59,11 @@ interface SqlTreeNode { */ void addSoftDeletePredicate(SpiQuery query); - /** - * Load the appropriate information from the SqlSelectReader. - *

- * At a high level this actually controls the reading of the data from the - * jdbc resultSet and putting it into the bean etc. - *

- */ - EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean contextBean) throws SQLException; - /** * Return true if the query has a many join. */ boolean hasMany(); - /** - * Return the reader for the single attribute query. - */ - ScalarDataReader getSingleAttributeReader(); - /** * Return true if the query is known to only have a single property selected. */ @@ -92,4 +73,9 @@ interface SqlTreeNode { * Add dependent tables to the given set. */ void dependentTables(Set tables); + + /** + * Create the loader for this node. + */ + SqlTreeLoad createLoad(); } 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 547eededc..4836fa3fd 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 @@ -1,30 +1,20 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.BeanCollection; -import io.ebean.bean.EntityBean; -import io.ebean.bean.EntityBeanIntercept; -import io.ebean.bean.PersistenceContext; -import io.ebean.core.type.ScalarDataReader; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.api.SpiQuery.Mode; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.id.IdBinder; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Normal bean included in the query. */ 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; @@ -36,33 +26,33 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * Set to true if this is a partial object fetch. */ - private final boolean partialObject; - private final STreeProperty[] properties; + final boolean partialObject; + final STreeProperty[] properties; /** * Extra where clause added by Where annotation on associated many. */ - private final String extraWhere; - private final STreePropertyAssoc nodeBeanProp; + final String extraWhere; + final STreePropertyAssoc nodeBeanProp; /** * False if report bean and has no id property. */ final boolean readId; - private final boolean readIdNormal; - private final boolean disableLazyLoad; - private final InheritInfo inheritInfo; + final boolean readIdNormal; + final boolean disableLazyLoad; + final InheritInfo inheritInfo; final String prefix; - private final Map pathMap; + final Map pathMap; final STreePropertyAssocMany lazyLoadParent; - private final SpiQuery.TemporalMode temporalMode; - private final boolean temporalVersions; - private final IdBinder lazyLoadParentIdBinder; + final SpiQuery.TemporalMode temporalMode; + final boolean temporalVersions; + final IdBinder lazyLoadParentIdBinder; String baseTableAlias; /** * Table alias set if this bean node includes a join to a intersection * table and that table has history support. */ - private boolean intersectionAsOfTableAlias; - private final boolean aggregation; + boolean intersectionAsOfTableAlias; + final boolean aggregation; /** * Construct for leaf node. @@ -108,8 +98,23 @@ class SqlTreeNodeBean implements SqlTreeNode { pathMap = createPathMap(prefix, desc); } - boolean isRoot() { - return false; + @Override + public SqlTreeLoad createLoad() { + return new SqlTreeLoadBean(this); + } + + protected SqlTreeLoad[] createLoadChildren() { + if (children.length == 0) { + return NO_LOAD_CHILDREN; + } + List loadChildren = new ArrayList<>(children.length); + for (SqlTreeNode child : children) { + SqlTreeLoad load = child.createLoad(); + if (load != null) { + loadChildren.add(load); + } + } + return loadChildren.toArray(new SqlTreeLoad[0]); } @Override @@ -117,25 +122,6 @@ class SqlTreeNodeBean implements SqlTreeNode { return properties != null && properties.length == 1 && children.length == 0; } - @Override - public final ScalarDataReader getSingleAttributeReader() { - if (properties == null || properties.length == 0) { - // if we have no property ask first children (in a distinct select with join) - if (children.length == 0) { - // expected to be a findIds query - return desc.idBinder().getBeanProperty(); - } - return children[0].getSingleAttributeReader(); - } - if (properties[0] instanceof STreePropertyAssocOne) { - STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0]; - if (assocOne.isAssocId()) { - return assocOne.idReader(); - } - } - return properties[0]; - } - private Map createPathMap(String prefix, STreeType desc) { HashMap m = new HashMap<>(); for (STreePropertyAssocMany many : desc.propsMany()) { @@ -173,293 +159,6 @@ class SqlTreeNodeBean implements SqlTreeNode { } } - /** - * Load that takes into account inheritance. - */ - private final class LoadInherit extends Load { - - private LoadInherit(DbReadContext ctx, EntityBean parentBean) { - super(ctx, parentBean); - } - - @Override - void initBeanType() throws SQLException { - InheritInfo localInfo = readId ? inheritInfo.readType(ctx) : desc.inheritInfo(); - if (localInfo == null) { - // the bean must be null - localIdBinder = idBinder; - localDesc = desc; - } else { - localBean = localInfo.createEntityBean(); - localType = localInfo.getType(); - localIdBinder = localInfo.getIdBinder(); - localDesc = localInfo.desc(); - } - } - - @Override - void loadProperties() { - // take account of inheritance - for (STreeProperty property : properties) { - localDesc.inheritanceLoad(sqlBeanLoad, property, ctx); - } - } - } - - /** - * Load a bean instance. - */ - class Load { - - final DbReadContext ctx; - final EntityBean parentBean; - - Object lazyLoadParentId; - Class localType; - STreeType localDesc; - IdBinder localIdBinder; - EntityBean localBean; - - Mode queryMode; - PersistenceContext persistenceContext; - Object id; - EntityBean contextBean; - SqlBeanLoad sqlBeanLoad; - boolean lazyLoadMany; - - private Load(DbReadContext ctx, EntityBean parentBean) { - this.ctx = ctx; - this.parentBean = parentBean; - } - - private void initLazyParent() throws SQLException { - if (lazyLoadParentIdBinder != null) { - lazyLoadParentId = lazyLoadParentIdBinder.read(ctx); - } - } - - void initBeanType() throws SQLException { - localDesc = desc; - localBean = desc.createEntityBean(); - localIdBinder = idBinder; - } - - private void initPersistenceContext() { - queryMode = ctx.getQueryMode(); - persistenceContext = (!readIdNormal) ? null : ctx.getPersistenceContext(); - } - - private void readId() throws SQLException { - if (readId) { - id = localIdBinder.readSet(ctx, localBean); - if (id == null) { - readIdNullBean(); - } else if (!temporalVersions) { - readIdBean(); - } - } - } - - private void readIdBean() { - // check the PersistenceContext to see if the bean already exists - contextBean = (EntityBean) localDesc.contextPutIfAbsent(persistenceContext, id, localBean); - if (contextBean == null) { - // bean just added to the persistenceContext - contextBean = localBean; - } else { - // bean already exists in persistenceContext - - if (queryMode.isLoadContextBean()) { - // if explicitly set loadContextBean to true, then reload - localBean = contextBean; - } else if (!contextBean._ebean_getIntercept().isFullyLoadedBean()) { - // reload if contextBean is partial object - localBean = contextBean; - // and switch to lazyLoad query mode in order not to overwrite - // existing properties in SqlBeanLoad::load - queryMode = Mode.LAZYLOAD_BEAN; - } else { - // ignore the DB data... - localBean = null; - } - } - } - - private void readIdNullBean() { - // bean must be null... - localBean = null; - // ... but there may exist as reference bean in parent which has to be marked as deleted. - if (parentBean != null && nodeBeanProp instanceof STreePropertyAssocOne) { - contextBean = ((STreePropertyAssocOne)nodeBeanProp).getValueAsEntityBean(parentBean); - if (contextBean != null) { - desc.markAsDeleted(contextBean); - } - } - } - - private void initSqlLoadBean() { - ctx.setCurrentPrefix(prefix, pathMap); - ctx.propagateState(localBean); - sqlBeanLoad = new SqlBeanLoad(ctx, localType, localBean, queryMode); - } - - void loadProperties() { - for (STreeProperty property : properties) { - property.load(sqlBeanLoad); - } - } - - private void loadChildren() throws SQLException { - if (localBean == null && queryMode == Mode.LAZYLOAD_MANY) { - // batch lazy load many into existing contextBean - localBean = contextBean; - lazyLoadMany = true; - } - for (SqlTreeNode child : children) { - child.load(ctx, localBean, contextBean); - } - } - - private boolean isLazyLoadManyRoot() { - return queryMode == Mode.LAZYLOAD_MANY && isRoot(); - } - - private EntityBean getContextBean() { - return contextBean; - } - - private void postLoad() { - if (!lazyLoadMany && localBean != null) { - ctx.setCurrentPrefix(prefix, pathMap); - if (readIdNormal) { - createListProxies(); - } - if (temporalMode == SpiQuery.TemporalMode.DRAFT) { - localDesc.setDraft(localBean); - } - localDesc.postLoad(localBean); - - EntityBeanIntercept ebi = localBean._ebean_getIntercept(); - ebi.setPersistenceContext(persistenceContext); - if (Mode.LAZYLOAD_BEAN == queryMode) { - // Lazy Load does not reset the dirty state - ebi.setLoadedLazy(); - } else if (readId) { - // normal bean loading - ebi.setLoaded(); - } - - if (disableLazyLoad) { - // bean does not have an Id or is SqlSelect based - ebi.setDisableLazyLoad(true); - } else if (partialObject) { - if (readId) { - // register for lazy loading - ctx.register(null, ebi); - } - } else { - ebi.setFullyLoadedBean(true); - } - - if (ctx.isAutoTuneProfiling() && !disableLazyLoad) { - // collect autoTune profiling for this bean... - ctx.profileBean(ebi, prefix); - } - } - } - - /** - * Create lazy loading proxies for the Many's except for the one that is - * included in the actual query. - */ - private void createListProxies() { - STreePropertyAssocMany fetchedMany = ctx.getManyProperty(); - boolean forceNewReference = queryMode == Mode.REFRESH_BEAN; - for (STreePropertyAssocMany many : localDesc.propsMany()) { - if (many != fetchedMany) { - // create a proxy for the many (deferred fetching) - BeanCollection ref = many.createReference(localBean, forceNewReference); - if (ref != null) { - if (disableLazyLoad) { - ref.setDisableLazyLoad(true); - } - if (!ref.isRegisteredWithLoadContext()) { - ctx.register(many.asMany(), ref); - } - } - } - } - } - - private void setBeanToParent() { - if (parentBean != null) { - // set this back to the parentBean - nodeBeanProp.setValue(parentBean, contextBean); - } - } - - private EntityBean complete() { - if (!readIdNormal) { - // a bean with no Id (never found in context) - if (lazyLoadParentId != null) { - ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); - } - return localBean; - } else { - if (lazyLoadParentId != null) { - ctx.setLazyLoadedChildBean(contextBean, lazyLoadParentId); - } - return contextBean; - } - } - - private void initialise() throws SQLException { - initLazyParent(); - initBeanType(); - initPersistenceContext(); - readId(); - initSqlLoadBean(); - loadProperties(); - loadChildren(); - } - - /** - * Perform the load returning the loaded bean. - */ - final EntityBean perform() throws SQLException { - initialise(); - if (isLazyLoadManyRoot()) { - return getContextBean(); - } - postLoad(); - setBeanToParent(); - return complete(); - } - - /** - * Return true if this bean was already in the context. If already in the - * context we need to check if it is already contained in the collection. - */ - final boolean isContextBean() { - return localBean == null; - } - } - - /** - * read the properties from the resultSet. - */ - @Override - public EntityBean load(DbReadContext ctx, EntityBean parentBean, EntityBean contextParent) throws SQLException { - return createLoad(ctx, parentBean).perform(); - } - - /** - * Create the loader with or without inheritance. - */ - final Load createLoad(DbReadContext ctx, EntityBean parentBean) { - return (inheritInfo != null) ? new LoadInherit(ctx, parentBean) : new Load(ctx, parentBean); - } - @Override public final void appendGroupBy(DbSqlContext ctx, boolean subQuery) { ctx.pushJoin(prefix); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index e7ca5d9ab..42d2395b5 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -38,6 +38,11 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany; } + @Override + public SqlTreeLoad createLoad() { + return null; + } + @Override public boolean isSingleProperty() { return false; @@ -73,11 +78,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { // nothing to do here } - @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); - } - /** * Return true if the extra join is a many join. *

@@ -184,14 +184,6 @@ final class SqlTreeNodeExtraJoin implements SqlTreeNode { public void appendWhere(DbSqlContext ctx) { } - /** - * Does nothing. - */ - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - return null; - } - @Override public boolean hasMany() { return manyJoin; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java index 06a71133a..502c28a6d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeFormulaWhereJoin.java @@ -33,13 +33,13 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode { } @Override - public boolean isSingleProperty() { - return true; + public SqlTreeLoad createLoad() { + return null; } @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); + public boolean isSingleProperty() { + return true; } @Override @@ -98,12 +98,6 @@ final class SqlTreeNodeFormulaWhereJoin implements SqlTreeNode { // nothing to do here } - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - // nothing to do here - return null; - } - @Override public boolean hasMany() { return true; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java index c030e96bc..a8b323533 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java @@ -1,16 +1,13 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; -import java.sql.SQLException; import java.util.List; final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { - private final STreePropertyAssocMany manyProp; + final STreePropertyAssocMany manyProp; SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List myList, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { @@ -19,22 +16,13 @@ final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { } @Override - public boolean hasMany() { - return true; + public SqlTreeLoad createLoad() { + return new SqlTreeLoadManyRoot(this); } @Override - public EntityBean load(DbReadContext cquery, EntityBean parentBean, EntityBean contextParent) throws SQLException { - // pass in null for parentBean because added to a collection rather than set to the parentBean - SqlTreeNodeBean.Load load = createLoad(cquery, null); - EntityBean detailBean = load.perform(); - if (contextParent != null) { - // Add to the collection and initialise collection if needed - // A null detailBean may initialise an empty collection - // Check for bean existing in collection based on load.isContextBean() - manyProp.addBeanToCollectionWithCreate(contextParent, detailBean, load.isContextBean()); - } - return detailBean; + public boolean hasMany() { + return true; } /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index 73c7a18b2..cb2ba54e7 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -1,10 +1,7 @@ package io.ebeaninternal.server.query; -import io.ebean.bean.EntityBean; -import io.ebean.core.type.ScalarType; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; @@ -37,13 +34,13 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode { } @Override - public boolean isSingleProperty() { - return false; + public SqlTreeLoad createLoad() { + return null; } @Override - public ScalarType getSingleAttributeReader() { - throw new IllegalStateException("No expected"); + public boolean isSingleProperty() { + return false; } @Override @@ -132,12 +129,6 @@ final class SqlTreeNodeManyWhereJoin implements SqlTreeNode { // nothing to do here } - @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { - // nothing to do here - return null; - } - @Override public boolean hasMany() { return true; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java index a58c51cc5..c25024624 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -1,21 +1,16 @@ package io.ebeaninternal.server.query; -import io.ebean.Version; -import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; -import java.sql.SQLException; -import java.sql.Timestamp; import java.util.List; import java.util.Set; /** * Represents the root node of the Sql Tree. */ -final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot { +final class SqlTreeNodeRoot extends SqlTreeNodeBean { private final TableJoin includeJoin; private final boolean sqlDistinct; @@ -34,27 +29,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean implements SqlTreeRoot { } @Override - protected boolean isRoot() { - return true; - } - - @Override - public EntityBean load(DbReadContext ctx) throws SQLException { - return load(ctx, null, null); - } - - /** - * Read the version bean. - */ - @Override - @SuppressWarnings("unchecked") - public Version loadVersion(DbReadContext ctx) throws SQLException { - // read the sys period lower and upper bounds - // these are always the first 2 columns in the resultSet - Timestamp start = ctx.getDataReader().getTimestamp(); - Timestamp end = ctx.getDataReader().getTimestamp(); - T bean = (T) load(ctx, null, null); - return new Version<>(bean, start, end); + public SqlTreeLoad createLoad() { + return new SqlTreeLoadRoot(this); } @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java new file mode 100644 index 000000000..7a0e929ef --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreePlan.java @@ -0,0 +1,41 @@ +package io.ebeaninternal.server.query; + +import java.util.Set; + +final class SqlTreePlan { + + private final SqlTreeLoad rootNode; + private final STreePropertyAssocMany manyProperty; + private final STreeProperty[] encryptedProps; + private final Set dependentTables; + + SqlTreePlan(SqlTreeLoad rootNode, STreePropertyAssocMany manyProperty, STreeProperty[] encryptedProps, Set dependentTables) { + this.rootNode = rootNode; + this.manyProperty = manyProperty; + this.encryptedProps = encryptedProps; + this.dependentTables = dependentTables; + } + + SqlTreeRoot getRootNode() { + return (SqlTreeRoot)rootNode; + } + + /** + * Return the property that is associated with the many. There can only be one + * per SqlSelect. This can be null. + */ + STreePropertyAssocMany getManyProperty() { + return manyProperty; + } + + STreeProperty[] getEncryptedProps() { + return encryptedProps; + } + + /** + * Return the tables that are joined in this query. + */ + Set dependentTables() { + return dependentTables; + } +} From 17f7be72f46da3b0e928ec3bdfa4d5706487dc14 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 21:54:19 +1300 Subject: [PATCH 46/47] Touch README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 30dc2c06b..a560d8c82 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,3 @@ Goto [https://ebean.io/docs/](https://ebean.io/docs/) [Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects") -## Other versions -* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent) - ebean-agent -* [![Maven Central : ebean-maven-plugin](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-maven-plugin) - ebean-maven-plugin From 7ffd2f1886bf73f1b54d142c33b88189fa82b459 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Jan 2022 22:41:55 +1300 Subject: [PATCH 47/47] #2501 Modify pom use ${h2database.version} --- ebean-api/pom.xml | 2 +- ebean-core/pom.xml | 2 +- ebean-test/pom.xml | 2 +- pom.xml | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index 56fd5d994..d11bb71f6 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -85,7 +85,7 @@ com.h2database h2 - 2.1.210 + ${h2database.version} true diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index d77e38d62..1adcaf362 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -78,7 +78,7 @@ com.h2database h2 - 2.1.210 + ${h2database.version} provided diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 2d210584d..2fcf19018 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -76,7 +76,7 @@ com.h2database h2 - 2.1.210 + ${h2database.version} diff --git a/pom.xml b/pom.xml index 49c958dde..66a499e77 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ false 2.12.1 + 2.1.210 1.2 1.1 12.13.1 @@ -68,7 +69,7 @@ com.h2database h2 - 2.1.210 + ${h2database.version} test