From 73b2cc55f358cc81bb274c745796e1fb7ee7b3d9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Feb 2018 22:22:08 +1300 Subject: [PATCH 0001/1036] #1254 - SpringJdbcTransactionManager inifinite recursion #1254 Fix. Note tested in ebean-spring-txn. --- .../ExternalTransactionScopeManager.java | 38 +------------------ 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java index c9701dc16..a80ba0852 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java @@ -1,12 +1,11 @@ package io.ebeaninternal.server.transaction; import io.ebean.config.ExternalTransactionManager; -import io.ebeaninternal.api.SpiTransaction; /** * A TransactionScopeManager aware of external transaction managers. */ -public class ExternalTransactionScopeManager extends TransactionScopeManager { +public class ExternalTransactionScopeManager extends DefaultTransactionScopeManager { private final ExternalTransactionManager externalManager; @@ -23,39 +22,4 @@ public class ExternalTransactionScopeManager extends TransactionScopeManager { externalManager.setTransactionManager(manager); } - @Override - public void commit() { - DefaultTransactionThreadLocal.commit(serverName); - } - - - @Override - public void end() { - DefaultTransactionThreadLocal.end(serverName); - } - - @Override - public SpiTransaction getMaybeInactive() { - return get(); - } - - @Override - public SpiTransaction get() { - return (SpiTransaction) externalManager.getCurrentTransaction(); - } - - @Override - public void replace(SpiTransaction trans) { - DefaultTransactionThreadLocal.replace(serverName, trans); - } - - @Override - public void rollback() { - DefaultTransactionThreadLocal.rollback(serverName); - } - - @Override - public void set(SpiTransaction trans) { - DefaultTransactionThreadLocal.set(serverName, trans); - } } From 175714046a996d075ae4b16409c574dc4c9b1395 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Feb 2018 23:03:07 +1300 Subject: [PATCH 0002/1036] #1254 - SpringJdbcTransactionManager inifinite recursion #1254 Yeah, nah. This is the real fix. Expose: SpiTransaction TransctionManager.getInScope(); ... and have ebean-spring-txn SpringJdbcTransactionManager call it instead of getActive(). --- .../api/SpiTransactionManager.java | 2 +- .../server/core/DefaultServer.java | 8 +++---- .../DefaultTransactionScopeManager.java | 4 ++-- .../ExternalTransactionScopeManager.java | 6 +++++ .../transaction/TransactionManager.java | 24 +++++++++---------- .../transaction/TransactionScopeManager.java | 8 +++---- 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/main/java/io/ebeaninternal/api/SpiTransactionManager.java b/src/main/java/io/ebeaninternal/api/SpiTransactionManager.java index e914d200e..d08e5aa2b 100644 --- a/src/main/java/io/ebeaninternal/api/SpiTransactionManager.java +++ b/src/main/java/io/ebeaninternal/api/SpiTransactionManager.java @@ -22,7 +22,7 @@ public interface SpiTransactionManager { /** * Return the currently active transaction (can be null). */ - SpiTransaction get(); + SpiTransaction getActive(); /** * Push an externally managed transaction into scope (e.g. Spring managed transaction). diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 2c3c21d48..1fce54334 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -613,7 +613,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { id = desc.convertId(id); PersistenceContext pc = null; - SpiTransaction t = transactionManager.get(); + SpiTransaction t = transactionManager.getActive(); if (t != null) { pc = t.getPersistenceContext(); Object existing = desc.contextGet(pc, id); @@ -725,7 +725,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public SpiTransaction currentServerTransaction() { - return transactionManager.get(); + return transactionManager.getActive(); } /** @@ -773,7 +773,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public Transaction currentTransaction() { - return transactionManager.get(); + return transactionManager.getActive(); } @Override @@ -2035,7 +2035,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { if (t != null) { return new ObtainedTransaction((SpiTransaction) t); } - SpiTransaction trans = transactionManager.get(); + SpiTransaction trans = transactionManager.getActive(); if (trans != null) { return new ObtainedTransaction(trans); } diff --git a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java index 0d54b9b22..0f376b3cb 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java @@ -28,12 +28,12 @@ public class DefaultTransactionScopeManager extends TransactionScopeManager { } @Override - public SpiTransaction getMaybeInactive() { + public SpiTransaction getInScope() { return DefaultTransactionThreadLocal.get(serverName); } @Override - public SpiTransaction get() { + public SpiTransaction getActive() { SpiTransaction t = DefaultTransactionThreadLocal.get(serverName); if (t == null || !t.isActive()) { return null; diff --git a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java index a80ba0852..ffa3bdb1e 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.config.ExternalTransactionManager; +import io.ebeaninternal.api.SpiTransaction; /** * A TransactionScopeManager aware of external transaction managers. @@ -22,4 +23,9 @@ public class ExternalTransactionScopeManager extends DefaultTransactionScopeMana externalManager.setTransactionManager(manager); } + @Override + public SpiTransaction getActive() { + return (SpiTransaction) externalManager.getCurrentTransaction(); + } + } diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 1ff2c453e..d4e0379ff 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -201,22 +201,22 @@ public class TransactionManager implements SpiTransactionManager { /** * Return the current active transaction. */ - public SpiTransaction get() { - return scopeManager.get(); + public SpiTransaction getActive() { + return scopeManager.getActive(); } /** * Return the current active transaction as a scoped transaction. */ - public ScopedTransaction getScoped() { - return (ScopedTransaction) scopeManager.get(); + public ScopedTransaction getActiveScoped() { + return (ScopedTransaction) scopeManager.getActive(); } /** - * Return the current scoped transaction allowing it to be inactive (already committed or rolled back). + * Return the current transaction from thread local scope. Note that it may be inactive. */ - private ScopedTransaction getMaybeInactive() { - return (ScopedTransaction)scopeManager.getMaybeInactive(); + public SpiTransaction getInScope() { + return scopeManager.getInScope(); } /** @@ -420,7 +420,7 @@ public class TransactionManager implements SpiTransactionManager { } public void externalModification(TransactionEventTable tableEvent) { - SpiTransaction t = get(); + SpiTransaction t = getActive(); if (t != null) { t.getEvent().add(tableEvent); } else { @@ -555,11 +555,11 @@ public class TransactionManager implements SpiTransactionManager { * Exit a scoped transaction (that can be inactive - already committed etc). */ public void exitScopedTransaction(Object returnOrThrowable, int opCode) { - ScopedTransaction st = getMaybeInactive(); - if (st != null) { + SpiTransaction st = getInScope(); + if (st instanceof ScopedTransaction) { // can be null for Supports as that can start as a 'No Transaction' and then // effectively be replaced by transactions inside the scope - st.complete(returnOrThrowable, opCode); + ((ScopedTransaction)st).complete(returnOrThrowable, opCode); } } @@ -588,7 +588,7 @@ public class TransactionManager implements SpiTransactionManager { txScope = initTxScope(txScope); boolean setToScope = false; - ScopedTransaction txnContainer = getScoped(); + ScopedTransaction txnContainer = getActiveScoped(); if (txnContainer == null) { setToScope = true; txnContainer = createScopedTransaction(); diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java index 994a667a9..541b07b1d 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java @@ -20,14 +20,14 @@ public abstract class TransactionScopeManager implements SpiTransactionScopeMana public abstract void register(TransactionManager manager); /** - * Return the current Transaction allowing it to be inactive. + * Return the current Transaction from internal Ebean scope. */ - public abstract SpiTransaction getMaybeInactive(); + public abstract SpiTransaction getInScope(); /** - * Return the current Transaction for this serverName and Thread. + * Return the current Transaction potentially looking in external scope (like Spring). */ - public abstract SpiTransaction get(); + public abstract SpiTransaction getActive(); /** * Set a new Transaction for this serverName and Thread. From 5b2aa0c74da9635e88b132ee21f8c4945d5e7fb4 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Feb 2018 23:42:28 +1300 Subject: [PATCH 0003/1036] [maven-release-plugin] prepare release ebean-11.10.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f3e7f3cb5..ce7beb2b4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.3-SNAPSHOT + 11.10.3 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.10.3 From f78f24136a5c6063d39589bf908553a6bc289535 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Feb 2018 23:42:42 +1300 Subject: [PATCH 0004/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ce7beb2b4..a2da3dc05 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.3 + 11.10.4-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.10.3 + HEAD From e5a1f9f7ccc84d1db20ad331c74683c1a4dc697b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:07:27 +1300 Subject: [PATCH 0005/1036] Testing - modify .travis adding docker service --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 372ace1ff..cfd2f10ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,9 @@ addons: postgresql: "9.6" services: + - docker - postgresql +# - mysql before_script: - ./.travis/setup_database @@ -19,6 +21,7 @@ before_script: env: - EBEAN_DB=h2 - EBEAN_DB=pg +# - EBEAN_DB=mysql install: true From b1027a2f2544b89d997df679997fe202a5420899 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:18:33 +1300 Subject: [PATCH 0006/1036] Testing - modify .travis to run mysql as docker container --- .travis.yml | 2 +- src/test/resources/docker-run.properties | 8 ++++++-- src/test/resources/ebean.properties | 8 +++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index cfd2f10ad..1e2f4a947 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ before_script: env: - EBEAN_DB=h2 - EBEAN_DB=pg -# - EBEAN_DB=mysql + - EBEAN_DB=mysql install: true diff --git a/src/test/resources/docker-run.properties b/src/test/resources/docker-run.properties index c5f5af698..52369203c 100644 --- a/src/test/resources/docker-run.properties +++ b/src/test/resources/docker-run.properties @@ -1,4 +1,10 @@ +mysql.version=5.7 +mysql.dbName=test_ebean +mysql.dbUser=test_ebean +mysql.dbPassword=test +mysql.startMode=dropcreate + #sqlserver.version=2017-CU2 #sqlserver.port=1433 #sqlserver.dbName=test_ebean @@ -11,8 +17,6 @@ #oracle.dbPassword=test ##oracle.startMode=dropcreate -#mysql.version=5.7 -#mysql.startMode=dropcreate #postgres.version=9.6 ##postgres.dbName=test_db diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 9e9a42ac8..62b6ee97e 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -103,11 +103,9 @@ datasource.hsqldb.databaseUrl=jdbc:hsqldb:mem:tests datasource.hsqldb.databaseDriver=org.hsqldb.jdbcDriver -datasource.mysql.username=unit -datasource.mysql.password=unit -datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/unit -#connection String for Connector/j 6.0 -#datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/unit?useLegacyDatetimeCode=false&serverTimezone=UTC +datasource.mysql.username=test_ebean +datasource.mysql.password=test +datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:4306/test_ebean datasource.mysql.databaseDriver=com.mysql.jdbc.Driver From 3fdb76d18f78d836d8bf094be731047d56cd85d5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:31:39 +1300 Subject: [PATCH 0007/1036] Testing - modify .travis to run mysql as service --- .travis.yml | 10 +++++++++- src/test/resources/docker-run.properties | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e2f4a947..c27858e69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,14 +9,22 @@ git: addons: postgresql: "9.6" + apt: + packages: + - mysql-server-5.6 + - mysql-client-core-5.6 + - mysql-client-5.6 services: - docker - postgresql -# - mysql + - mysql before_script: - ./.travis/setup_database + - mysql -u root -e 'CREATE DATABASE test_ebean;' + - mysql -u root -e "CREATE USER 'test_ebean'@'localhost' IDENTIFIED BY 'test';" + - mysql -u root -e "GRANT ALL ON test_ebean.* TO 'test_ebean'@'localhost';" env: - EBEAN_DB=h2 diff --git a/src/test/resources/docker-run.properties b/src/test/resources/docker-run.properties index 52369203c..467515d9b 100644 --- a/src/test/resources/docker-run.properties +++ b/src/test/resources/docker-run.properties @@ -1,9 +1,9 @@ -mysql.version=5.7 -mysql.dbName=test_ebean -mysql.dbUser=test_ebean -mysql.dbPassword=test -mysql.startMode=dropcreate +#mysql.version=5.7 +#mysql.dbName=test_ebean +#mysql.dbUser=test_ebean +#mysql.dbPassword=test +#mysql.startMode=dropcreate #sqlserver.version=2017-CU2 #sqlserver.port=1433 From 0f7158ea18053c57dbf4e37698972eda6bb1981f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:34:34 +1300 Subject: [PATCH 0008/1036] Testing - modify .travis to run mysql as service --- src/test/resources/ebean.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 62b6ee97e..826d41ad6 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -105,7 +105,7 @@ datasource.hsqldb.databaseDriver=org.hsqldb.jdbcDriver datasource.mysql.username=test_ebean datasource.mysql.password=test -datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:4306/test_ebean +datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/test_ebean datasource.mysql.databaseDriver=com.mysql.jdbc.Driver From f1c2f134add02a6cd8dfb0355177bb15350a1503 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:56:05 +1300 Subject: [PATCH 0009/1036] #1255 - Regression on raw LIKE expression with slashes on Postgres Related update for Sqlite --- .../io/ebean/config/dbplatform/sqlite/SQLitePlatform.java | 5 +++++ .../java/io/ebeaninternal/server/core/DefaultContainer.java | 1 + 2 files changed, 6 insertions(+) diff --git a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java index a9a8dd65c..74823549a 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java @@ -19,12 +19,17 @@ public class SQLitePlatform extends DatabasePlatform { this.dbIdentity.setSelectLastInsertedIdTemplate("select last_insert_rowid()"); this.booleanDbType = Types.INTEGER; + this.likeClauseRaw = "like ?"; + this.likeClauseEscaped = "like ?"; dbTypeMap.put(DbType.BIT, new DbPlatformType("int default 0")); dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int default 0")); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("integer")); dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("integer")); + } + protected void escapeLikeCharacter(char ch, StringBuilder sb) { + sb.append(ch); } } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java index 1ef44d978..ff4fd4338 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java @@ -331,6 +331,7 @@ public class DefaultContainer implements SpiContainer { dsConfig.setAutoCommit(true); //dsConfig.setReadOnly(true); dsConfig.setDefaults(config.getDataSourceConfig()); + dsConfig.setIsolationLevel(config.getDataSourceConfig().getIsolationLevel()); } String poolName = config.getName() + (readOnly ? "-ro" : ""); return factory.createPool(poolName, dsConfig); From 6474f306b596f72ae509f3dc2435d13b852e50a0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 00:57:19 +1300 Subject: [PATCH 0010/1036] #1255 - Regression on raw LIKE expression with slashes on Postgres Related update for Sqlite --- src/test/resources/ebean.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 826d41ad6..39776ad38 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -94,8 +94,6 @@ datasource.sqlite.password= datasource.sqlite.databaseUrl=jdbc:sqlite:mydb.db datasource.sqlite.databaseDriver=org.sqlite.JDBC datasource.sqlite.isolationlevel=read_uncommitted -datasource.sqlite.minConnections=1 -datasource.sqlite.maxConnections=25 datasource.hsqldb.username=sa datasource.hsqldb.password= From e4d9e4f2de01d950ca3c1a8071115217e94e9971 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 01:04:19 +1300 Subject: [PATCH 0011/1036] Testing - modify .travis to run mysql as service (bump MySql version to 5.7) --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index c27858e69..90914b1e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,9 @@ addons: postgresql: "9.6" apt: packages: - - mysql-server-5.6 - - mysql-client-core-5.6 - - mysql-client-5.6 + - mysql-server-5.7 + - mysql-client-core-5.7 + - mysql-client-5.7 services: - docker @@ -29,7 +29,7 @@ before_script: env: - EBEAN_DB=h2 - EBEAN_DB=pg - - EBEAN_DB=mysql +# - EBEAN_DB=mysql install: true From f1b2a09b30929b4b669f16ccfd819ee9a0627248 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Feb 2018 01:16:40 +1300 Subject: [PATCH 0012/1036] Testing - modify .travis to run mysql as service (bump MySql version to 5.7) --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 90914b1e6..2126f0a28 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,11 +9,11 @@ git: addons: postgresql: "9.6" - apt: - packages: - - mysql-server-5.7 - - mysql-client-core-5.7 - - mysql-client-5.7 +# apt: +# packages: +# - mysql-server-5.7 +# - mysql-client-core-5.7 +# - mysql-client-5.7 services: - docker From 17a54e3804f3b1ab43db9abd47461f1c4c0caa0b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 13 Feb 2018 14:09:08 +1300 Subject: [PATCH 0013/1036] No effective change - extra tests for DeployPropertyParser --- .../deploy/DeployPropertyParserTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java new file mode 100644 index 000000000..a6be2b9f7 --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -0,0 +1,38 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.BaseTestCase; +import org.junit.Test; +import org.tests.model.basic.Customer; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class DeployPropertyParserTest extends BaseTestCase { + + private final BeanDescriptor descriptor = getBeanDescriptor(Customer.class); + + @Test + public void depth0_path() { + assertThat(parser().parse("pre status post")).isEqualTo("pre ${}status post"); + } + + @Test + public void depth1_path() { + assertThat(parser().parse("billingAddress.city")).isEqualTo("${billingAddress}city"); + } + + @Test + public void depth2_path() { + assertThat(parser().parse("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)"); + } + + @Test + public void unknown_path() { + assertThat(parser().parse(" foo ")).isEqualTo(" foo "); + } + + private DeployPropertyParser parser() { + return descriptor.createDeployPropertyParser(); + } + +} From a95fd063ae0dc5cafa47b5c8b28d3b8b0023a146 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 13 Feb 2018 14:52:18 +1300 Subject: [PATCH 0014/1036] #1256 - Query where many isNotEmpty() ... on ManyToMany with SoftDelete produces incorrect SQL (Part 2) --- .../server/deploy/DeployParser.java | 17 ++++++++++++++--- .../server/deploy/DeployPropertyParser.java | 12 +++++++++++- .../server/query/CQueryPredicates.java | 14 ++++---------- .../server/deploy/DeployPropertyParserTest.java | 5 +++++ .../java/org/tests/m2m/softdelete/MsManyA.java | 10 ++++++++++ 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index e61e5f144..ff693b1ec 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -37,6 +37,8 @@ public abstract class DeployParser { protected int pos; + protected String priorWord; + protected String word; protected char wordTerminator; @@ -45,7 +47,6 @@ public abstract class DeployParser { public abstract String getDeployWord(String expression); - /** * Return the join includes. */ @@ -67,8 +68,14 @@ public abstract class DeployParser { this.sb = new StringBuilder(source.length() + 20); while (nextWord()) { - String deployWord = convertWord(); - sb.append(deployWord); + if (skipWordConvert()) { + sb.append(word); + priorWord = word; + } else { + String deployWord = convertWord(); + sb.append(deployWord); + priorWord = deployWord; + } if (pos < sourceLength) { sb.append(wordTerminator); if (wordTerminator == SINGLE_QUOTE) { @@ -80,6 +87,10 @@ public abstract class DeployParser { return sb.toString(); } + protected boolean skipWordConvert() { + return false; + } + private boolean nextWord() { if (!findWordStart()) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java index a698b9f9e..108e8f2d7 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java @@ -14,12 +14,15 @@ import java.util.Set; */ public final class DeployPropertyParser extends DeployParser { + private static final String JOIN = "join"; + + private static final String FROM = "from"; private final BeanDescriptor beanDescriptor; private final Set includes = new HashSet<>(); - public DeployPropertyParser(BeanDescriptor beanDescriptor) { + DeployPropertyParser(BeanDescriptor beanDescriptor) { this.beanDescriptor = beanDescriptor; } @@ -28,6 +31,13 @@ public final class DeployPropertyParser extends DeployParser { return includes; } + /** + * Skip if in raw sql expression with from tableName or join tableName. + */ + protected boolean skipWordConvert() { + return FROM.equalsIgnoreCase(priorWord) || JOIN.equalsIgnoreCase(priorWord); + } + @Override public String getDeployWord(String expression) { ElPropertyDeploy elProp = beanDescriptor.getElPropertyDeploy(expression); diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java index b49f65a59..98fe40941 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.query; -import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiExpressionList; import io.ebeaninternal.api.SpiQuery; @@ -12,6 +11,7 @@ import io.ebeaninternal.server.expression.DefaultExpressionRequest; import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.querydefn.OrmQueryProperties; import io.ebeaninternal.server.querydefn.OrmUpdateProperties; +import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.type.DataBind; import io.ebeaninternal.server.util.BindParamsParser; import org.slf4j.Logger; @@ -318,15 +318,9 @@ public class CQueryPredicates { } private String parse(String expr, DeployParser deployParser) { - - StringBuilder sb = new StringBuilder(); - if (!isEmpty(expr)) { - if (sb.length() > 0) { - sb.append(" and "); - } - sb.append(deployParser.parse(expr)); - } - return sb.toString(); + if (expr == null) return ""; + if (expr.isEmpty()) return expr; + return deployParser.parse(expr); } private String deriveHaving(DeployParser deployParser) { diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index a6be2b9f7..1d6a9cafa 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -11,6 +11,11 @@ public class DeployPropertyParserTest extends BaseTestCase { private final BeanDescriptor descriptor = getBeanDescriptor(Customer.class); + @Test + public void from_prefix_expect_unchanged() { + assertThat(parser().parse("(select x from status join status)")).isEqualTo("(select x from status join status)"); + } + @Test public void depth0_path() { assertThat(parser().parse("pre status post")).isEqualTo("pre ${}status post"); diff --git a/src/test/java/org/tests/m2m/softdelete/MsManyA.java b/src/test/java/org/tests/m2m/softdelete/MsManyA.java index 193eb5b0c..0b9cf1f24 100644 --- a/src/test/java/org/tests/m2m/softdelete/MsManyA.java +++ b/src/test/java/org/tests/m2m/softdelete/MsManyA.java @@ -18,6 +18,16 @@ public class MsManyA { @SoftDelete boolean deleted; + /** + * Name clash with M2M intersection table name. + */ + boolean ms_many_a_many_b; + + /** + * Name clash with other side table name. + */ + boolean ms_many_b; + @ManyToMany List manybs; From b2967dec1eb0732430740037d02393997a41606e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 13 Feb 2018 16:22:52 +1300 Subject: [PATCH 0015/1036] #1257 - ServerConfig with register = true, defaultServer = false ... fails as it tries to create the default server --- src/main/java/io/ebean/Ebean.java | 14 +++----------- src/main/java/io/ebean/EbeanServerFactory.java | 4 +--- src/test/java/io/ebean/PrimaryServerTest.java | 6 +++--- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/ebean/Ebean.java b/src/main/java/io/ebean/Ebean.java index edb4a5d6f..df48ce3ba 100644 --- a/src/main/java/io/ebean/Ebean.java +++ b/src/main/java/io/ebean/Ebean.java @@ -5,10 +5,10 @@ import io.ebean.cache.ServerCacheManager; import io.ebean.config.ServerConfig; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import java.util.Collection; @@ -131,8 +131,7 @@ public final class Ebean { private final ConcurrentHashMap concMap = new ConcurrentHashMap<>(); /** - * Cache for synchronized read, creation and put. Protected by the monitor - * object. + * Cache for synchronized read, creation and put. Protected by the monitor object. */ private final HashMap syncMap = new HashMap<>(); @@ -146,14 +145,7 @@ public final class Ebean { private ServerManager() { try { - // skipDefaultServer is set by EbeanServerFactory - // ... when it is creating the primaryServer - if (PrimaryServer.isSkip()) { - // primary server being created by EbeanServerFactory - // ... so we should not try and create it here - logger.debug("PrimaryServer.isSkip()"); - - } else { + if (!PrimaryServer.isSkip()) { // look to see if there is a default server defined String defaultName = PrimaryServer.getDefaultServerName(); logger.debug("defaultName:{}", defaultName); diff --git a/src/main/java/io/ebean/EbeanServerFactory.java b/src/main/java/io/ebean/EbeanServerFactory.java index 090e23e9a..888b54647 100644 --- a/src/main/java/io/ebean/EbeanServerFactory.java +++ b/src/main/java/io/ebean/EbeanServerFactory.java @@ -65,10 +65,8 @@ public class EbeanServerFactory { EbeanServer server = createInternal(config); - if (config.isDefaultServer()) { - PrimaryServer.setSkip(true); - } if (config.isRegister()) { + PrimaryServer.setSkip(true); Ebean.register(server, config.isDefaultServer()); } diff --git a/src/test/java/io/ebean/PrimaryServerTest.java b/src/test/java/io/ebean/PrimaryServerTest.java index ce5a198dd..56460f7f3 100644 --- a/src/test/java/io/ebean/PrimaryServerTest.java +++ b/src/test/java/io/ebean/PrimaryServerTest.java @@ -14,7 +14,7 @@ public class PrimaryServerTest extends BaseTestCase { @Test - public void testIsSkipPrimaryServer() throws Exception { + public void testIsSkipPrimaryServer() { PrimaryServer.setSkip(true); assertTrue(PrimaryServer.isSkip()); PrimaryServer.setSkip(false); @@ -23,14 +23,14 @@ public class PrimaryServerTest extends BaseTestCase { @Test @ForPlatform(Platform.H2) - public void testGetPrimaryServerName() throws Exception { + public void testGetPrimaryServerName() { String primaryServerName = PrimaryServer.getDefaultServerName(); assertEquals("h2", primaryServerName); } @Test - public void testLoadProperties() throws Exception { + public void testLoadProperties() { Properties properties = PrimaryServer.getProperties(); assertTrue(!properties.isEmpty()); From 7c477827fe5761c653dfe32886bb216ed82896ad Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 12:39:35 +1300 Subject: [PATCH 0016/1036] #1259 - Throw explicit mapping error when an Enum is mapped to both ORDINAL and STRING --- .../server/deploy/parse/DeployUtil.java | 34 ++----- .../server/type/DefaultTypeManager.java | 18 ++-- .../server/type/ScalarTypeDayOfWeek.java | 9 ++ .../server/type/ScalarTypeEnum.java | 16 +++- .../server/type/ScalarTypeEnumStandard.java | 11 +++ .../type/ScalarTypeEnumWithMapping.java | 6 ++ .../server/type/ScalarTypeMonth.java | 9 ++ .../io/ebean/server/type/TestTypeManager.java | 20 +++- .../server/type/DefaultTypeManagerTest.java | 91 ++++++++++++++++++- 9 files changed, 176 insertions(+), 38 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java index 8f524f1ac..b821cb89a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java @@ -112,30 +112,16 @@ public class DeployUtil { if (!enumType.isEnum()) { throw new IllegalArgumentException("Class [" + enumType + "] is Not a Enum?"); } - ScalarType scalarType = typeManager.getScalarType(enumType); - if (enumOverrideDefaultMapping(enumerated, scalarType)) { - logger.debug("override default enum mapping for type {}", enumType); - scalarType = null; - } - if (scalarType == null) { - // look for @DbEnumValue or @EnumValue annotations etc - Class> enumClass = (Class>) enumType; - EnumType type = enumerated != null ? enumerated.value() : null; - scalarType = typeManager.createEnumScalarType(enumClass, type); - } - prop.setScalarType(scalarType); - prop.setDbType(scalarType.getJdbcType()); - } + try { + Class> enumClass = (Class>) enumType; + EnumType type = enumerated != null ? enumerated.value() : null; + ScalarType scalarType = typeManager.createEnumScalarType(enumClass, type); + prop.setScalarType(scalarType); + prop.setDbType(scalarType.getJdbcType()); - /** - * Return true if there is an existing default mapping for the enum that needs - * to be overridden (for example, DayOfWeek defaults to Integer mapping 1 to 7 - * and some might want this mapped to 'MONDAY' etc). - */ - private boolean enumOverrideDefaultMapping(Enumerated enumerated, ScalarType scalarType) { - return enumerated != null && scalarType != null - && enumerated.value() == EnumType.STRING - && scalarType.getJdbcType() != Types.VARCHAR; + } catch (IllegalStateException e) { + throw new PersistenceException("Error mapping property " + prop.getFullBeanName() + " - " + e.getMessage()); + } } /** @@ -304,7 +290,7 @@ public class DeployUtil { prop.setScalarType(scalarType); } - public boolean isClobType(Class type) { + private boolean isClobType(Class type) { return type.equals(String.class); } diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 439b4f347..1e3812b3a 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -271,6 +271,7 @@ public final class DefaultTypeManager implements TypeManager { public void addEnumType(ScalarType scalarType, Class enumClass) { Set> mappedClasses = new HashSet<>(); + mappedClasses.add(enumClass); for (Object value : EnumSet.allOf(enumClass).toArray()) { mappedClasses.add(value.getClass()); } @@ -552,7 +553,7 @@ public final class DefaultTypeManager implements TypeManager { * Return null if the EnumValue annotations are not present/used. *

*/ - private ScalarType createEnumScalarType2(Class enumType) { + private ScalarTypeEnum createEnumScalarType2(Class enumType) { boolean integerType = true; @@ -589,8 +590,11 @@ public final class DefaultTypeManager implements TypeManager { @Override public ScalarType createEnumScalarType(Class> enumType, EnumType type) { - ScalarType scalarType = getScalarType(enumType); - if (scalarType != null) { + ScalarTypeEnum scalarType = (ScalarTypeEnum) getScalarType(enumType); + if (scalarType != null && !scalarType.isOverrideBy(type)) { + if (type != null && !scalarType.isCompatible(type)) { + throw new IllegalStateException("Error mapping Enum type:"+enumType+" It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)"); + } return scalarType; } @@ -603,7 +607,7 @@ public final class DefaultTypeManager implements TypeManager { return scalarType; } - private ScalarType createEnumScalarTypePerSpec(Class enumType, EnumType type) { + private ScalarTypeEnum createEnumScalarTypePerSpec(Class enumType, EnumType type) { if (type == null) { // default as per spec is ORDINAL return new ScalarTypeEnumStandard.OrdinalEnum(enumType); @@ -616,7 +620,7 @@ public final class DefaultTypeManager implements TypeManager { } } - private ScalarType createEnumScalarTypePerExtentions(Class> enumType) { + private ScalarTypeEnum createEnumScalarTypePerExtentions(Class> enumType) { Method[] methods = enumType.getMethods(); for (Method method : methods) { @@ -638,7 +642,7 @@ public final class DefaultTypeManager implements TypeManager { * Return null if the EnumValue annotations are not present/used. *

*/ - private ScalarType createEnumScalarTypeDbValue(Class> enumType, Method method, boolean integerType) { + private ScalarTypeEnum createEnumScalarTypeDbValue(Class> enumType, Method method, boolean integerType) { Map nameValueMap = new HashMap<>(); @@ -664,7 +668,7 @@ public final class DefaultTypeManager implements TypeManager { * length create the ScalarType for the Enum. */ @SuppressWarnings({"unchecked", "rawtypes"}) - private ScalarType createEnumScalarType(Class enumType, Map nameValueMap, boolean integerType, int dbColumnLength) { + private ScalarTypeEnum createEnumScalarType(Class enumType, Map nameValueMap, boolean integerType, int dbColumnLength) { EnumToDbValueMap beanDbMap = EnumToDbValueMap.create(integerType); diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeDayOfWeek.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeDayOfWeek.java index 31a46c3fc..9bfc8abca 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeDayOfWeek.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeDayOfWeek.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.type; +import javax.persistence.EnumType; import java.sql.SQLException; import java.sql.Types; import java.time.DayOfWeek; @@ -22,6 +23,14 @@ public class ScalarTypeDayOfWeek extends ScalarTypeEnumWithMapping { super(beanDbMap, DayOfWeek.class, 1); } + /** + * We allow this to be overridden by a JPA EnumType. + */ + @Override + public boolean isOverrideBy(EnumType type) { + return type != null; + } + /** * Bind DayOfWeek enum using getValue(). */ diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnum.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnum.java index f01229e9d..1dc3de475 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnum.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnum.java @@ -1,15 +1,29 @@ package io.ebeaninternal.server.type; +import javax.persistence.EnumType; import java.util.Set; /** * Marker interface for the Enum scalar types. */ -public interface ScalarTypeEnum { +public interface ScalarTypeEnum extends ScalarType { /** * Return the IN values for DB constraint construction. */ Set getDbCheckConstraintValues(); + /** + * Return true if we allow this scalar enum type to be overridden. + * Ability to override the built-in support for java time DayOfWeek and Month. + */ + default boolean isOverrideBy(EnumType type) { + return false; + } + + /** + * Return true if the scalar type is compatible with the specified enum type. + */ + boolean isCompatible(EnumType enumType); + } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java index cbcf533ab..17a66a69b 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumStandard.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonParser; import io.ebean.text.TextException; import io.ebeanservice.docstore.api.mapping.DocPropertyType; +import javax.persistence.EnumType; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -40,6 +41,11 @@ public class ScalarTypeEnumStandard { this.length = maxValueLength(enumType); } + @Override + public boolean isCompatible(EnumType enumType) { + return EnumType.STRING == enumType; + } + /** * Return the IN values for DB constraint construction. */ @@ -128,6 +134,11 @@ public class ScalarTypeEnumStandard { this.enumArray = EnumSet.allOf(enumType).toArray(); } + @Override + public boolean isCompatible(EnumType enumType) { + return EnumType.ORDINAL == enumType; + } + /** * Return the IN values for DB constraint construction. */ diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java index 56e3674fc..fe996266b 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeEnumWithMapping.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.type; +import javax.persistence.EnumType; import java.sql.SQLException; import java.util.Iterator; import java.util.LinkedHashSet; @@ -24,6 +25,11 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i this.length = length; } + @Override + public boolean isCompatible(EnumType enumType) { + return enumType == null; + } + @Override public long asVersion(Object value) { throw new RuntimeException("not supported"); diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonth.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonth.java index c4605cad9..0f86ed315 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonth.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonth.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.type; +import javax.persistence.EnumType; import java.sql.SQLException; import java.sql.Types; import java.time.Month; @@ -22,6 +23,14 @@ public class ScalarTypeMonth extends ScalarTypeEnumWithMapping { super(beanDbMap, Month.class, 1); } + /** + * We allow this to be overridden by a JPA EnumType. + */ + @Override + public boolean isOverrideBy(EnumType type) { + return type != null; + } + /** * Bind Month enum value. */ diff --git a/src/test/java/io/ebean/server/type/TestTypeManager.java b/src/test/java/io/ebean/server/type/TestTypeManager.java index 4e552b69f..e5ab13393 100644 --- a/src/test/java/io/ebean/server/type/TestTypeManager.java +++ b/src/test/java/io/ebean/server/type/TestTypeManager.java @@ -12,10 +12,12 @@ import org.junit.Test; import org.tests.model.ivo.Money; import org.tests.model.ivo.converter.MoneyTypeConverter; +import javax.persistence.EnumType; import java.sql.SQLException; import java.sql.Types; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; public class TestTypeManager extends BaseTestCase { @@ -42,6 +44,13 @@ public class TestTypeManager extends BaseTestCase { assertThat(typeA).isNotNull(); ScalarType typeC = typeManager.getScalarType(MyEnum.Cval.getClass()); assertThat(typeC).isNotNull(); + + try { + typeManager.createEnumScalarType(MyEnum.class, EnumType.STRING); + assertTrue("never get here",false); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } } @Test @@ -65,6 +74,13 @@ public class TestTypeManager extends BaseTestCase { val = dayOfWeekType.read(new DummyDataReader("FRIDAY ")); assertThat(val).isEqualTo(MyDayOfWeek.FRIDAY); + + try { + typeManager.createEnumScalarType(MyDayOfWeek.class, EnumType.ORDINAL); + assertTrue("never get here",false); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } } @Test @@ -73,8 +89,8 @@ public class TestTypeManager extends BaseTestCase { DefaultTypeManager typeManager = createTypeManager(); ScalarType scalarType = typeManager.getScalarType(Money.class); - Assert.assertTrue(scalarType.getJdbcType() == Types.DECIMAL); - Assert.assertTrue(!scalarType.isJdbcNative()); + assertTrue(scalarType.getJdbcType() == Types.DECIMAL); + assertTrue(!scalarType.isJdbcNative()); Assert.assertEquals(Money.class, scalarType.getType()); } diff --git a/src/test/java/io/ebeaninternal/server/type/DefaultTypeManagerTest.java b/src/test/java/io/ebeaninternal/server/type/DefaultTypeManagerTest.java index 635f64d04..b03a452f4 100644 --- a/src/test/java/io/ebeaninternal/server/type/DefaultTypeManagerTest.java +++ b/src/test/java/io/ebeaninternal/server/type/DefaultTypeManagerTest.java @@ -5,23 +5,28 @@ import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebeaninternal.server.core.bootup.BootupClasses; import org.junit.Test; +import javax.persistence.EnumType; +import java.time.DayOfWeek; +import java.time.Month; + +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class DefaultTypeManagerTest { - DefaultTypeManager typeManager; - - public DefaultTypeManagerTest() { + private DefaultTypeManager create() { ServerConfig serverConfig = new ServerConfig(); serverConfig.setDatabasePlatform(new PostgresPlatform()); BootupClasses bootupClasses = new BootupClasses(); - typeManager = new DefaultTypeManager(serverConfig, bootupClasses); + return new DefaultTypeManager(serverConfig, bootupClasses); } @Test public void isIntegerType() { + DefaultTypeManager typeManager = create(); + assertTrue(typeManager.isIntegerType("1")); assertTrue(typeManager.isIntegerType("0")); @@ -33,4 +38,82 @@ public class DefaultTypeManagerTest { assertFalse(typeManager.isIntegerType(" A")); } + + @Test + public void enumDayMonth_builtIn_overrideAsString() { + + DefaultTypeManager typeManager = create(); + + ScalarType type = typeManager.createEnumScalarType(Month.class, null); + assertThat(type).isInstanceOf(ScalarTypeEnumWithMapping.class).as("built in type"); + + // mapped explicitly as JPA EnumType.STRING + type = typeManager.createEnumScalarType(Month.class, EnumType.STRING); + assertThat(type).isInstanceOf(ScalarTypeEnumStandard.StringEnum.class).as("override built in type"); + + try { + typeManager.createEnumScalarType(Month.class, EnumType.ORDINAL); + assertThat(true).isFalse().as("never get here"); + + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } + } + + @Test + public void enumMonth_builtIn_overrideAsOrdinal() { + + DefaultTypeManager typeManager = create(); + + // mapped explicitly as JPA EnumType.STRING + ScalarType type = typeManager.createEnumScalarType(Month.class, EnumType.ORDINAL); + assertThat(type).isInstanceOf(ScalarTypeEnumStandard.OrdinalEnum.class).as("override built in type"); + + try { + typeManager.createEnumScalarType(Month.class, EnumType.STRING); + assertThat(true).isFalse().as("never get here"); + + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } + } + + @Test + public void enumDayOfWeek_builtIn_overrideAsString() { + + DefaultTypeManager typeManager = create(); + + ScalarType type = typeManager.createEnumScalarType(DayOfWeek.class, null); + assertThat(type).isInstanceOf(ScalarTypeEnumWithMapping.class).as("built in type"); + + // mapped explicitly as JPA EnumType.STRING + type = typeManager.createEnumScalarType(DayOfWeek.class, EnumType.STRING); + assertThat(type).isInstanceOf(ScalarTypeEnumStandard.StringEnum.class).as("override built in type"); + + try { + typeManager.createEnumScalarType(DayOfWeek.class, EnumType.ORDINAL); + assertThat(true).isFalse().as("never get here"); + + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } + } + + @Test + public void enumDayOfWeek_builtIn_overrideAsOrdinal() { + + DefaultTypeManager typeManager = create(); + + // mapped explicitly as JPA EnumType.STRING + ScalarType type = typeManager.createEnumScalarType(DayOfWeek.class, EnumType.ORDINAL); + assertThat(type).isInstanceOf(ScalarTypeEnumStandard.OrdinalEnum.class).as("override built in type"); + + try { + typeManager.createEnumScalarType(DayOfWeek.class, EnumType.STRING); + assertThat(true).isFalse().as("never get here"); + + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("It is mapped using 2 different modes when only one is supported"); + } + } } From 2a986ab590f4866bbe5e86bee5a6dce34002c9e2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 15:28:13 +1300 Subject: [PATCH 0017/1036] #1260 - Mark query.setForUpdate(true) as deprecated - migrate to query.forUpdate() --- src/main/java/io/ebean/Query.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java index 53499f9c6..8d61e223c 100644 --- a/src/main/java/io/ebean/Query.java +++ b/src/main/java/io/ebean/Query.java @@ -1436,9 +1436,12 @@ public interface Query { String getGeneratedSql(); /** + * Deprecated - migrate to forUpdate(). + * * executed the select with "for update" which should lock the record * "on read" */ + @Deprecated Query setForUpdate(boolean forUpdate); /** From 4bd9e6770342f4c094903b9eaf76370dbce29a2a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 15:29:12 +1300 Subject: [PATCH 0018/1036] [maven-release-plugin] prepare release ebean-11.10.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a2da3dc05..48881fbd1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.4-SNAPSHOT + 11.10.4 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.10.4 From d9125db9575547755a35e425f8e94746412e0762 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 15:29:26 +1300 Subject: [PATCH 0019/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 48881fbd1..621a03706 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.4 + 11.10.5-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.10.4 + HEAD From 6db9a60f4f27a6f1a52ac348add85f8f1725fb10 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 17:24:14 +1300 Subject: [PATCH 0020/1036] #107 - Fix existing test - Ah ??? ... this PrimaryKeyJoinColumn was ignored and should never have been in this test. --- src/test/java/org/tests/model/onetoone/OtoBChild.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/tests/model/onetoone/OtoBChild.java b/src/test/java/org/tests/model/onetoone/OtoBChild.java index a2772a5e8..56c1b58a5 100644 --- a/src/test/java/org/tests/model/onetoone/OtoBChild.java +++ b/src/test/java/org/tests/model/onetoone/OtoBChild.java @@ -3,8 +3,8 @@ package org.tests.model.onetoone; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; +import javax.persistence.JoinColumn; import javax.persistence.OneToOne; -import javax.persistence.PrimaryKeyJoinColumn; @Entity public class OtoBChild { @@ -16,7 +16,7 @@ public class OtoBChild { String child; @OneToOne - @PrimaryKeyJoinColumn(name = "master_id", referencedColumnName = "id") + @JoinColumn(name = "master_id", referencedColumnName = "id") OtoBMaster master; public Long getId() { From 842292ef6b95434ee787eaa512071a964c835b92 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 22:59:57 +1300 Subject: [PATCH 0021/1036] #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns --- .../build/ModelBuildPropertyVisitor.java | 10 ++- .../server/deploy/BeanCascadeInfo.java | 2 +- .../server/deploy/BeanDescriptor.java | 6 ++ .../server/deploy/BeanDescriptorManager.java | 8 ++ .../server/deploy/BeanPropertyAssocOne.java | 19 ++-- .../server/deploy/BeanTable.java | 9 ++ .../deploy/meta/DeployBeanDescriptor.java | 21 ++++- .../meta/DeployBeanPropertyAssocOne.java | 10 +++ .../deploy/parse/AnnotationAssocOnes.java | 64 +++++++++++--- .../server/deploy/parse/DeployBeanInfo.java | 10 ++- .../org/tests/model/onetoone/OtoPrime.java | 67 ++++++++++++++ .../tests/model/onetoone/OtoPrimeExtra.java | 49 +++++++++++ .../onetoone/TestOneToOnePrimaryKeyJoin.java | 87 +++++++++++++++++++ 13 files changed, 337 insertions(+), 25 deletions(-) create mode 100644 src/test/java/org/tests/model/onetoone/OtoPrime.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoPrimeExtra.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index 719dcbfcc..ba90cdd1c 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -11,6 +11,7 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoinColumn; import io.ebeaninternal.server.deploy.id.ImportedId; @@ -148,8 +149,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { TableJoinColumn[] columns = p.getTableJoin().columns(); if (columns.length == 0) { - String msg = "No join columns for " + p.getFullBeanName(); - throw new RuntimeException(msg); + throw new RuntimeException("No join columns for " + p.getFullBeanName()); } ImportedId importedId = p.getImportedId(); @@ -231,6 +231,12 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { if (p.getBeanDescriptor().isUseIdGenerator()) { col.setIdentity(true); } + TableJoin primaryKeyJoin = p.getBeanDescriptor().getPrimaryKeyJoin(); + if (primaryKeyJoin != null) { + TableJoinColumn[] columns = primaryKeyJoin.columns(); + col.setReferences(primaryKeyJoin.getTable() + "." + columns[0].getForeignDbColumn()); + col.setForeignKeyName(determineForeignKeyConstraintName(col.getName())); + } } else { col.setDefaultValue(p.getDbColumnDefault()); col.setDbMigrationInfos(p.getDbMigrationInfos()); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCascadeInfo.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCascadeInfo.java index 54801eae9..af231db1d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCascadeInfo.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCascadeInfo.java @@ -22,7 +22,7 @@ public class BeanCascadeInfo { } } - private void setType(CascadeType type) { + public void setType(CascadeType type) { switch (type) { case ALL: save = true; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 3a225cc92..c5b82b19d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -179,6 +179,7 @@ public class BeanDescriptor implements BeanType { private final String baseTableAsOf; private final String baseTableVersionsBetween; private final boolean historySupport; + private final TableJoin primaryKeyJoin; private final BeanProperty softDeleteProperty; private final boolean softDelete; @@ -454,6 +455,7 @@ public class BeanDescriptor implements BeanType { this.draftTable = deploy.getDraftTable(); this.baseTable = InternString.intern(deploy.getBaseTable()); this.baseTableAsOf = deploy.getBaseTableAsOf(); + this.primaryKeyJoin = deploy.getPrimaryKeyJoin(); this.baseTableVersionsBetween = deploy.getBaseTableVersionsBetween(); this.dependentTables = deploy.getDependentTables(); this.dbComment = deploy.getDbComment(); @@ -2888,6 +2890,10 @@ public class BeanDescriptor implements BeanType { } } + public TableJoin getPrimaryKeyJoin() { + return primaryKeyJoin; + } + @Override public BeanProperty getIdProperty() { return idProperty; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 20c7396e7..c9341c74a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1546,6 +1546,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return changeLogListener; } + public void addPrimaryKeyJoin(DeployBeanPropertyAssocOne prop, DeployTableJoin inverse) { + + TableJoin inverseJoin = new TableJoin(inverse); + + DeployBeanInfo target = deployInfoMap.get(prop.getTargetType()); + target.setPrimaryKeyJoin(inverseJoin); + } + /** * Comparator to sort the BeanDescriptors by name. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 6aabd4927..2bc1bd27c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -39,15 +39,14 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { private final boolean importedPrimaryKey; + private final boolean primaryKeyExport; + private AssocOneHelp localHelp; protected final BeanProperty[] embeddedProps; private final HashMap embeddedPropsMap; - /** - * The information for Imported foreign Keys. - */ protected ImportedId importedId; private String deleteByParentIdSql; @@ -70,6 +69,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { super(descriptor, deploy); + primaryKeyExport = deploy.isPrimaryKeyExport(); importedPrimaryKey = deploy.isImportedPrimaryKey(); oneToOne = deploy.isOneToOne(); oneToOneExported = deploy.isOneToOneExported(); @@ -550,13 +550,17 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { @Override public void appendSelect(DbSqlContext ctx, boolean subQuery) { if (!isTransient) { - localHelp.appendSelect(ctx, subQuery); + if (primaryKeyExport) { + descriptor.getIdProperty().appendSelect(ctx, subQuery); + } else { + localHelp.appendSelect(ctx, subQuery); + } } } @Override public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { - if (!isTransient) { + if (!isTransient && !primaryKeyExport) { localHelp.appendFrom(ctx, joinType); if (sqlFormulaJoin != null) { ctx.appendFormulaJoin(sqlFormulaJoin, joinType); @@ -734,6 +738,11 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { */ public void setParentBeanToChild(EntityBean parent, EntityBean child) { + if (primaryKeyExport) { + Object parentId = descriptor.getId(parent); + targetDescriptor.convertSetId(parentId, child); + } + if (mappedBy != null) { BeanProperty beanProperty = targetDescriptor.getBeanProperty(mappedBy); if (beanProperty != null && beanProperty.getValue(child) == null) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java index a091aa979..d9e3e1413 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java @@ -121,4 +121,13 @@ public class BeanTable { } + /** + * Return the primary key DB column. + */ + public String getIdColumn() { + if (idProperties.length != 1) { + throw new IllegalStateException("Expecting only one Id column to join to on "+beanType); + } + return idProperties[0].dbColumn; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 396c3e06e..2e8b4165c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -27,6 +27,7 @@ import io.ebeaninternal.server.deploy.ChainedBeanPostLoad; import io.ebeaninternal.server.deploy.ChainedBeanQueryAdapter; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.parse.DeployBeanInfo; import io.ebeaninternal.server.idgen.UuidIdGenerator; import io.ebeaninternal.server.rawsql.SpiRawSql; @@ -55,10 +56,7 @@ public class DeployBeanDescriptor { @Override public int compare(DeployBeanProperty o1, DeployBeanProperty o2) { - - int v2 = o1.getSortOrder(); - int v1 = o2.getSortOrder(); - return (v1 < v2 ? -1 : (v1 == v2 ? 0 : 1)); + return Integer.compare(o2.getSortOrder(), o1.getSortOrder()); } } @@ -203,6 +201,7 @@ public class DeployBeanDescriptor { private DocStoreMode docStoreDelete; private List idProperties; + private TableJoin primaryKeyJoin; private short profileId; @@ -215,6 +214,20 @@ public class DeployBeanDescriptor { this.beanType = beanType; } + /** + * PK is also a FK. + */ + public void setPrimaryKeyJoin(TableJoin join) { + this.primaryKeyJoin = join; + this.idType = IdType.EXTERNAL; + this.idGeneratorName = null; + this.idGenerator = null; + } + + public TableJoin getPrimaryKeyJoin() { + return primaryKeyJoin; + } + /** * Return the DeployBeanInfo for the given bean class. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index fff547d9c..dc21bbe82 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -9,6 +9,8 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { private boolean oneToOneExported; + private boolean primaryKeyExport; + private boolean importedPrimaryKey; private DeployBeanEmbedded deployEmbedded; @@ -115,4 +117,12 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { public String getColumnPrefix() { return columnPrefix; } + + public void setPrimaryKeyExport() { + this.primaryKeyExport = true; + } + + public boolean isPrimaryKeyExport() { + return primaryKeyExport; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index be49ab616..985608df7 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -6,9 +6,15 @@ import io.ebean.config.NamingConvention; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.BeanTable; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; +import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.meta.DeployTableJoin; +import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; import io.ebeaninternal.server.query.SqlJoinType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; @@ -17,6 +23,7 @@ import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToOne; import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; import javax.validation.constraints.NotNull; /** @@ -24,12 +31,14 @@ import javax.validation.constraints.NotNull; */ public class AnnotationAssocOnes extends AnnotationParser { + private static final Logger log = LoggerFactory.getLogger(AnnotationAssocOnes.class); + private final BeanDescriptorManager factory; /** * Create with the deploy Info. */ - public AnnotationAssocOnes(DeployBeanInfo info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) { + AnnotationAssocOnes(DeployBeanInfo info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) { super(info, javaxValidationAnnotations); this.factory = factory; } @@ -88,6 +97,11 @@ public class AnnotationAssocOnes extends AnnotationParser { prop.setExtraWhere(where.clause()); } + PrimaryKeyJoinColumn primaryKeyJoin = get(prop, PrimaryKeyJoinColumn.class); + if (primaryKeyJoin != null) { + readPrimaryKeyJoin(primaryKeyJoin, prop); + } + FetchPreference fetchPreference = get(prop, FetchPreference.class); if (fetchPreference != null) { prop.setFetchPreference(fetchPreference.value()); @@ -156,18 +170,21 @@ public class AnnotationAssocOnes extends AnnotationParser { return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered?"; } + private BeanTable beanTable(DeployBeanPropertyAssoc prop) { + BeanTable assoc = factory.getBeanTable(prop.getPropertyType()); + if (assoc == null) { + throw new RuntimeException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName())); + } + return assoc; + } + private void readManyToOne(ManyToOne propAnn, DeployBeanProperty prop) { DeployBeanPropertyAssocOne beanProp = (DeployBeanPropertyAssocOne) prop; setCascadeTypes(propAnn.cascade(), beanProp.getCascadeInfo()); - BeanTable assoc = factory.getBeanTable(beanProp.getPropertyType()); - if (assoc == null) { - String msg = errorMsgMissingBeanTable(beanProp.getPropertyType(), prop.getFullBeanName()); - throw new RuntimeException(msg); - } - beanProp.setBeanTable(assoc); + beanProp.setBeanTable(beanTable(beanProp)); beanProp.setDbInsertable(true); beanProp.setDbUpdateable(true); beanProp.setNullable(propAnn.optional()); @@ -187,14 +204,37 @@ public class AnnotationAssocOnes extends AnnotationParser { } setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo()); + prop.setBeanTable(beanTable(prop)); + } - BeanTable assoc = factory.getBeanTable(prop.getPropertyType()); - if (assoc == null) { - String msg = errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName()); - throw new RuntimeException(msg); + private void readPrimaryKeyJoin(PrimaryKeyJoinColumn primaryKeyJoin, DeployBeanPropertyAssocOne prop) { + + if (!prop.isOneToOne()) { + throw new IllegalStateException("Expecting property " + prop.getFullBeanName() + " with PrimaryKeyJoinColumn to be a OneToOne?"); + } + prop.setPrimaryKeyExport(); + prop.setOneToOneExported(); + if (!prop.getCascadeInfo().isSave()) { + // we pretty much need to cascade save so turning that on automatically ... + prop.getCascadeInfo().setType(CascadeType.ALL); } - prop.setBeanTable(assoc); + if (!primaryKeyJoin.name().isEmpty()) { + log.warn("Automatically determining join columns and ignoring PrimaryKeyJoinColumn.name {} on {}", primaryKeyJoin.name(), prop.getFullBeanName()); + } + if (!primaryKeyJoin.referencedColumnName().isEmpty()) { + log.warn("Automatically determining join columns and Ignoring PrimaryKeyJoinColumn.referencedColumnName {} on {}", primaryKeyJoin.referencedColumnName(), prop.getFullBeanName()); + } + + BeanTable baseBeanTable = factory.getBeanTable(info.getDescriptor().getBeanType()); + + String localPrimaryKey = baseBeanTable.getIdColumn(); + String foreignColumn = beanTable(prop).getIdColumn(); + + prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localPrimaryKey, foreignColumn, false, false)); + + DeployTableJoin inverse = prop.getTableJoin().createInverse(baseBeanTable.getBaseTable()); + factory.addPrimaryKeyJoin(prop, inverse); } private void readEmbedded(DeployBeanPropertyAssocOne prop, Embedded embedded) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java index f84a9dd69..553e263c8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java @@ -1,11 +1,12 @@ package io.ebeaninternal.server.deploy.parse; import io.ebean.RawSql; -import io.ebeaninternal.server.rawsql.SpiRawSql; +import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.query.SqlJoinType; +import io.ebeaninternal.server.rawsql.SpiRawSql; import java.util.HashMap; @@ -91,4 +92,11 @@ public class DeployBeanInfo { public void addNamedQuery(String name, String query) { descriptor.addNamedQuery(name, query); } + + /** + * Set that the PK is also a foreign key. + */ + public void setPrimaryKeyJoin(TableJoin join) { + descriptor.setPrimaryKeyJoin(join); + } } diff --git a/src/test/java/org/tests/model/onetoone/OtoPrime.java b/src/test/java/org/tests/model/onetoone/OtoPrime.java new file mode 100644 index 000000000..d1f2ddb20 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoPrime.java @@ -0,0 +1,67 @@ +package org.tests.model.onetoone; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Version; + +@Entity +public class OtoPrime { + + @Id + Long pid; + + String name; + + /** + * Automatically set Cascade PERSIST and mapped by. + */ + @OneToOne(optional = false, cascade = CascadeType.ALL) //, mappedBy = "prime") + @PrimaryKeyJoinColumn + OtoPrimeExtra extra; + + @Version + Long version; + + public OtoPrime(String name) { + this.name = name; + } + + public String toString() { + return "id:"+ pid +" name:"+name+" extra:"+extra; + } + + public Long getPid() { + return pid; + } + + public void setPid(Long pid) { + this.pid = pid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OtoPrimeExtra getExtra() { + return extra; + } + + public void setExtra(OtoPrimeExtra extra) { + this.extra = extra; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/OtoPrimeExtra.java b/src/test/java/org/tests/model/onetoone/OtoPrimeExtra.java new file mode 100644 index 000000000..acb6fc28e --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoPrimeExtra.java @@ -0,0 +1,49 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class OtoPrimeExtra { + + @Id + Long eid; + + String extra; + + @Version + Long version; + + public OtoPrimeExtra(String extra) { + this.extra = extra; + } + + public String toString() { + return "exId:"+ eid +" "+extra; + } + + public Long getEid() { + return eid; + } + + public void setEid(Long eid) { + this.eid = eid; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java new file mode 100644 index 000000000..b2ab2d1c6 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java @@ -0,0 +1,87 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Query; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOnePrimaryKeyJoin extends BaseTestCase { + + + private OtoPrime insert(String desc) { + OtoPrime prime = new OtoPrime("p" + desc); + OtoPrimeExtra extra = new OtoPrimeExtra("e" + desc); + prime.setExtra(extra); + Ebean.save(prime); + return prime; + } + + @Test + public void insertUpdateDelete() { + + String desc = "" + System.currentTimeMillis(); + OtoPrime p1 = insert(desc); + + assertThat(p1.getExtra().getEid()).isEqualTo(p1.getPid()).as("Same id values"); + + + Query query = Ebean.find(OtoPrime.class).setId(p1.getPid()); + + OtoPrime found = query.findOne(); + + assertThat(found).isNotNull(); + assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_prime t0 where t0.pid = ?") + .as("we don't join to oto_prime_extra"); + + assertThat(found.getName()).isEqualTo("p" + desc); + + Query queryWithFetch = Ebean.find(OtoPrime.class) + .setId(p1.getPid()) + .fetch("extra"); + + OtoPrime oneWith = queryWithFetch.findOne(); + + assertThat(oneWith).isNotNull(); + assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_prime t0 join oto_prime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + .as("we join to oto_prime_extra"); + + + assertThat(oneWith.getExtra().getExtra()).isEqualTo("e" + desc); + + thenUpdate(oneWith); + thenDelete(found); + } + + private void thenUpdate(OtoPrime oneWith) { + + OtoPrimeExtra extra = oneWith.getExtra(); + extra.setExtra("modified"); + + Ebean.save(oneWith); + + extra.setExtra("mod2"); + oneWith.setName("mod2"); + + Ebean.save(oneWith); + } + + private void thenDelete(OtoPrime found) { + + + OtoPrime bean = Ebean.find(OtoPrime.class, found.getPid()); + + LoggedSqlCollector.start(); + Ebean.delete(bean); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from oto_prime_extra where"); + assertThat(sql.get(1)).contains("delete from oto_prime where"); + + } +} From 6a067c0cf718643ab7e7892ff5a3522e6276160f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Feb 2018 23:09:10 +1300 Subject: [PATCH 0022/1036] #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns Extra test with UUID and optional OneToOne so has left join --- .../org/tests/model/onetoone/OtoPrime.java | 3 +- .../org/tests/model/onetoone/OtoUPrime.java | 68 +++++++++++++++ .../tests/model/onetoone/OtoUPrimeExtra.java | 50 +++++++++++ .../TestOneToOnePrimaryKeyJoinOptional.java | 87 +++++++++++++++++++ 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/tests/model/onetoone/OtoUPrime.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoUPrimeExtra.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java diff --git a/src/test/java/org/tests/model/onetoone/OtoPrime.java b/src/test/java/org/tests/model/onetoone/OtoPrime.java index d1f2ddb20..771b2de9b 100644 --- a/src/test/java/org/tests/model/onetoone/OtoPrime.java +++ b/src/test/java/org/tests/model/onetoone/OtoPrime.java @@ -17,8 +17,9 @@ public class OtoPrime { /** * Automatically set Cascade PERSIST and mapped by. + * OneToOne not optional so inner join to extra. */ - @OneToOne(optional = false, cascade = CascadeType.ALL) //, mappedBy = "prime") + @OneToOne(optional = false, cascade = CascadeType.ALL) @PrimaryKeyJoinColumn OtoPrimeExtra extra; diff --git a/src/test/java/org/tests/model/onetoone/OtoUPrime.java b/src/test/java/org/tests/model/onetoone/OtoUPrime.java new file mode 100644 index 000000000..052dbf876 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoUPrime.java @@ -0,0 +1,68 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Version; +import java.util.UUID; + +@Entity +public class OtoUPrime { + + @Id + UUID pid; + + String name; + + /** + * Effectively Ebean automatically sets Cascade PERSIST and mapped by for PrimaryKeyJoinColumn. + * This OneToOne is optional so left join to extra. + */ + @OneToOne + @PrimaryKeyJoinColumn + OtoUPrimeExtra extra; + + @Version + Long version; + + public OtoUPrime(String name) { + this.name = name; + } + + public String toString() { + return "id:"+ pid +" name:"+name+" extra:"+extra; + } + + public UUID getPid() { + return pid; + } + + public void setPid(UUID pid) { + this.pid = pid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OtoUPrimeExtra getExtra() { + return extra; + } + + public void setExtra(OtoUPrimeExtra extra) { + this.extra = extra; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/OtoUPrimeExtra.java b/src/test/java/org/tests/model/onetoone/OtoUPrimeExtra.java new file mode 100644 index 000000000..7c3fae318 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoUPrimeExtra.java @@ -0,0 +1,50 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; +import java.util.UUID; + +@Entity +public class OtoUPrimeExtra { + + @Id + UUID eid; + + String extra; + + @Version + Long version; + + public OtoUPrimeExtra(String extra) { + this.extra = extra; + } + + public String toString() { + return "exId:"+ eid +" "+extra; + } + + public UUID getEid() { + return eid; + } + + public void setEid(UUID eid) { + this.eid = eid; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java new file mode 100644 index 000000000..64835b68b --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java @@ -0,0 +1,87 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Query; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOnePrimaryKeyJoinOptional extends BaseTestCase { + + + private OtoUPrime insert(String desc) { + OtoUPrime prime = new OtoUPrime("u" + desc); + OtoUPrimeExtra extra = new OtoUPrimeExtra("v" + desc); + prime.setExtra(extra); + Ebean.save(prime); + return prime; + } + + @Test + public void insertUpdateDelete() { + + String desc = "" + System.currentTimeMillis(); + OtoUPrime p1 = insert(desc); + + assertThat(p1.getExtra().getEid()).isEqualTo(p1.getPid()).as("Same id values"); + + + Query query = Ebean.find(OtoUPrime.class).setId(p1.getPid()); + + OtoUPrime found = query.findOne(); + + assertThat(found).isNotNull(); + assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_uprime t0 where t0.pid = ?") + .as("we don't join to oto_uprime_extra"); + + assertThat(found.getName()).isEqualTo("u" + desc); + + Query queryWithFetch = Ebean.find(OtoUPrime.class) + .setId(p1.getPid()) + .fetch("extra"); + + OtoUPrime oneWith = queryWithFetch.findOne(); + + assertThat(oneWith).isNotNull(); + assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_uprime t0 left join oto_uprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + .as("we join to oto_prime_extra"); + + + assertThat(oneWith.getExtra().getExtra()).isEqualTo("v" + desc); + + thenUpdate(oneWith); + thenDelete(found); + } + + private void thenUpdate(OtoUPrime oneWith) { + + OtoUPrimeExtra extra = oneWith.getExtra(); + extra.setExtra("modified"); + + Ebean.save(oneWith); + + extra.setExtra("mod2"); + oneWith.setName("mod2"); + + Ebean.save(oneWith); + } + + private void thenDelete(OtoUPrime found) { + + + OtoUPrime bean = Ebean.find(OtoUPrime.class, found.getPid()); + + LoggedSqlCollector.start(); + Ebean.delete(bean); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from oto_uprime_extra where"); + assertThat(sql.get(1)).contains("delete from oto_uprime where"); + + } +} From 31cac603938a9c2553ee6989c0fca3be2accd2fb Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Feb 2018 00:49:51 +1300 Subject: [PATCH 0023/1036] #107 - Mapping - Add support for @PrimaryKeyJoinColumn/@PrimaryKeyJoinColumns Adds Bi-directional support --- .../server/deploy/BeanDescriptorManager.java | 30 ++++++- .../deploy/meta/DeployBeanProperty.java | 6 +- .../deploy/meta/DeployBeanPropertyAssoc.java | 2 +- .../meta/DeployBeanPropertyAssocOne.java | 27 +++++- .../deploy/parse/AnnotationAssocOnes.java | 12 +-- .../org/tests/model/onetoone/OtoUBPrime.java | 65 ++++++++++++++ .../tests/model/onetoone/OtoUBPrimeExtra.java | 67 ++++++++++++++ .../TestOneToOnePrimaryKeyJoinBidi.java | 87 +++++++++++++++++++ 8 files changed, 278 insertions(+), 18 deletions(-) create mode 100644 src/test/java/org/tests/model/onetoone/OtoUBPrime.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoUBPrimeExtra.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index c9341c74a..d9452bc8f 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -797,8 +797,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // We only perform 'circular' checks etc after we have // all the DeployBeanDescriptors created and in the map. + List> primaryKeyJoinCheck = new ArrayList<>(); for (DeployBeanInfo info : deployInfoMap.values()) { - checkMappedBy(info); + checkMappedBy(info, primaryKeyJoinCheck); + } + for (DeployBeanPropertyAssocOne prop : primaryKeyJoinCheck) { + checkUniDirectionalPrimaryKeyJoin(prop); } for (DeployBeanInfo info : deployInfoMap.values()) { @@ -868,12 +872,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap { * relationships. *

*/ - private void checkMappedBy(DeployBeanInfo info) { + private void checkMappedBy(DeployBeanInfo info, List> primaryKeyJoinCheck) { for (DeployBeanPropertyAssocOne oneProp : info.getDescriptor().propertiesAssocOne()) { if (!oneProp.isTransient()) { if (oneProp.getMappedBy() != null) { checkMappedByOneToOne(oneProp); + } else if (oneProp.isPrimaryKeyJoin()) { + primaryKeyJoinCheck.add(oneProp); } } } @@ -1071,6 +1077,21 @@ public class BeanDescriptorManager implements BeanDescriptorMap { DeployTableJoin otherTableJoin = mappedAssocOne.getTableJoin(); otherTableJoin.copyWithoutType(tableJoin, true, tableJoin.getTable()); } + + if (mappedAssocOne.isPrimaryKeyJoin()) { + // bi-directional PrimaryKeyJoin ... + mappedAssocOne.setPrimaryKeyJoin(false); + prop.setPrimaryKeyExport(); + addPrimaryKeyJoin(prop); + } + } + + private void checkUniDirectionalPrimaryKeyJoin(DeployBeanPropertyAssocOne prop) { + if (prop.isPrimaryKeyJoin()) { + // uni-directional PrimaryKeyJoin ... + prop.setPrimaryKeyExport(); + addPrimaryKeyJoin(prop); + } } /** @@ -1546,7 +1567,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return changeLogListener; } - public void addPrimaryKeyJoin(DeployBeanPropertyAssocOne prop, DeployTableJoin inverse) { + public void addPrimaryKeyJoin(DeployBeanPropertyAssocOne prop) { + + String baseTable = prop.getDesc().getBaseTable(); + DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable); TableJoin inverseJoin = new TableJoin(inverse); diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index c588028f5..5e2cfa517 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -17,8 +17,8 @@ import io.ebean.config.dbplatform.DbEncryptFunction; import io.ebean.util.AnnotationUtil; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.DeployDocPropertyOptions; import io.ebeaninternal.server.deploy.DbMigrationInfo; +import io.ebeaninternal.server.deploy.DeployDocPropertyOptions; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.properties.BeanPropertyGetter; @@ -284,6 +284,10 @@ public class DeployBeanProperty { return desc.getFullName() + "." + name; } + public DeployBeanDescriptor getDesc() { + return desc; + } + /** * Return the DB column length for character columns. *

diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java index e0bbc9f0e..cbe3dc48f 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java @@ -16,7 +16,7 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty { /** * Persist settings. */ - private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo(); + protected final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo(); /** * The join table information. diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index dc21bbe82..9e257def2 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -1,5 +1,7 @@ package io.ebeaninternal.server.deploy.meta; +import javax.persistence.CascadeType; + /** * Property mapped to a joined bean. */ @@ -9,6 +11,8 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { private boolean oneToOneExported; + private boolean primaryKeyJoin; + private boolean primaryKeyExport; private boolean importedPrimaryKey; @@ -118,11 +122,30 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { return columnPrefix; } - public void setPrimaryKeyExport() { - this.primaryKeyExport = true; + /** + * Mark as PrimaryKeyJoin (we don't know which side is the export side initially). + */ + public void setPrimaryKeyJoin(boolean primaryKeyJoin) { + this.primaryKeyJoin = primaryKeyJoin; + } + + public boolean isPrimaryKeyJoin() { + return primaryKeyJoin; } public boolean isPrimaryKeyExport() { return primaryKeyExport; } + + /** + * Set as export side of OneToOne with PrimaryKeyJoin. + */ + public void setPrimaryKeyExport() { + this.primaryKeyExport = true; + this.oneToOneExported = true; + if (!cascadeInfo.isSave()) { + // we pretty much need to cascade save so turning that on automatically ... + cascadeInfo.setType(CascadeType.ALL); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 985608df7..4e5b04e36 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -8,13 +8,11 @@ import io.ebeaninternal.server.deploy.BeanTable; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; -import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; import io.ebeaninternal.server.query.SqlJoinType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; @@ -212,12 +210,7 @@ public class AnnotationAssocOnes extends AnnotationParser { if (!prop.isOneToOne()) { throw new IllegalStateException("Expecting property " + prop.getFullBeanName() + " with PrimaryKeyJoinColumn to be a OneToOne?"); } - prop.setPrimaryKeyExport(); - prop.setOneToOneExported(); - if (!prop.getCascadeInfo().isSave()) { - // we pretty much need to cascade save so turning that on automatically ... - prop.getCascadeInfo().setType(CascadeType.ALL); - } + prop.setPrimaryKeyJoin(true); if (!primaryKeyJoin.name().isEmpty()) { log.warn("Automatically determining join columns and ignoring PrimaryKeyJoinColumn.name {} on {}", primaryKeyJoin.name(), prop.getFullBeanName()); @@ -232,9 +225,6 @@ public class AnnotationAssocOnes extends AnnotationParser { String foreignColumn = beanTable(prop).getIdColumn(); prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localPrimaryKey, foreignColumn, false, false)); - - DeployTableJoin inverse = prop.getTableJoin().createInverse(baseBeanTable.getBaseTable()); - factory.addPrimaryKeyJoin(prop, inverse); } private void readEmbedded(DeployBeanPropertyAssocOne prop, Embedded embedded) { diff --git a/src/test/java/org/tests/model/onetoone/OtoUBPrime.java b/src/test/java/org/tests/model/onetoone/OtoUBPrime.java new file mode 100644 index 000000000..9416135c6 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoUBPrime.java @@ -0,0 +1,65 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; +import java.util.UUID; + +@Entity +public class OtoUBPrime { + + @Id + UUID pid; + + String name; + + /** + * Master side of bi-directional PrimaryJoinColumn. + */ + @OneToOne(mappedBy = "prime") + OtoUBPrimeExtra extra; + + @Version + Long version; + + public OtoUBPrime(String name) { + this.name = name; + } + + public String toString() { + return "id:"+ pid +" name:"+name+" extra:"+extra; + } + + public UUID getPid() { + return pid; + } + + public void setPid(UUID pid) { + this.pid = pid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OtoUBPrimeExtra getExtra() { + return extra; + } + + public void setExtra(OtoUBPrimeExtra extra) { + this.extra = extra; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/OtoUBPrimeExtra.java b/src/test/java/org/tests/model/onetoone/OtoUBPrimeExtra.java new file mode 100644 index 000000000..3b50b73f8 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoUBPrimeExtra.java @@ -0,0 +1,67 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.Version; +import java.util.UUID; + +@Entity +public class OtoUBPrimeExtra { + + @Id + UUID eid; + + String extra; + + /** + * Child side of bi-directional PrimaryJoinColumn. + */ + @OneToOne + @PrimaryKeyJoinColumn + OtoUBPrime prime; + + @Version + Long version; + + public OtoUBPrimeExtra(String extra) { + this.extra = extra; + } + + public String toString() { + return "exId:" + eid + " " + extra; + } + + public UUID getEid() { + return eid; + } + + public void setEid(UUID eid) { + this.eid = eid; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + + public OtoUBPrime getPrime() { + return prime; + } + + public void setPrime(OtoUBPrime prime) { + this.prime = prime; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java new file mode 100644 index 000000000..8becdfe02 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java @@ -0,0 +1,87 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Query; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOnePrimaryKeyJoinBidi extends BaseTestCase { + + + private OtoUBPrime insert(String desc) { + OtoUBPrime prime = new OtoUBPrime("u" + desc); + OtoUBPrimeExtra extra = new OtoUBPrimeExtra("v" + desc); + prime.setExtra(extra); + Ebean.save(prime); + return prime; + } + + @Test + public void insertUpdateDelete() { + + String desc = "" + System.currentTimeMillis(); + OtoUBPrime p1 = insert(desc); + + assertThat(p1.getExtra().getEid()).isEqualTo(p1.getPid()).as("Same id values"); + + + Query query = Ebean.find(OtoUBPrime.class).setId(p1.getPid()); + + OtoUBPrime found = query.findOne(); + + assertThat(found).isNotNull(); + assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_ubprime t0 where t0.pid = ?") + .as("we don't join to oto_ubprime_extra"); + + assertThat(found.getName()).isEqualTo("u" + desc); + + Query queryWithFetch = Ebean.find(OtoUBPrime.class) + .setId(p1.getPid()) + .fetch("extra"); + + OtoUBPrime oneWith = queryWithFetch.findOne(); + + assertThat(oneWith).isNotNull(); + assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version, t1.eid from oto_ubprime t0 left join oto_ubprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + .as("we join to oto_prime_extra"); + + + assertThat(oneWith.getExtra().getExtra()).isEqualTo("v" + desc); + + thenUpdate(oneWith); + thenDelete(found); + } + + private void thenUpdate(OtoUBPrime oneWith) { + + OtoUBPrimeExtra extra = oneWith.getExtra(); + extra.setExtra("modified"); + + Ebean.save(oneWith); + + extra.setExtra("mod2"); + oneWith.setName("mod2"); + + Ebean.save(oneWith); + } + + private void thenDelete(OtoUBPrime found) { + + + OtoUBPrime bean = Ebean.find(OtoUBPrime.class, found.getPid()); + + LoggedSqlCollector.start(); + Ebean.delete(bean); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from oto_ubprime_extra where"); + assertThat(sql.get(1)).contains("delete from oto_ubprime where"); + + } +} From 628af31dddedfcef0e36be1cf87a64de45d67290 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Feb 2018 22:31:41 +1300 Subject: [PATCH 0024/1036] #1142 - Mapping - Add support for @OrderColumn (Ebean automatically maintains an order column) --- .../java/io/ebean/bean/BeanCollection.java | 5 + .../io/ebean/bean/EntityBeanIntercept.java | 18 ++ .../ebean/common/AbstractBeanCollection.java | 7 +- .../java/io/ebean/common/ModifyHolder.java | 13 + .../server/deploy/BeanDescriptor.java | 9 + .../server/deploy/BeanDescriptorManager.java | 23 ++ .../server/deploy/BeanPropertyAssocMany.java | 10 + .../deploy/BeanPropertyOrderColumn.java | 36 +++ .../deploy/meta/DeployBeanDescriptor.java | 10 + .../meta/DeployBeanPropertyAssocMany.java | 30 ++- .../deploy/meta/DeployBeanPropertyLists.java | 26 +- .../server/deploy/meta/DeployOrderColumn.java | 39 +++ .../deploy/parse/AnnotationAssocManys.java | 11 + .../server/persist/DefaultPersister.java | 189 +------------- .../server/persist/SaveManyPropRequest.java | 247 ++++++++++++++++++ .../server/persist/dml/MetaFactory.java | 7 + .../persist/dmlbind/BindableOrderColumn.java | 37 +++ .../server/type/DefaultTypeManager.java | 4 +- .../server/type/ScalarTypeInteger.java | 8 +- .../server/type/ScalarTypeString.java | 8 +- .../org/tests/cascade/OmOrderedDetail.java | 57 ++++ .../org/tests/cascade/OmOrderedMaster.java | 63 +++++ .../org/tests/cascade/TestOrderedList.java | 98 +++++++ 23 files changed, 746 insertions(+), 209 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanPropertyOrderColumn.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/meta/DeployOrderColumn.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableOrderColumn.java create mode 100644 src/test/java/org/tests/cascade/OmOrderedDetail.java create mode 100644 src/test/java/org/tests/cascade/OmOrderedMaster.java create mode 100644 src/test/java/org/tests/cascade/TestOrderedList.java diff --git a/src/main/java/io/ebean/bean/BeanCollection.java b/src/main/java/io/ebean/bean/BeanCollection.java index 25d84de7d..28b17bd05 100644 --- a/src/main/java/io/ebean/bean/BeanCollection.java +++ b/src/main/java/io/ebean/bean/BeanCollection.java @@ -227,6 +227,11 @@ public interface BeanCollection extends Serializable { */ void modifyReset(); + /** + * Has been modified by an addition or removal. + */ + boolean wasTouched(); + /** * Return a shallow copy of this collection that is modifiable. */ diff --git a/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/src/main/java/io/ebean/bean/EntityBeanIntercept.java index cdeb21bba..17b1eac73 100644 --- a/src/main/java/io/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/io/ebean/bean/EntityBeanIntercept.java @@ -90,6 +90,7 @@ public final class EntityBeanIntercept implements Serializable { private int lazyLoadProperty = -1; private Object ownerId; + private int sortOrder; /** * Create a intercept with a given entity. @@ -693,6 +694,9 @@ public final class EntityBeanIntercept implements Serializable { * Add and return a dirty property hash recursing into embedded beans. */ private void addDirtyPropertyKey(StringBuilder sb) { + if (sortOrder > 0) { + sb.append("s,"); + } int len = getPropertyLength(); for (int i = 0; i < len; i++) { if (changedProps != null && changedProps[i]) { @@ -1050,4 +1054,18 @@ public final class EntityBeanIntercept implements Serializable { public void setOldValue(int propertyIndex, Object oldValue) { setChangedPropertyValue(propertyIndex, true, oldValue); } + + /** + * Return the sort order value for an order column. + */ + public int getSortOrder() { + return sortOrder; + } + + /** + * Set the sort order value for an order column. + */ + public void setSortOrder(int sortOrder) { + this.sortOrder = sortOrder; + } } diff --git a/src/main/java/io/ebean/common/AbstractBeanCollection.java b/src/main/java/io/ebean/common/AbstractBeanCollection.java index e13a6dc1d..d02c0ffc7 100644 --- a/src/main/java/io/ebean/common/AbstractBeanCollection.java +++ b/src/main/java/io/ebean/common/AbstractBeanCollection.java @@ -213,7 +213,12 @@ abstract class AbstractBeanCollection implements BeanCollection { boolean holdsModifications() { return modifyHolder != null && modifyHolder.hasModifications(); } - + + @Override + public boolean wasTouched() { + return modifyHolder != null && modifyHolder.wasTouched(); + } + /** * Copies all relevant properties for a clone. See {@link #getShallowCopy()} * @param other diff --git a/src/main/java/io/ebean/common/ModifyHolder.java b/src/main/java/io/ebean/common/ModifyHolder.java index 1e4008c32..247fb5cf2 100644 --- a/src/main/java/io/ebean/common/ModifyHolder.java +++ b/src/main/java/io/ebean/common/ModifyHolder.java @@ -28,7 +28,10 @@ class ModifyHolder implements Serializable { */ private Set modifyAdditions = new LinkedHashSet<>(); + private boolean touched; + void reset() { + touched = false; modifyDeletions = new LinkedHashSet<>(); modifyAdditions = new LinkedHashSet<>(); } @@ -50,6 +53,7 @@ class ModifyHolder implements Serializable { void modifyAddition(E bean) { if (bean != null) { + touched = true; // If it is to delete then just remove the deletion if (!undoDeletion(bean)) { // Insert @@ -65,6 +69,7 @@ class ModifyHolder implements Serializable { @SuppressWarnings("unchecked") void modifyRemoval(Object bean) { if (bean != null) { + touched = true; // If it is to be added then just remove the addition if (!undoAddition(bean)) { modifyDeletions.add((E) bean); @@ -80,6 +85,14 @@ class ModifyHolder implements Serializable { return modifyDeletions; } + /** + * Return true if the collection was touched in some way. This is still true even if + * a bean was removed and then added (which is not held as a modification). + */ + boolean wasTouched() { + return touched; + } + /** * Return true if there additions or removals. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index c5b82b19d..1c34a0783 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -308,6 +308,7 @@ public class BeanDescriptor implements BeanType { private final BeanPropertyAssocOne unidirectional; + private final BeanProperty orderColumn; /** * list of properties that are Lists/Sets/Maps (Derived). @@ -480,6 +481,7 @@ public class BeanDescriptor implements BeanType { this.propertiesLocal = listHelper.getLocal(); this.propertiesMutable = listHelper.getMutable(); this.unidirectional = listHelper.getUnidirectional(); + this.orderColumn = listHelper.getOrderColumn(); this.propertiesOne = listHelper.getOnes(); this.propertiesOneExportedSave = listHelper.getOneExportedSave(); this.propertiesOneExportedDelete = listHelper.getOneExportedDelete(); @@ -1925,6 +1927,13 @@ public class BeanDescriptor implements BeanType { return owner.getBeanDescriptor(otherType); } + /** + * Return the order column property. + */ + public BeanProperty getOrderColumn() { + return orderColumn; + } + /** * Return the "shadow" property to support unidirectional relationships. *

diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index d9452bc8f..d523bb739 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -38,6 +38,7 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import io.ebeaninternal.server.deploy.meta.DeployBeanTable; +import io.ebeaninternal.server.deploy.meta.DeployOrderColumn; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.parse.DeployBeanInfo; import io.ebeaninternal.server.deploy.parse.DeployCreateProperties; @@ -50,6 +51,7 @@ import io.ebeaninternal.server.properties.BeanPropertiesReader; import io.ebeaninternal.server.properties.BeanPropertyAccess; import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess; import io.ebeaninternal.server.query.CQueryPlan; +import io.ebeaninternal.server.type.ScalarTypeInteger; import io.ebeaninternal.xmlmapping.XmlMappingReader; import io.ebeaninternal.xmlmapping.model.XmAliasMapping; import io.ebeaninternal.xmlmapping.model.XmColumnMapping; @@ -979,6 +981,23 @@ public class BeanDescriptorManager implements BeanDescriptorMap { throw new PersistenceException(msg); } + private void makeOrderColumn(DeployBeanPropertyAssocMany oneToMany) { + + DeployBeanDescriptor targetDesc = getTargetDescriptor(oneToMany); + + DeployOrderColumn orderColumn = oneToMany.getOrderColumn(); + DeployBeanProperty orderProperty = new DeployBeanProperty(targetDesc, Integer.class, ScalarTypeInteger.INSTANCE, null); + + orderProperty.setName(DeployOrderColumn.LOGICAL_NAME); + orderProperty.setDbColumn(orderColumn.getName()); + orderProperty.setNullable(orderColumn.isNullable()); + orderProperty.setDbInsertable(orderColumn.isInsertable()); + orderProperty.setDbUpdateable(orderColumn.isUpdatable()); + orderProperty.setDbRead(true); + + targetDesc.setOrderColumn(orderProperty); + } + /** * A OneToMany with no matching mappedBy property in the target so must be * unidirectional. @@ -1112,6 +1131,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap { prop.getCascadeInfo().setSaveDelete(true, true); } + if (prop.hasOrderColumn()) { + makeOrderColumn(prop); + } + if (prop.getMappedBy() == null) { // if we are doc store only we are done // this allowes the use of @OneToMany in @DocStore - Entities diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 1a04e8ef9..8f902c047 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -58,6 +58,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ private final boolean unidirectional; + /** + * Flag to indicate that the target has a order column to auto populate. + */ + private final boolean hasOrderColumn; + /** * Flag to indicate manyToMany relationship. */ @@ -109,6 +114,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { public BeanPropertyAssocMany(BeanDescriptor descriptor, DeployBeanPropertyAssocMany deploy) { super(descriptor, deploy); this.unidirectional = deploy.isUnidirectional(); + this.hasOrderColumn = deploy.hasOrderColumn(); this.manyToMany = deploy.isManyToMany(); this.manyType = deploy.getManyType(); this.mapKey = deploy.getMapKey(); @@ -534,6 +540,10 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return true; } + public boolean hasOrderColumn() { + return hasOrderColumn; + } + @Override public boolean isAssocMany() { return true; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyOrderColumn.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyOrderColumn.java new file mode 100644 index 000000000..319c8830b --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyOrderColumn.java @@ -0,0 +1,36 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; + +/** + * Bean property for synthetic sort order value / order column. + * + * The value of which is held on the entity bean intercept. + */ +public class BeanPropertyOrderColumn extends BeanProperty { + + public BeanPropertyOrderColumn(BeanDescriptor descriptor, DeployBeanProperty deploy) { + super(descriptor, deploy); + } + + @Override + public Object getValue(EntityBean bean) { + return bean._ebean_getIntercept().getSortOrder(); + } + + @Override + public Object getValueIntercept(EntityBean bean) { + return bean._ebean_getIntercept().getSortOrder(); + } + + @Override + public void setValue(EntityBean bean, Object value) { + bean._ebean_getIntercept().setSortOrder((int)value); + } + + @Override + public void setValueIntercept(EntityBean bean, Object value) { + bean._ebean_getIntercept().setSortOrder((int)value); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 2e8b4165c..36e14a2e8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -81,6 +81,8 @@ public class DeployBeanDescriptor { private DeployBeanPropertyAssocOne unidirectional; + private DeployBeanProperty orderColumn; + /** * Type of Identity generation strategy used. */ @@ -446,6 +448,14 @@ public class DeployBeanDescriptor { this.unidirectional = unidirectional; } + public void setOrderColumn(DeployBeanProperty orderColumn) { + this.orderColumn = orderColumn; + } + + public DeployBeanProperty getOrderColumn() { + return orderColumn; + } + /** * Return the concurrency mode used for beans of this type. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java index 06a6c9915..121938fab 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java @@ -12,35 +12,37 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { /** * The type of the many, set, list or map. */ - final ManyType manyType; + private final ManyType manyType; ModifyListenMode modifyListenMode = ModifyListenMode.NONE; /** * Flag to indicate manyToMany relationship. */ - boolean manyToMany; + private boolean manyToMany; /** * Flag to indicate this is a unidirectional relationship. */ - boolean unidirectional; + private boolean unidirectional; /** * Join for manyToMany intersection table. */ - DeployTableJoin intersectionJoin; + private DeployTableJoin intersectionJoin; /** * For ManyToMany this is the Inverse join used to build reference queries. */ - DeployTableJoin inverseJoin; + private DeployTableJoin inverseJoin; - String fetchOrderBy; + private String fetchOrderBy; - String mapKey; + private String mapKey; - String intersectionDraftTable; + private String intersectionDraftTable; + + private DeployOrderColumn orderColumn; /** * Create this property. @@ -206,4 +208,16 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { public void setIntersectionDraftTable() { this.intersectionDraftTable = intersectionJoin.getTable() + "_draft"; } + + public void setOrderColumn(DeployOrderColumn orderColumn) { + this.orderColumn = orderColumn; + } + + public DeployOrderColumn getOrderColumn() { + return orderColumn; + } + + public boolean hasOrderColumn() { + return orderColumn != null; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index 5fb1b7010..c8bcfc6ce 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -6,6 +6,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptorMap; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.BeanPropertyOrderColumn; import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; @@ -64,6 +65,7 @@ public class DeployBeanPropertyLists { private final TableJoin[] tableJoins; private final BeanPropertyAssocOne unidirectional; + private final BeanProperty orderColumn; @SuppressWarnings({"unchecked", "rawtypes"}) public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor desc, DeployBeanDescriptor deploy) { @@ -71,12 +73,11 @@ public class DeployBeanPropertyLists { setImportedPrimaryKeys(deploy); + DeployBeanProperty deployOrderColumn = deploy.getOrderColumn(); + this.orderColumn = deployOrderColumn != null ? new BeanPropertyOrderColumn(desc, deployOrderColumn) : null; + DeployBeanPropertyAssocOne deployUnidirectional = deploy.getUnidirectional(); - if (deployUnidirectional == null) { - unidirectional = null; - } else { - unidirectional = new BeanPropertyAssocOne(owner, desc, deployUnidirectional); - } + this.unidirectional = deployUnidirectional == null ? null : new BeanPropertyAssocOne(owner, desc, deployUnidirectional); this.propertyMap = new LinkedHashMap<>(); @@ -89,7 +90,7 @@ public class DeployBeanPropertyLists { // Create a BeanProperty for the discriminator column to support // using RawSql queries with inheritance discriminatorColumn = inheritInfo.getDiscriminatorColumn(); - DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, new ScalarTypeString(), null); + DeployBeanProperty discDeployProp = new DeployBeanProperty(deploy, String.class, ScalarTypeString.INSTANCE, null); discDeployProp.setDiscriminator(); discDeployProp.setName(discriminatorColumn); discDeployProp.setDbColumn(discriminatorColumn); @@ -115,6 +116,12 @@ public class DeployBeanPropertyLists { allocateToList(prop); } + if (orderColumn != null) { + orderColumn.setDeployOrder(order++); + allocateToList(orderColumn); + propertyMap.put(orderColumn.getName(), orderColumn); + } + if (discProperty != null) { // put the discriminator property into the property map only // (after the real properties have been organised into their lists) @@ -160,6 +167,13 @@ public class DeployBeanPropertyLists { return unidirectional; } + /** + * Return the order column property. + */ + public BeanProperty getOrderColumn() { + return orderColumn; + } + /** * Allocate the property to a list. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployOrderColumn.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployOrderColumn.java new file mode 100644 index 000000000..26a8402b6 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployOrderColumn.java @@ -0,0 +1,39 @@ +package io.ebeaninternal.server.deploy.meta; + +import javax.persistence.OrderColumn; + +public class DeployOrderColumn { + + /** + * Logical property name used for order by and available for expression language. + */ + public static final String LOGICAL_NAME = "orderColumn"; + + private final String name; + private final boolean insertable; + private final boolean updatable; + private final boolean nullable; + + public DeployOrderColumn(OrderColumn orderColumn) { + this.name = orderColumn.name(); + this.insertable = orderColumn.insertable(); + this.updatable = orderColumn.updatable(); + this.nullable = orderColumn.nullable(); + } + + public String getName() { + return name; + } + + public boolean isInsertable() { + return insertable; + } + + public boolean isUpdatable() { + return updatable; + } + + public boolean isNullable() { + return nullable; + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 2d4b72ced..a451886ba 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -13,16 +13,19 @@ import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanTable; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.meta.DeployOrderColumn; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; import io.ebeaninternal.server.query.SqlJoinType; +import javax.persistence.CascadeType; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.MapKey; import javax.persistence.OneToMany; import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; import java.util.Set; /** @@ -66,6 +69,14 @@ class AnnotationAssocManys extends AnnotationParser { prop.setModifyListenMode(ModifyListenMode.REMOVALS); prop.getCascadeInfo().setDelete(privateOwned.cascadeRemove()); } + OrderColumn orderColumn = get(prop, OrderColumn.class); + if (orderColumn != null) { + // need to cascade as we set the order on cascade + prop.setOrderColumn(new DeployOrderColumn(orderColumn)); + prop.setFetchOrderBy(DeployOrderColumn.LOGICAL_NAME); + prop.getCascadeInfo().setType(CascadeType.ALL); + prop.setModifyListenMode(ModifyListenMode.ALL); + } } ManyToMany manyToMany = get(prop, ManyToMany.class); if (manyToMany != null) { diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 5de669ab3..3c9effc4d 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -8,7 +8,6 @@ import io.ebean.Update; import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebean.bean.EntityBean; -import io.ebean.bean.EntityBeanIntercept; import io.ebean.bean.PersistenceContext; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiTransaction; @@ -21,7 +20,6 @@ import io.ebeaninternal.server.core.PersistRequestCallableSql; import io.ebeaninternal.server.core.PersistRequestOrmUpdate; import io.ebeaninternal.server.core.PersistRequestUpdateSql; import io.ebeaninternal.server.core.Persister; -import io.ebeaninternal.server.deploy.BeanCollectionUtil; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.BeanManager; @@ -29,7 +27,6 @@ import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.IntersectionRow; -import io.ebeaninternal.server.deploy.ManyType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -413,7 +410,7 @@ public final class DefaultPersister implements Persister { } } - private void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) { + void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) { // determine insert or update taking into account stateless updates PersistRequestBean request = createRequestRecurse(bean, t, parentBean, insertMode, publish); @@ -826,86 +823,6 @@ public final class DefaultPersister implements Persister { } } - /** - * Helper to wrap the details when saving a OneToMany or ManyToMany - * relationship. - */ - private static class SaveManyPropRequest { - private final boolean insertedParent; - private final BeanPropertyAssocMany many; - private final EntityBean parentBean; - private final SpiTransaction transaction; - private final boolean cascade; - private final boolean deleteMissingChildren; - private final boolean publish; - - private SaveManyPropRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { - this.insertedParent = insertedParent; - this.many = many; - this.cascade = many.getCascadeInfo().isSave(); - this.parentBean = parentBean; - this.transaction = request.getTransaction(); - this.deleteMissingChildren = request.isDeleteMissingChildren(); - this.publish = request.isPublish(); - } - - public boolean isSaveIntersection() { - return transaction.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName()); - } - - private Object getValue() { - return many.getValue(parentBean); - } - - private boolean isModifyListenMode() { - return ModifyListenMode.REMOVALS == many.getModifyListenMode(); - } - - private boolean isDeleteMissingChildren() { - return deleteMissingChildren; - } - - private boolean isInsertedParent() { - return insertedParent; - } - - private BeanPropertyAssocMany getMany() { - return many; - } - - private EntityBean getParentBean() { - return parentBean; - } - - private SpiTransaction getTransaction() { - return transaction; - } - - private boolean isCascade() { - return cascade; - } - - public void modifyListenReset(BeanCollection c) { - if (insertedParent) { - // after insert set the modify listening mode - // for private owned etc - c.setModifyListening(many.getModifyListenMode()); - } - c.modifyReset(); - } - - public boolean isPublish() { - return publish; - } - - private void resetModifyState() { - Object details = getValue(); - if (details instanceof BeanCollection) { - modifyListenReset((BeanCollection) details); - } - } - } - private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) { if (saveMany.getMany().isManyToMany()) { @@ -967,107 +884,7 @@ public final class DefaultPersister implements Persister { */ private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren, boolean insertMode) { - BeanPropertyAssocMany prop = saveMany.getMany(); - - Object details = saveMany.getValue(); - - // check that the list is not null and if it is a BeanCollection - // check that is has been populated (don't trigger lazy loading) - // For a Map this is a collection of Map.Entry objects and not beans - Collection collection = BeanCollectionUtil.getActualEntries(details); - - if (collection == null) { - // nothing to do here - return; - } - - BeanDescriptor targetDescriptor = prop.getTargetDescriptor(); - if (saveMany.isInsertedParent()) { - // performance optimisation for large collections - targetDescriptor.preAllocateIds(collection.size()); - } - - SpiTransaction t = saveMany.getTransaction(); - boolean isMap = ManyType.MAP == prop.getManyType(); - EntityBean parentBean = saveMany.getParentBean(); - - if (deleteMissingChildren) { - // collect the Id's (to exclude from deleteManyDetails) - List detailIds = collectIds(collection, targetDescriptor, isMap); - // deleting missing children - children not in our collected detailIds - deleteManyDetails(t, prop.getBeanDescriptor(), parentBean, prop, detailIds, false); - } - - // increase depth for batching order - t.depth(+1); - - // if a map, then we get the key value and - // set it to the appropriate property on the - // detail bean before we save it - Object mapKeyValue = null; - - boolean saveSkippable = prop.isSaveRecurseSkippable(); - boolean skipSavingThisBean; - - for (Object detailBean : collection) { - if (isMap) { - // its a map so need the key and value - Map.Entry entry = (Map.Entry) detailBean; - mapKeyValue = entry.getKey(); - detailBean = entry.getValue(); - } - - if (detailBean instanceof EntityBean) { - EntityBean detail = (EntityBean) detailBean; - EntityBeanIntercept ebi = detail._ebean_getIntercept(); - if (prop.isManyToMany()) { - skipSavingThisBean = targetDescriptor.isReference(ebi); - } else { - if (targetDescriptor.isReference(ebi)) { - // we can skip this one - skipSavingThisBean = true; - - } else if (ebi.isNewOrDirty()) { - skipSavingThisBean = false; - // set the parent bean to detailBean - prop.setJoinValuesToChild(parentBean, detail, mapKeyValue); - - } else { - // unmodified so skip depending on prop.isSaveRecurseSkippable(); - skipSavingThisBean = saveSkippable; - } - } - - if (!skipSavingThisBean) { - saveRecurse(detail, t, parentBean, insertMode, saveMany.isPublish()); - } - } - } - - t.depth(-1); - } - - /** - * Collect the Id values of the details to remove 'missing children' for stateless updates. - */ - private List collectIds(Collection collection, BeanDescriptor targetDescriptor, boolean isMap) { - - List detailIds = new ArrayList<>(); - // stateless update with deleteMissingChildren so first - // collect the Id values to remove the 'missing children' - for (Object detailBean : collection) { - if (isMap) { - detailBean = ((Map.Entry) detailBean).getValue(); - } - if (detailBean instanceof EntityBean) { - Object id = targetDescriptor.getId((EntityBean) detailBean); - if (!DmlUtil.isNullOrZero(id)) { - // remember the Id (other details not in the collection) will be removed - detailIds.add(id); - } - } - } - return detailIds; + saveMany.saveDetails(this, deleteMissingChildren, insertMode); } /** @@ -1266,7 +1083,7 @@ public final class DefaultPersister implements Persister { * collection (and should not be deleted). *

*/ - private void deleteManyDetails(SpiTransaction t, BeanDescriptor desc, EntityBean parentBean, + void deleteManyDetails(SpiTransaction t, BeanDescriptor desc, EntityBean parentBean, BeanPropertyAssocMany many, List excludeDetailIds, boolean softDelete) { if (many.getCascadeInfo().isDelete()) { diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java new file mode 100644 index 000000000..f25fd9d48 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java @@ -0,0 +1,247 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanCollectionUtil; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.ManyType; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Helper to wrap the details when saving a OneToMany or ManyToMany relationship. + */ +class SaveManyPropRequest { + + private final boolean insertedParent; + private final BeanPropertyAssocMany many; + private final EntityBean parentBean; + private final SpiTransaction transaction; + private final boolean cascade; + private final boolean deleteMissingChildren; + private final boolean publish; + + private final Object value; + private final BeanDescriptor targetDescriptor; + private final boolean isMap; + private final boolean saveRecurseSkippable; + + private Collection collection; + private DefaultPersister persister; + private boolean deleteMissing; + private boolean insertMode; + private int sortOrder; + + SaveManyPropRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + this.insertedParent = insertedParent; + this.many = many; + this.cascade = many.getCascadeInfo().isSave(); + this.parentBean = parentBean; + this.transaction = request.getTransaction(); + this.deleteMissingChildren = request.isDeleteMissingChildren(); + this.publish = request.isPublish(); + this.value = many.getValue(parentBean); + this.targetDescriptor = many.getTargetDescriptor(); + this.isMap = ManyType.MAP == many.getManyType(); + this.saveRecurseSkippable = many.isSaveRecurseSkippable(); + } + + public boolean isSaveIntersection() { + return transaction.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName()); + } + + Object getValue() { + return value; + } + + boolean isModifyListenMode() { + return BeanCollection.ModifyListenMode.REMOVALS == many.getModifyListenMode(); + } + + boolean isDeleteMissingChildren() { + return deleteMissingChildren; + } + + boolean isInsertedParent() { + return insertedParent; + } + + BeanPropertyAssocMany getMany() { + return many; + } + + EntityBean getParentBean() { + return parentBean; + } + + SpiTransaction getTransaction() { + return transaction; + } + + boolean isCascade() { + return cascade; + } + + boolean isPublish() { + return publish; + } + + void modifyListenReset(BeanCollection c) { + if (insertedParent) { + // after insert set the modify listening mode for private owned etc + c.setModifyListening(many.getModifyListenMode()); + } + c.modifyReset(); + } + + void resetModifyState() { + if (value instanceof BeanCollection) { + modifyListenReset((BeanCollection) value); + } + } + + void saveDetails(DefaultPersister persister, boolean deleteMissing, boolean insertMode) { + + this.persister = persister; + this.deleteMissing = deleteMissing; + this.insertMode = insertMode; + + // check that the list is not null and if it is a BeanCollection + // check that is has been populated (don't trigger lazy loading) + // For a Map this is a collection of Map.Entry objects and not beans + collection = BeanCollectionUtil.getActualEntries(value); + if (collection != null) { + processDetails(); + } + } + + private void processDetails() { + + BeanProperty orderColumn = null; + boolean hasOrderColumn = many.hasOrderColumn(); + if (hasOrderColumn) { + if (!insertedParent && canSkipForOrderColumn()) { + return; + } + orderColumn = targetDescriptor.getOrderColumn(); + } + + if (insertedParent) { + // performance optimisation for large collections + targetDescriptor.preAllocateIds(collection.size()); + } + + if (deleteMissing) { + // collect the Id's (to exclude from deleteManyDetails) + List detailIds = collectIds(collection, targetDescriptor, isMap); + // deleting missing children - children not in our collected detailIds + persister.deleteManyDetails(transaction, many.getBeanDescriptor(), parentBean, many, detailIds, false); + } + + transaction.depth(+1); + saveAllBeans(orderColumn); + if (hasOrderColumn) { + resetModifyState(); + } + transaction.depth(-1); + } + + + private void saveAllBeans(BeanProperty orderColumn) { + + // if a map, then we get the key value and + // set it to the appropriate property on the + // detail bean before we save it + Object mapKeyValue = null; + boolean skipSavingThisBean; + + for (Object detailBean : collection) { + sortOrder++; + if (isMap) { + // its a map so need the key and value + Map.Entry entry = (Map.Entry) detailBean; + mapKeyValue = entry.getKey(); + detailBean = entry.getValue(); + } + + if (detailBean instanceof EntityBean) { + EntityBean detail = (EntityBean) detailBean; + EntityBeanIntercept ebi = detail._ebean_getIntercept(); + if (many.isManyToMany()) { + skipSavingThisBean = targetDescriptor.isReference(ebi); + } else { + if (orderColumn != null) { + orderColumn.setValue(detail, sortOrder); + ebi.setDirty(true); + } + if (targetDescriptor.isReference(ebi)) { + // we can skip this one + skipSavingThisBean = true; + + } else if (ebi.isNewOrDirty()) { + skipSavingThisBean = false; + // set the parent bean to detailBean + many.setJoinValuesToChild(parentBean, detail, mapKeyValue); + + } else { + // unmodified so skip depending on prop.isSaveRecurseSkippable(); + skipSavingThisBean = saveRecurseSkippable; + } + } + + if (!skipSavingThisBean) { + persister.saveRecurse(detail, transaction, parentBean, insertMode, publish); + } + } + } + } + + /** + * Return true if we can skip based on .. no modifications to the collection and no beans are dirty. + */ + private boolean canSkipForOrderColumn() { + return value instanceof BeanCollection + && !((BeanCollection) value).wasTouched() + && noDirtyBeans(); + } + + private boolean noDirtyBeans() { + for (Object bean : collection) { + if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isDirty()) { + return false; + } + } + return true; + } + + /** + * Collect the Id values of the details to remove 'missing children' for stateless updates. + */ + private List collectIds(Collection collection, BeanDescriptor targetDescriptor, boolean isMap) { + + List detailIds = new ArrayList<>(); + // stateless update with deleteMissingChildren so first + // collect the Id values to remove the 'missing children' + for (Object detailBean : collection) { + if (isMap) { + detailBean = ((Map.Entry) detailBean).getValue(); + } + if (detailBean instanceof EntityBean) { + Object id = targetDescriptor.getId((EntityBean) detailBean); + if (!DmlUtil.isNullOrZero(id)) { + // remember the Id (other details not in the collection) will be removed + detailIds.add(id); + } + } + } + return detailIds; + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/MetaFactory.java b/src/main/java/io/ebeaninternal/server/persist/dml/MetaFactory.java index 9ab432141..7bc370757 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/MetaFactory.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/MetaFactory.java @@ -3,10 +3,12 @@ package io.ebeaninternal.server.persist.dml; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbEncrypt; import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.persist.dmlbind.Bindable; import io.ebeaninternal.server.persist.dmlbind.BindableId; import io.ebeaninternal.server.persist.dmlbind.BindableList; +import io.ebeaninternal.server.persist.dmlbind.BindableOrderColumn; import io.ebeaninternal.server.persist.dmlbind.BindableUnidirectional; import io.ebeaninternal.server.persist.dmlbind.FactoryAssocOnes; import io.ebeaninternal.server.persist.dmlbind.FactoryBaseProperties; @@ -62,6 +64,11 @@ public class MetaFactory { embeddedFact.create(setList, desc, DmlMode.UPDATE, includeLobs); assocOneFact.create(setList, desc, DmlMode.UPDATE); + BeanProperty orderColumn = desc.getOrderColumn(); + if (orderColumn != null) { + setList.add(new BindableOrderColumn(orderColumn)); + } + BindableId id = idFact.createId(desc); Bindable version = versionFact.create(desc); Bindable tenantId = versionFact.createTenantId(desc); diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableOrderColumn.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableOrderColumn.java new file mode 100644 index 000000000..ef7046634 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableOrderColumn.java @@ -0,0 +1,37 @@ +package io.ebeaninternal.server.persist.dmlbind; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanProperty; + +import java.sql.SQLException; +import java.util.List; + +/** + * Bindable for the synthetic order column. + */ +public class BindableOrderColumn extends BindableProperty { + + public BindableOrderColumn(BeanProperty prop) { + super(prop); + } + + @Override + public void addToUpdate(PersistRequestBean request, List list) { + int sortOrder = request.getEntityBeanIntercept().getSortOrder(); + if (sortOrder > 0) { + list.add(this); + } + } + + /** + * Normal binding of a property value from the bean. + */ + @Override + public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { + + int sortOrder = bean._ebean_getIntercept().getSortOrder(); + request.bind(sortOrder, prop); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 1e3812b3a..a6dd341d4 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -109,7 +109,7 @@ public final class DefaultTypeManager implements TypeManager { private final ScalarType shortType = new ScalarTypeShort(); - private final ScalarType integerType = new ScalarTypeInteger(); + private final ScalarType integerType = ScalarTypeInteger.INSTANCE; private final ScalarType longType = new ScalarTypeLong(); @@ -130,7 +130,7 @@ public final class DefaultTypeManager implements TypeManager { private final ScalarType currencyType = new ScalarTypeCurrency(); private final ScalarType timeZoneType = new ScalarTypeTimeZone(); - private final ScalarType stringType = new ScalarTypeString(); + private final ScalarType stringType = ScalarTypeString.INSTANCE; private final ScalarType classType = new ScalarTypeClass(); diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeInteger.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeInteger.java index 6a4caddcd..51f6cfe4d 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeInteger.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeInteger.java @@ -1,10 +1,10 @@ package io.ebeaninternal.server.type; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; import io.ebean.text.TextException; import io.ebeaninternal.server.core.BasicTypeConverter; import io.ebeanservice.docstore.api.mapping.DocPropertyType; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; import java.io.DataInput; import java.io.DataOutput; @@ -17,7 +17,9 @@ import java.sql.Types; */ public class ScalarTypeInteger extends ScalarTypeBase { - public ScalarTypeInteger() { + public static ScalarTypeInteger INSTANCE = new ScalarTypeInteger(); + + private ScalarTypeInteger() { super(Integer.class, true, Types.INTEGER); } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeString.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeString.java index 164a55fcf..f9a31355c 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeString.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeString.java @@ -1,9 +1,9 @@ package io.ebeaninternal.server.type; -import io.ebeaninternal.server.core.BasicTypeConverter; -import io.ebeanservice.docstore.api.mapping.DocPropertyType; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; +import io.ebeaninternal.server.core.BasicTypeConverter; +import io.ebeanservice.docstore.api.mapping.DocPropertyType; import java.io.DataInput; import java.io.DataOutput; @@ -16,7 +16,9 @@ import java.sql.Types; */ public class ScalarTypeString extends ScalarTypeBase { - public ScalarTypeString() { + public static final ScalarTypeString INSTANCE = new ScalarTypeString(); + + private ScalarTypeString() { super(String.class, true, Types.VARCHAR); } diff --git a/src/test/java/org/tests/cascade/OmOrderedDetail.java b/src/test/java/org/tests/cascade/OmOrderedDetail.java new file mode 100644 index 000000000..b15a4ff8e --- /dev/null +++ b/src/test/java/org/tests/cascade/OmOrderedDetail.java @@ -0,0 +1,57 @@ +package org.tests.cascade; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class OmOrderedDetail { + + @Id + Long id; + + String name; + + @ManyToOne + OmOrderedMaster master; + + @Version + Long version; + + public OmOrderedDetail(String name) { + this.name = name; + } + + 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 OmOrderedMaster getMaster() { + return master; + } + + public void setMaster(OmOrderedMaster master) { + this.master = master; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/cascade/OmOrderedMaster.java b/src/test/java/org/tests/cascade/OmOrderedMaster.java new file mode 100644 index 000000000..8607084d3 --- /dev/null +++ b/src/test/java/org/tests/cascade/OmOrderedMaster.java @@ -0,0 +1,63 @@ +package org.tests.cascade; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OrderColumn; +import javax.persistence.Version; +import java.util.List; + +@Entity +public class OmOrderedMaster { + + @Id + Long id; + + String name; + + /** + * Cascade ALL set automatically as we set order values when cascading. + */ + @OneToMany(mappedBy = "master") //, cascade = CascadeType.ALL) + @OrderColumn(name="sort_order") + List details; + + @Version + Long version; + + public OmOrderedMaster(String name) { + this.name = name; + } + + 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 getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/cascade/TestOrderedList.java b/src/test/java/org/tests/cascade/TestOrderedList.java new file mode 100644 index 000000000..9baf7a601 --- /dev/null +++ b/src/test/java/org/tests/cascade/TestOrderedList.java @@ -0,0 +1,98 @@ +package org.tests.cascade; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOrderedList extends BaseTestCase { + + @Test + public void test() { + + OmOrderedMaster master = new OmOrderedMaster("m1"); + + List details = master.getDetails(); + for (int i = 0; i < 5; i++) { + details.add(new OmOrderedDetail("d"+i)); + } + + LoggedSqlCollector.start(); + Ebean.save(master); + + List sql = LoggedSqlCollector.current(); + assertThat(sql.size()).isGreaterThan(1); + assertThat(sql.get(0)).contains("insert into om_ordered_master"); + assertThat(sql.get(1)).contains("insert into om_ordered_detail (name, version, sort_order, master_id) values (?,?,?,?)"); + + // update without any changes + Ebean.save(master); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); + + + // update just changing master + master.setName("m1-mod"); + Ebean.save(master); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update om_ordered_master set name=?, version=?"); + + + fetchAndReorder(master.getId()); + + } + + private void fetchAndReorder(Long id) { + + OmOrderedMaster fresh = Ebean.find(OmOrderedMaster.class).setId(id).fetch("details").findOne(); + List details1 = fresh.getDetails(); + + List sql = LoggedSqlCollector.current(); + assertThat(sql.get(0)).contains("order by t0.id, t1.sort_order"); + + // fetched, not dirty + Ebean.save(fresh); + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); + + + // reorder + OmOrderedDetail third = details1.remove(2); + OmOrderedDetail first = details1.remove(0); + details1.add(first); + details1.add(third); + + fresh.setName("m1-reorder"); + + Ebean.save(fresh); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(6); + assertThat(sql.get(0)).contains("update om_ordered_master set name=?, version=?"); + assertThat(sql.get(1)).contains("update om_ordered_detail set version=?, sort_order=? where id=? and version=?"); + + details1.get(1).setName("was 1"); + fresh.setName("m1-mod3"); + Ebean.save(fresh); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(6); + assertThat(sql.get(0)).contains("update om_ordered_master set name=?, version=?"); + assertThat(sql.get(1)).contains("update om_ordered_detail set version=?, sort_order=? where id=? and version=?"); + assertThat(sql.get(2)).contains("update om_ordered_detail set name=?, version=?, sort_order=? where id=? and version=?"); + + + Ebean.delete(fresh); + + sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from om_ordered_detail where master_id = ?"); + assertThat(sql.get(1)).contains("delete from om_ordered_master where id=? and version=?"); + } +} From 49b568e7d45f9fe0e0bd27f1c7c41bc1f444b1d0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Feb 2018 22:32:43 +1300 Subject: [PATCH 0025/1036] [maven-release-plugin] prepare release ebean-11.10.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 621a03706..1bfed8150 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.5-SNAPSHOT + 11.10.5 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.10.5 From 6c1b295d4195c047f9baa6ec7b72e784fccb0a73 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Feb 2018 22:32:56 +1300 Subject: [PATCH 0026/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1bfed8150..be7fed8e4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.5 + 11.10.6-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.10.5 + HEAD From 9926cad7f16cdc3e4cd27ac1c4b6a556ca6042d4 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 00:11:27 +1300 Subject: [PATCH 0027/1036] #1262 - ENH: Support firstRow maxRows with findNative() --- .../server/query/CQueryBuilder.java | 7 ++ .../server/querydefn/DefaultOrmQuery.java | 2 +- .../rawsql/nativesql/TestNativeSqlBasic.java | 73 ++++++++++++------- 3 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 5753d4021..6ae7a12a0 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -366,6 +366,10 @@ class CQueryBuilder { return new SqlTreeBuilder(this, request, predicates).build(); } + private String nativeQueryPaging(SpiQuery query, String sql) { + return dbPlatform.getBasicSqlLimiter().limit(sql, query.getFirstRow(), query.getMaxRows()); + } + /** * Create the SqlTree by reading the ResultSetMetaData and mapping table/columns to bean property paths. */ @@ -375,6 +379,9 @@ class CQueryBuilder { // parse named parameters returning the final sql to execute String sql = predicates.parseBindParams(query.getNativeSql()); + if (query.hasMaxRowsOrFirstRow()) { + sql = nativeQueryPaging(query, sql); + } query.setGeneratedSql(sql); Connection connection = request.getTransaction().getConnection(); diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 7a85fe2d8..a2cb55362 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -996,7 +996,7 @@ public class DefaultOrmQuery implements SpiQuery { CQueryPlanKey createQueryPlanKey() { if (isNativeSql()) { - queryPlanKey = new NativeSqlQueryPlanKey(nativeSql); + queryPlanKey = new NativeSqlQueryPlanKey(nativeSql + "-" + firstRow + "-" + maxRows); } else { queryPlanKey = new OrmQueryPlanKey(beanDescriptor.getDiscValue(), m2mIncludeJoin, type, detail, maxRows, firstRow, disableLazyLoading, orderBy, diff --git a/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java b/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java index 77ceba129..94f7219a4 100644 --- a/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java +++ b/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java @@ -3,7 +3,6 @@ package org.tests.rawsql.nativesql; import io.ebean.BaseTestCase; import io.ebean.BeanState; import io.ebean.Ebean; -import io.ebean.EbeanServer; import io.ebean.Query; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; @@ -24,16 +23,14 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select id, name from o_customer"; - Query query = server.findNative(Customer.class, nativeSql); + Query query = Ebean.findNative(Customer.class, nativeSql); List customers = query.findList(); assertThat(customers).isNotEmpty(); - BeanState beanState = server.getBeanState(customers.get(0)); + BeanState beanState = Ebean.getBeanState(customers.get(0)); assertThat(beanState.getLoadedProps()).contains("id", "name"); } @@ -42,15 +39,13 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select * from o_customer"; - Query query = server.findNative(Customer.class, nativeSql); + Query query = Ebean.findNative(Customer.class, nativeSql); List customers = query.findList(); assertThat(customers).isNotEmpty(); - BeanState beanState = server.getBeanState(customers.get(0)); + BeanState beanState = Ebean.getBeanState(customers.get(0)); assertThat(beanState.getLoadedProps().size()).isGreaterThan(10); } @@ -59,10 +54,8 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select c.*, b.city from o_customer c join o_address b on b.id = c.billing_address_id"; - Query query = server.findNative(Customer.class, nativeSql); + Query query = Ebean.findNative(Customer.class, nativeSql); List customers = query.findList(); assertThat(customers).isNotEmpty(); @@ -73,33 +66,67 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select id, name from o_customer where id > :some"; - Query query = server.findNative(Customer.class, nativeSql); + Query query = Ebean.findNative(Customer.class, nativeSql); query.setParameter("some", 1); List customers = query.findList(); assertThat(customers).isNotEmpty(); - Query query2 = server.findNative(Customer.class, nativeSql); + Query query2 = Ebean.findNative(Customer.class, nativeSql); query2.setParameter("some", 2); List customers2 = query2.findList(); assertThat(customers2).isNotEmpty(); } + @Test + public void withMaxRows() { + + ResetBasicData.reset(); + + String nativeSql = "select id, name from o_customer where id > :some"; + + Query query = Ebean.findNative(Customer.class, nativeSql) + .setParameter("some", 1) + .setMaxRows(10); + + query.findList(); + + if (isH2() || isPostgres()) { + assertThat(sqlOf(query)).contains(" limit 10"); + } + } + + @Test + public void withFirstRowsMaxRows() { + + ResetBasicData.reset(); + + String nativeSql = "select id, name from o_customer where id > :some"; + + Query query = Ebean.findNative(Customer.class, nativeSql) + .setParameter("some", 1) + .setFirstRow(20) + .setMaxRows(10); + + query.findList(); + + if (isH2() || isPostgres()) { + assertThat(sqlOf(query)).contains(" limit 10 offset 20"); + } + } + + @Test public void partialAndLazyLoad() { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select id, name from o_customer where id > ?"; - List customers = server.findNative(Customer.class, nativeSql) + List customers = Ebean.findNative(Customer.class, nativeSql) .setParameter(1, 1) .findList(); @@ -117,11 +144,9 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select o.id, o.status, c.id, c.name, c.version from o_order o join o_customer c on c.id = o.kcustomer_id "; - List orders = server.findNative(Order.class, nativeSql) + List orders = Ebean.findNative(Order.class, nativeSql) .findList(); for (Order order : orders) { @@ -135,11 +160,9 @@ public class TestNativeSqlBasic extends BaseTestCase { ResetBasicData.reset(); - EbeanServer server = Ebean.getDefaultServer(); - String nativeSql = "select o.id, o.status, o.kcustomer_id from o_order o"; - List orders = server.findNative(Order.class, nativeSql) + List orders = Ebean.findNative(Order.class, nativeSql) .findList(); LoggedSqlCollector.start(); From 5237e8ba666e2389eeb1e656177e27fe80c438d9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 09:45:49 +1300 Subject: [PATCH 0028/1036] #1261 - ENH: Support use of getGeneratedKeys with SqlUpdate --- src/main/java/io/ebean/SqlUpdate.java | 24 ++++ .../io/ebeaninternal/api/SpiSqlUpdate.java | 16 +++ .../server/core/DefaultSqlUpdate.java | 31 +++++ .../server/core/PersistRequestUpdateSql.java | 5 + .../server/persist/ExeOrmUpdate.java | 6 +- .../server/persist/ExeUpdateSql.java | 27 +++- .../server/persist/PstmtFactory.java | 13 +- .../server/persist/dml/DmlHandler.java | 5 +- .../java/io/ebeaninternal/util/JdbcClose.java | 14 ++ .../java/org/tests/update/EPersonOnline.java | 57 ++++++++ .../org/tests/update/TestSqlUpdateUpsert.java | 128 ++++++++++++++++++ src/test/resources/ebean.properties | 2 +- 12 files changed, 315 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/tests/update/EPersonOnline.java create mode 100644 src/test/java/org/tests/update/TestSqlUpdateUpsert.java diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java index 1f8401eed..59865f815 100644 --- a/src/main/java/io/ebean/SqlUpdate.java +++ b/src/main/java/io/ebean/SqlUpdate.java @@ -54,6 +54,25 @@ public interface SqlUpdate { */ int execute(); + /** + * Return the generated key value. + */ + Object getGeneratedKey(); + + /** + * Execute and return the generated key. This is effectively a short cut for: + * + *
{@code
+   *
+   *   sqlUpdate.execute();
+   *   Object key = sqlUpdate.getGeneratedKey();
+   *
+   * }
+ * + * @return The generated key value + */ + Object executeGetKey(); + /** * Return true if eBean should automatically deduce the table modification * information and process it. @@ -88,6 +107,11 @@ public interface SqlUpdate { */ SqlUpdate setLabel(String label); + /** + * Set to true when we want to use getGeneratedKeys with this statement. + */ + SqlUpdate setGetGeneratedKeys(boolean getGeneratedKeys); + /** * Return the sql statement. */ diff --git a/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java b/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java index d9da393c8..10c7ccad7 100644 --- a/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java +++ b/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java @@ -4,7 +4,23 @@ import io.ebean.SqlUpdate; public interface SpiSqlUpdate extends SqlUpdate { + /** + * Return the Bind parameters. + */ BindParams getBindParams(); + /** + * Set the final sql being executed with named parameters replaced etc. + */ void setGeneratedSql(String sql); + + /** + * Return true if we are using getGeneratedKeys. + */ + boolean isGetGeneratedKeys(); + + /** + * Set the generated key value. + */ + void setGeneratedKey(Object idValue); } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java index ea8a4c3cc..c65b6c269 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java @@ -65,6 +65,10 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { */ private int addPos; + private boolean getGeneratedKeys; + + private Object generatedKey; + /** * Create with server sql and bindParams object. *

@@ -93,6 +97,12 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { this(null, sql, new BindParams()); } + @Override + public Object executeGetKey() { + execute(); + return getGeneratedKey(); + } + @Override public int execute() { if (server != null) { @@ -103,6 +113,16 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { } } + @Override + public Object getGeneratedKey() { + return generatedKey; + } + + @Override + public void setGeneratedKey(Object idValue) { + this.generatedKey = idValue; + } + @Override public boolean isAutoTableMod() { return isAutoTableMod; @@ -125,6 +145,17 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { return this; } + @Override + public boolean isGetGeneratedKeys() { + return getGeneratedKeys; + } + + @Override + public SqlUpdate setGetGeneratedKeys(boolean getGeneratedKeys) { + this.getGeneratedKeys = getGeneratedKeys; + return this; + } + @Override public String getGeneratedSql() { return generatedSql; diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java index 52add1204..05fd26cd6 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java @@ -73,6 +73,11 @@ public final class PersistRequestUpdateSql extends PersistRequest { */ @Override public void setGeneratedKey(Object idValue) { + updateSql.setGeneratedKey(idValue); + } + + public boolean isGetGeneratedKeys() { + return updateSql.isGetGeneratedKeys(); } /** diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java index 756111a72..3830096a6 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java @@ -16,7 +16,7 @@ import java.sql.SQLException; /** * Executes the UpdateSql requests. */ -public class ExeOrmUpdate { +class ExeOrmUpdate { private static final Logger logger = LoggerFactory.getLogger(ExeOrmUpdate.class); @@ -27,7 +27,7 @@ public class ExeOrmUpdate { /** * Create with a given binder. */ - public ExeOrmUpdate(Binder binder) { + ExeOrmUpdate(Binder binder) { this.pstmtFactory = new PstmtFactory(); this.binder = binder; } @@ -107,7 +107,7 @@ public class ExeOrmUpdate { if (logSql) { t.logSql(sql); } - pstmt = pstmtFactory.getPstmt(t, sql); + pstmt = pstmtFactory.getPstmt(t, sql, false); } String bindLog = null; diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java index 7e265033a..b8e050783 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java @@ -6,17 +6,19 @@ import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.PersistRequestUpdateSql; import io.ebeaninternal.server.core.PersistRequestUpdateSql.SqlType; import io.ebeaninternal.server.util.BindParamsParser; +import io.ebeaninternal.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; /** * Executes the UpdateSql requests. */ -public class ExeUpdateSql { +class ExeUpdateSql { private static final Logger logger = LoggerFactory.getLogger(ExeUpdateSql.class); @@ -27,7 +29,7 @@ public class ExeUpdateSql { /** * Create with a given binder. */ - public ExeUpdateSql(Binder binder) { + ExeUpdateSql(Binder binder) { this.binder = binder; this.pstmtFactory = new PstmtFactory(); } @@ -51,6 +53,9 @@ public class ExeUpdateSql { } else { int rowCount = pstmt.executeUpdate(); request.checkRowCount(rowCount); + if (request.isGetGeneratedKeys()) { + readGeneratedKeys(pstmt, request); + } request.postExecute(); return rowCount; } @@ -68,6 +73,22 @@ public class ExeUpdateSql { } } + private void readGeneratedKeys(PreparedStatement stmt, PersistRequestUpdateSql request) { + + ResultSet resultSet = null; + try { + resultSet = stmt.getGeneratedKeys(); + if (resultSet.next()) { + request.setGeneratedKey(resultSet.getObject(1)); + } + } catch (SQLException ex) { + throw new PersistenceException(ex); + + } finally { + JdbcClose.close(resultSet); + } + } + private PreparedStatement bindStmt(PersistRequestUpdateSql request, boolean batchThisRequest) throws SQLException { SpiSqlUpdate updateSql = request.getUpdateSql(); @@ -90,7 +111,7 @@ public class ExeUpdateSql { if (logSql) { t.logSql(TrimLogSql.trim(sql)); } - pstmt = pstmtFactory.getPstmt(t, sql); + pstmt = pstmtFactory.getPstmt(t, sql, request.isGetGeneratedKeys()); } if (updateSql.getTimeout() > 0) { diff --git a/src/main/java/io/ebeaninternal/server/persist/PstmtFactory.java b/src/main/java/io/ebeaninternal/server/persist/PstmtFactory.java index 6655e4cbb..df1c348b1 100644 --- a/src/main/java/io/ebeaninternal/server/persist/PstmtFactory.java +++ b/src/main/java/io/ebeaninternal/server/persist/PstmtFactory.java @@ -6,6 +6,7 @@ import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Statement; /** * Factory for creating Statements. @@ -14,9 +15,9 @@ import java.sql.SQLException; * getGeneratedKeys. *

*/ -public class PstmtFactory { +class PstmtFactory { - public PstmtFactory() { + PstmtFactory() { } /** @@ -30,9 +31,13 @@ public class PstmtFactory { /** * Get a prepared statement without any batching. */ - public PreparedStatement getPstmt(SpiTransaction t, String sql) throws SQLException { + public PreparedStatement getPstmt(SpiTransaction t, String sql, boolean getGeneratedKeys) throws SQLException { Connection conn = t.getInternalConnection(); - return conn.prepareStatement(sql); + if (getGeneratedKeys) { + return conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + } else { + return conn.prepareStatement(sql); + } } /** diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java b/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java index 22777d865..3b7d0e857 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java @@ -24,6 +24,8 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest { private static final Logger logger = LoggerFactory.getLogger(DmlHandler.class); + private static final int[] GENERATED_KEY_COLUMNS = new int[]{1}; + /** * The originating request. */ @@ -260,8 +262,7 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest { // the Id generated is always the first column // Required to stop Oracle10 giving us Oracle rowId?? // Other jdbc drivers seem fine without this hint. - int[] columns = {1}; - return conn.prepareStatement(sql, columns); + return conn.prepareStatement(sql, GENERATED_KEY_COLUMNS); } else { return conn.prepareStatement(sql); diff --git a/src/main/java/io/ebeaninternal/util/JdbcClose.java b/src/main/java/io/ebeaninternal/util/JdbcClose.java index 4fc2432e7..647f34709 100644 --- a/src/main/java/io/ebeaninternal/util/JdbcClose.java +++ b/src/main/java/io/ebeaninternal/util/JdbcClose.java @@ -4,6 +4,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; /** @@ -13,6 +14,19 @@ public class JdbcClose { private static final Logger logger = LoggerFactory.getLogger(JdbcClose.class); + /** + * Close the resultSet logging if an error occurs. + */ + public static void close(ResultSet resultSet) { + try { + if (resultSet != null) { + resultSet.close(); + } + } catch (SQLException e) { + logger.warn("Error closing resultSet", e); + } + } + /** * Close the connection logging if an error occurs. */ diff --git a/src/test/java/org/tests/update/EPersonOnline.java b/src/test/java/org/tests/update/EPersonOnline.java new file mode 100644 index 000000000..f9a3e3e04 --- /dev/null +++ b/src/test/java/org/tests/update/EPersonOnline.java @@ -0,0 +1,57 @@ +package org.tests.update; + +import io.ebean.annotation.Index; +import io.ebean.annotation.WhenModified; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.Instant; + +@Entity +@Table(name = "e_person_online") +public class EPersonOnline { + + @Id + Long id; + + @Index(unique = true) + String email; + + boolean online; + + @WhenModified + Instant whenUpdated; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean isOnline() { + return online; + } + + public void setOnline(boolean online) { + this.online = online; + } + + public Instant getWhenUpdated() { + return whenUpdated; + } + + public void setWhenUpdated(Instant whenUpdated) { + this.whenUpdated = whenUpdated; + } +} diff --git a/src/test/java/org/tests/update/TestSqlUpdateUpsert.java b/src/test/java/org/tests/update/TestSqlUpdateUpsert.java new file mode 100644 index 000000000..92aa0dd3f --- /dev/null +++ b/src/test/java/org/tests/update/TestSqlUpdateUpsert.java @@ -0,0 +1,128 @@ +package org.tests.update; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.SqlUpdate; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestSqlUpdateUpsert extends BaseTestCase { + + @ForPlatform(Platform.H2) + @Test + public void h2Merge() { + + String sql = "merge into e_person_online (email, online, when_updated) key(email) values (?, ?, now())"; + + String email = "baz@one.com"; + + Object key = Ebean.createSqlUpdate(sql) + .setGetGeneratedKeys(true) + .setParameter(1, email) + .setParameter(2, true) + .executeGetKey(); + + EPersonOnline found = Ebean.find(EPersonOnline.class, key); + assertThat(found).isNotNull(); + assertThat(found.getEmail()).isEqualTo(email); + assertThat(found.isOnline()).isTrue(); + + String sqlNamed = "merge into e_person_online (email, online, when_updated) key(email) values (:email, :online, now())"; + + SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) + .setGetGeneratedKeys(true) + .setParameter("email", email) + .setParameter("online", false); + + Object key2 = sqlUpdate2.executeGetKey(); + assertThat(key2).isNull(); + + + EPersonOnline found2 = Ebean.find(EPersonOnline.class).where().eq("email", email).findOne(); + assertThat(found2).isNotNull(); + assertThat(found2.getId()).isEqualTo(key); + assertThat(found2.getEmail()).isEqualTo(email); + assertThat(found2.isOnline()).isFalse(); + assertThat(found2.getWhenUpdated()).isGreaterThan(found.getWhenUpdated()); + } + + @ForPlatform(Platform.POSTGRES) + @Test + public void postgresUpsert() { + + String sql = "insert into e_person_online (email, online, when_updated) values (?, ?, now()) on conflict (email) do update set when_updated=now(), online = ?"; + + String email = "foo@one.com"; + + Object key = Ebean.createSqlUpdate(sql) + .setGetGeneratedKeys(true) + .setParameter(1, email) + .setParameter(2, true) + .setParameter(3, true) + .executeGetKey(); + + EPersonOnline found = Ebean.find(EPersonOnline.class, key); + assertThat(found).isNotNull(); + assertThat(found.getEmail()).isEqualTo("foo@one.com"); + assertThat(found.isOnline()).isTrue(); + + + String sqlNamed = "insert into e_person_online (email, online, when_updated) values (:email, :online, now()) on conflict (email) do update set when_updated=now(), online = :online"; + SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) + .setGetGeneratedKeys(true) + .setParameter("email", email) + .setParameter("online", false); + + Object key2 = sqlUpdate2.executeGetKey(); + + EPersonOnline found2 = Ebean.find(EPersonOnline.class, key2); + assertThat(found2).isNotNull(); + assertThat(found2.getId()).isEqualTo(key); + assertThat(found2.getEmail()).isEqualTo("foo@one.com"); + assertThat(found2.isOnline()).isFalse(); + assertThat(found2.getWhenUpdated()).isGreaterThan(found.getWhenUpdated()); + + } + + @ForPlatform(Platform.MYSQL) + @Test + public void mySqlUpsert() { + + String email = "bar@one.com"; + + String sql = "insert into e_person_online (email, online, when_updated) values (?, ?, current_time) on duplicate key update when_updated=current_time, online = ?"; + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql) + .setGetGeneratedKeys(true) + .setParameter(1, email) + .setParameter(2, true) + .setParameter(3, true); + + Object key = sqlUpdate.executeGetKey(); + assertThat(key).isNotNull(); + + EPersonOnline found = Ebean.find(EPersonOnline.class, key); + assertThat(found).isNotNull(); + assertThat(found.getEmail()).isEqualTo("bar@one.com"); + assertThat(found.isOnline()).isTrue(); + + + String sqlNamed = "insert into e_person_online (email, online, when_updated) values (:email, :online, current_time) on duplicate key update when_updated=current_time, online = :online"; + SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) + .setGetGeneratedKeys(true) + .setParameter("email", email) + .setParameter("online", false); + + sqlUpdate2.execute(); + Object key2 = sqlUpdate2.getGeneratedKey(); + + EPersonOnline found2 = Ebean.find(EPersonOnline.class, key2); + assertThat(found2).isNotNull(); + assertThat(found2.getId()).isEqualTo(key); + assertThat(found2.getEmail()).isEqualTo("bar@one.com"); + assertThat(found2.isOnline()).isFalse(); + + } +} diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 39776ad38..d2e64ef00 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -103,7 +103,7 @@ datasource.hsqldb.databaseDriver=org.hsqldb.jdbcDriver datasource.mysql.username=test_ebean datasource.mysql.password=test -datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/test_ebean +datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:4306/test_ebean datasource.mysql.databaseDriver=com.mysql.jdbc.Driver From a5c6f483b0cc3a7cd42a4376e212f9095177951a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 11:18:17 +1300 Subject: [PATCH 0029/1036] #1258 - ENH: Add ServerConfig notifyL2CacheInForeground option ... was ServerCachePlugin BackgroundExecutor problem --- .../java/io/ebean/config/ServerConfig.java | 27 ++++++++++++++++++- .../server/core/InternalConfiguration.java | 4 +-- .../transaction/PostCommitProcessing.java | 2 +- .../transaction/TransactionManager.java | 4 +-- .../TransactionManagerOptions.java | 6 ++--- .../io/ebean/config/ServerConfigTest.java | 13 +++++++++ 6 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index e2b1af685..a3f9348c9 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -463,6 +463,12 @@ public class ServerConfig { */ private boolean disableL2Cache; + /** + * Generally we want to perform L2 cache notification in the background and not impact + * the performance of executing transactions. + */ + private boolean notifyL2CacheInForeground; + /** * The time in millis used to determine when a query is alerted for being slow. */ @@ -473,7 +479,6 @@ public class ServerConfig { */ private SlowQueryListener slowQueryListener; - private ProfilingConfig profilingConfig = new ProfilingConfig(); /** @@ -2680,6 +2685,7 @@ public class ServerConfig { slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis); docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly); disableL2Cache = p.getBoolean("disableL2Cache", disableL2Cache); + notifyL2CacheInForeground = p.getBoolean("notifyL2CacheInForeground", notifyL2CacheInForeground); explicitTransactionBeginMode = p.getBoolean("explicitTransactionBeginMode", explicitTransactionBeginMode); autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode); useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager); @@ -2900,6 +2906,25 @@ public class ServerConfig { this.disableL2Cache = disableL2Cache; } + /** + * Return true if L2 cache notification should run in the foreground. + */ + public boolean isNotifyL2CacheInForeground() { + return notifyL2CacheInForeground; + } + + /** + * Set this to true to run L2 cache notification in the foreground. + *

+ * In general we don't want to do that as when we use a distributed cache (like Ignite, Hazelcast etc) + * we are making network calls and we prefer to do this in background and not impact the response time + * of the executing transaction. + *

+ */ + public void setNotifyL2CacheInForeground(boolean notifyL2CacheInForeground) { + this.notifyL2CacheInForeground = notifyL2CacheInForeground; + } + /** * Return the query plan time to live. */ diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index e2da8f4b4..3702d1984 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -372,10 +372,10 @@ public class InternalConfiguration { public TransactionManager createTransactionManager(DocStoreUpdateProcessor indexUpdateProcessor) { TransactionScopeManager scopeManager = createTransactionScopeManager(); - boolean localL2 = cacheManager.isLocalL2Caching(); + boolean notifyL2CacheInForeground = cacheManager.isLocalL2Caching() || serverConfig.isNotifyL2CacheInForeground(); TransactionManagerOptions options = - new TransactionManagerOptions(localL2, serverConfig, scopeManager, clusterManager, backgroundExecutor, + new TransactionManagerOptions(notifyL2CacheInForeground, serverConfig, scopeManager, clusterManager, backgroundExecutor, indexUpdateProcessor, beanDescriptorManager, dataSource(), profileHandler()); if (serverConfig.isExplicitTransactionBeginMode()) { diff --git a/src/main/java/io/ebeaninternal/server/transaction/PostCommitProcessing.java b/src/main/java/io/ebeaninternal/server/transaction/PostCommitProcessing.java index 637482a2c..ac3a57560 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/PostCommitProcessing.java +++ b/src/main/java/io/ebeaninternal/server/transaction/PostCommitProcessing.java @@ -86,7 +86,7 @@ public final class PostCommitProcessing { */ void notifyLocalCache() { processTableEvents(event.getEventTables()); - if (manager.localL2Caching) { + if (manager.notifyL2CacheInForeground) { // process l2 cache changes in foreground processCacheChanges(event.buildCacheChanges(manager.viewInvalidation)); } else { diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index d4e0379ff..b9d3ce08f 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -120,7 +120,7 @@ public class TransactionManager implements SpiTransactionManager { */ private final boolean changeLogAsync; - protected final boolean localL2Caching; + protected final boolean notifyL2CacheInForeground; protected final boolean viewInvalidation; @@ -144,7 +144,7 @@ public class TransactionManager implements SpiTransactionManager { this.databasePlatform = options.config.getDatabasePlatform(); this.skipCacheAfterWrite = options.config.isSkipCacheAfterWrite(); - this.localL2Caching = options.localL2Caching; + this.notifyL2CacheInForeground = options.notifyL2CacheInForeground; this.persistBatch = options.config.getPersistBatch(); this.persistBatchOnCascade = options.config.appliedPersistBatchOnCascade(); this.rollbackOnChecked = options.config.isTransactionRollbackOnChecked(); diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java index 87a469b80..6c8c40d47 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManagerOptions.java @@ -12,7 +12,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; */ public class TransactionManagerOptions { - final boolean localL2Caching; + final boolean notifyL2CacheInForeground; final ServerConfig config; final ClusterManager clusterManager; final BackgroundExecutor backgroundExecutor; @@ -23,11 +23,11 @@ public class TransactionManagerOptions { final SpiProfileHandler profileHandler; final TransactionScopeManager scopeManager; - public TransactionManagerOptions(boolean localL2Caching, ServerConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, + public TransactionManagerOptions(boolean notifyL2CacheInForeground, ServerConfig config, TransactionScopeManager scopeManager, ClusterManager clusterManager, BackgroundExecutor backgroundExecutor, DocStoreUpdateProcessor docStoreUpdateProcessor, BeanDescriptorManager descMgr, DataSourceSupplier dataSourceSupplier, SpiProfileHandler profileHandler) { - this.localL2Caching = localL2Caching; + this.notifyL2CacheInForeground = notifyL2CacheInForeground; this.config = config; this.scopeManager = scopeManager; this.clusterManager = clusterManager; diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index dbeb9cdb8..860ad9582 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import java.util.Properties; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -43,9 +44,13 @@ public class ServerConfigTest { props.setProperty("dbOffline", "true"); props.setProperty("jsonDateTime", "ISO8601"); props.setProperty("autoReadOnlyDataSource", "true"); + props.setProperty("disableL2Cache", "true"); + props.setProperty("notifyL2CacheInForeground", "true"); serverConfig.loadFromProperties(props); + assertTrue(serverConfig.isDisableL2Cache()); + assertTrue(serverConfig.isNotifyL2CacheInForeground()); assertTrue(serverConfig.isDbOffline()); assertTrue(serverConfig.isAutoReadOnlyDataSource()); @@ -66,7 +71,15 @@ public class ServerConfigTest { props1.setProperty("ebean.persistBatch", "ALL"); props1.setProperty("ebean.persistBatchOnCascade", "ALL"); + serverConfig.setNotifyL2CacheInForeground(true); + serverConfig.setDisableL2Cache(true); + props1.setProperty("ebean.disableL2Cache", "false"); + props1.setProperty("ebean.notifyL2CacheInForeground", "false"); + serverConfig.loadFromProperties(props1); + assertFalse(serverConfig.isDisableL2Cache()); + assertFalse(serverConfig.isNotifyL2CacheInForeground()); + serverConfig.loadTestProperties(); assertEquals(PersistBatch.ALL, serverConfig.getPersistBatch()); From cc7e22014dd023c5866a1986424f1ad0473648c2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 12:24:57 +1300 Subject: [PATCH 0030/1036] #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases Initial failing test ... and TypeResolver prior to cleanup --- .../server/type/TypeResolver.java | 517 ++++++++++++++++++ 1 file changed, 517 insertions(+) create mode 100644 src/main/java/io/ebeaninternal/server/type/TypeResolver.java diff --git a/src/main/java/io/ebeaninternal/server/type/TypeResolver.java b/src/main/java/io/ebeaninternal/server/type/TypeResolver.java new file mode 100644 index 000000000..46b91a00a --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/type/TypeResolver.java @@ -0,0 +1,517 @@ +package io.ebeaninternal.server.type; + + +//import java.lang.ref.Reference; +//import java.lang.ref.WeakReference; +//import java.lang.reflect.AccessibleObject; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.HashMap; +import java.util.Map; + +//import java.lang.reflect.Constructor; +//import java.lang.reflect.Field; +//import java.lang.reflect.Member; +//import java.lang.reflect.Method; +//import java.lang.reflect.Modifier; +//import java.security.AccessController; +//import java.security.PrivilegedExceptionAction; +//import java.util.Arrays; +//import java.util.Collections; +//import java.util.WeakHashMap; + +//import sun.misc.Unsafe; + +public class TypeResolver { + + /** Cache of type variable/argument pairs */ +// private static final Map, Reference, Type>>> TYPE_VARIABLE_CACHE = Collections +// .synchronizedMap(new WeakHashMap, Reference, Type>>>()); +// private static volatile boolean CACHE_ENABLED = true; +// private static boolean RESOLVES_LAMBDAS; +// private static Method GET_CONSTANT_POOL; +// private static Method GET_CONSTANT_POOL_SIZE; +// private static Method GET_CONSTANT_POOL_METHOD_AT; +// private static final Map OBJECT_METHODS = new HashMap(); +// private static final Map, Class> PRIMITIVE_WRAPPERS; +// private static final Double JAVA_VERSION; +// +// static { +// JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version", "0")); +// +// try { +//// Unsafe unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { +//// @Override +//// public Unsafe run() throws Exception { +//// final Field f = Unsafe.class.getDeclaredField("theUnsafe"); +//// f.setAccessible(true); +//// +//// return (Unsafe) f.get(null); +//// } +//// }); +// +//// GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool"); +//// String constantPoolName = JAVA_VERSION < 9 ? "sun.reflect.ConstantPool" : "jdk.internal.reflect.ConstantPool"; +//// Class constantPoolClass = Class.forName(constantPoolName); +//// GET_CONSTANT_POOL_SIZE = constantPoolClass.getDeclaredMethod("getSize"); +//// GET_CONSTANT_POOL_METHOD_AT = constantPoolClass.getDeclaredMethod("getMethodAt", int.class); +// +// // setting the methods as accessible +//// Field overrideField = AccessibleObject.class.getDeclaredField("override"); +//// long overrideFieldOffset = unsafe.objectFieldOffset(overrideField); +//// unsafe.putBoolean(GET_CONSTANT_POOL, overrideFieldOffset, true); +//// unsafe.putBoolean(GET_CONSTANT_POOL_SIZE, overrideFieldOffset, true); +//// unsafe.putBoolean(GET_CONSTANT_POOL_METHOD_AT, overrideFieldOffset, true); +// +// // additional checks - make sure we get a result when invoking the Class::getConstantPool and +// // ConstantPool::getSize on a class +//// Object constantPool = GET_CONSTANT_POOL.invoke(Object.class); +//// GET_CONSTANT_POOL_SIZE.invoke(constantPool); +// +//// for (Method method : Object.class.getDeclaredMethods()) +//// OBJECT_METHODS.put(method.getName(), method); +// +//// RESOLVES_LAMBDAS = true; +// } catch (Exception ignore) { +// } +// +//// Map, Class> types = new HashMap, Class>(); +//// types.put(boolean.class, Boolean.class); +//// types.put(byte.class, Byte.class); +//// types.put(char.class, Character.class); +//// types.put(double.class, Double.class); +//// types.put(float.class, Float.class); +//// types.put(int.class, Integer.class); +//// types.put(long.class, Long.class); +//// types.put(short.class, Short.class); +//// types.put(void.class, Void.class); +//// PRIMITIVE_WRAPPERS = Collections.unmodifiableMap(types); +// } + + /** An unknown type. */ + public static final class Unknown { + private Unknown() { + } + } + + private TypeResolver() { + } + +// /** +// * Enables the internal caching of resolved TypeVariables. +// */ +// public static void enableCache() { +// CACHE_ENABLED = true; +// } +// +// /** +// * Disables the internal caching of resolved TypeVariables. +// */ +// public static void disableCache() { +// TYPE_VARIABLE_CACHE.clear(); +// CACHE_ENABLED = false; +// } + + /** + * Returns the raw class representing the argument for the {@code type} using type variable information from the + * {@code subType}. If no arguments can be resolved then {@code Unknown.class} is returned. + * + * @param type to resolve argument for + * @param subType to extract type variable information from + * @return argument for {@code type} else {@link Unknown}.class if no type arguments are declared + * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code type} + */ + public static Class resolveRawArgument(Class type, Class subType) { + return resolveRawArgument(resolveGenericType(type, subType), subType); + } + + /** + * Returns the raw class representing the argument for the {@code genericType} using type variable information from + * the {@code subType}. If {@code genericType} is an instance of class, then {@code genericType} is returned. If no + * arguments can be resolved then {@code Unknown.class} is returned. + * + * @param genericType to resolve argument for + * @param subType to extract type variable information from + * @return argument for {@code genericType} else {@link Unknown}.class if no type arguments are declared + * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code genericType} + */ + public static Class resolveRawArgument(Type genericType, Class subType) { + Class[] arguments = resolveRawArguments(genericType, subType); + if (arguments == null) + return Unknown.class; + + if (arguments.length != 1) + throw new IllegalArgumentException( + "Expected 1 argument for generic type " + genericType + " but found " + arguments.length); + + return arguments[0]; + } + + /** + * Returns an array of raw classes representing arguments for the {@code type} using type variable information from + * the {@code subType}. Arguments for {@code type} that cannot be resolved are returned as {@code Unknown.class}. If + * no arguments can be resolved then {@code null} is returned. + * + * @param type to resolve arguments for + * @param subType to extract type variable information from + * @return array of raw classes representing arguments for the {@code type} else {@code null} if no type arguments are + * declared + */ + public static Class[] resolveRawArgs(Class type, Class subType) { + return resolveRawArguments(resolveGenericType(type, subType), subType); + } + + /** + * Returns an array of raw classes representing arguments for the {@code genericType} using type variable information + * from the {@code subType}. Arguments for {@code genericType} that cannot be resolved are returned as + * {@code Unknown.class}. If no arguments can be resolved then {@code null} is returned. + * + * @param genericType to resolve arguments for + * @param subType to extract type variable information from + * @return array of raw classes representing arguments for the {@code genericType} else {@code null} if no type + * arguments are declared + */ + public static Class[] resolveRawArguments(Type genericType, Class subType) { + Class[] result = null; + Class functionalInterface = null; + +// // Handle lambdas +// if (RESOLVES_LAMBDAS && subType.isSynthetic()) { +// Class fi = genericType instanceof ParameterizedType +// && ((ParameterizedType) genericType).getRawType() instanceof Class +// ? (Class) ((ParameterizedType) genericType).getRawType() +// : genericType instanceof Class ? (Class) genericType : null; +// if (fi != null && fi.isInterface()) +// functionalInterface = fi; +// } + + if (genericType instanceof ParameterizedType) { + ParameterizedType paramType = (ParameterizedType) genericType; + Type[] arguments = paramType.getActualTypeArguments(); + result = new Class[arguments.length]; + for (int i = 0; i < arguments.length; i++) + result[i] = resolveRawClass(arguments[i], subType, functionalInterface); + } else if (genericType instanceof TypeVariable) { + result = new Class[1]; + result[0] = resolveRawClass(genericType, subType, functionalInterface); + } else if (genericType instanceof Class) { + TypeVariable[] typeParams = ((Class) genericType).getTypeParameters(); + result = new Class[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) + result[i] = resolveRawClass(typeParams[i], subType, functionalInterface); + } + + return result; + } + + /** + * Returns the generic {@code type} using type variable information from the {@code subType} else {@code null} if the + * generic type cannot be resolved. + * + * @param type to resolve generic type for + * @param subType to extract type variable information from + * @return generic {@code type} else {@code null} if it cannot be resolved + */ + public static Type resolveGenericType(Class type, Type subType) { + Class rawType; + if (subType instanceof ParameterizedType) + rawType = (Class) ((ParameterizedType) subType).getRawType(); + else + rawType = (Class) subType; + + if (type.equals(rawType)) + return subType; + + Type result; + if (type.isInterface()) { + for (Type superInterface : rawType.getGenericInterfaces()) + if (superInterface != null && !superInterface.equals(Object.class)) + if ((result = resolveGenericType(type, superInterface)) != null) + return result; + } + + Type superClass = rawType.getGenericSuperclass(); + if (superClass != null && !superClass.equals(Object.class)) + if ((result = resolveGenericType(type, superClass)) != null) + return result; + + return null; + } + + /** + * Resolves the raw class for the {@code genericType}, using the type variable information from the {@code subType} + * else {@link Unknown} if the raw class cannot be resolved. + * + * @param genericType to resolve raw class for + * @param subType to extract type variable information from + * @return raw class for the {@code genericType} else {@link Unknown} if it cannot be resolved + */ + public static Class resolveRawClass(Type genericType, Class subType) { + return resolveRawClass(genericType, subType, null); + } + + private static Class resolveRawClass(Type genericType, Class subType, Class functionalInterface) { + if (genericType instanceof Class) { + return (Class) genericType; + } else if (genericType instanceof ParameterizedType) { + return resolveRawClass(((ParameterizedType) genericType).getRawType(), subType, functionalInterface); + } else if (genericType instanceof GenericArrayType) { + GenericArrayType arrayType = (GenericArrayType) genericType; + Class component = resolveRawClass(arrayType.getGenericComponentType(), subType, functionalInterface); + return Array.newInstance(component, 0).getClass(); + } else if (genericType instanceof TypeVariable) { + TypeVariable variable = (TypeVariable) genericType; + genericType = getTypeVariableMap(subType, functionalInterface).get(variable); + genericType = genericType == null ? resolveBound(variable) + : resolveRawClass(genericType, subType, functionalInterface); + } + + return genericType instanceof Class ? (Class) genericType : Unknown.class; + } + + private static Map, Type> getTypeVariableMap(final Class targetType, Class functionalInterface) { + + //Reference, Type>> ref = TYPE_VARIABLE_CACHE.get(targetType); + Map, Type> map = null;//ref != null ? ref.get() : null; + + if (map == null) { + map = new HashMap, Type>(); + +// // Populate lambdas +// if (functionalInterface != null) +// populateLambdaArgs(functionalInterface, targetType, map); + + // Populate interfaces + populateSuperTypeArgs(targetType.getGenericInterfaces(), map, functionalInterface != null); + + // Populate super classes and interfaces + Type genericType = targetType.getGenericSuperclass(); + Class type = targetType.getSuperclass(); + while (type != null && !Object.class.equals(type)) { + if (genericType instanceof ParameterizedType) + populateTypeArgs((ParameterizedType) genericType, map, false); + populateSuperTypeArgs(type.getGenericInterfaces(), map, false); + + genericType = type.getGenericSuperclass(); + type = type.getSuperclass(); + } + + // Populate enclosing classes + type = targetType; + while (type.isMemberClass()) { + genericType = type.getGenericSuperclass(); + if (genericType instanceof ParameterizedType) + populateTypeArgs((ParameterizedType) genericType, map, functionalInterface != null); + + type = type.getEnclosingClass(); + } + +// if (CACHE_ENABLED) +// TYPE_VARIABLE_CACHE.put(targetType, new WeakReference, Type>>(map)); + } + + return map; + } + + /** + * Populates the {@code map} with with variable/argument pairs for the given {@code types}. + */ + private static void populateSuperTypeArgs(final Type[] types, final Map, Type> map, + boolean depthFirst) { + for (Type type : types) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + if (!depthFirst) + populateTypeArgs(parameterizedType, map, depthFirst); + Type rawType = parameterizedType.getRawType(); + if (rawType instanceof Class) + populateSuperTypeArgs(((Class) rawType).getGenericInterfaces(), map, depthFirst); + if (depthFirst) + populateTypeArgs(parameterizedType, map, depthFirst); + } else if (type instanceof Class) { + populateSuperTypeArgs(((Class) type).getGenericInterfaces(), map, depthFirst); + } + } + } + + /** + * Populates the {@code map} with variable/argument pairs for the given {@code type}. + */ + private static void populateTypeArgs(ParameterizedType type, Map, Type> map, boolean depthFirst) { + if (type.getRawType() instanceof Class) { + TypeVariable[] typeVariables = ((Class) type.getRawType()).getTypeParameters(); + Type[] typeArguments = type.getActualTypeArguments(); + + if (type.getOwnerType() != null) { + Type owner = type.getOwnerType(); + if (owner instanceof ParameterizedType) + populateTypeArgs((ParameterizedType) owner, map, depthFirst); + } + + for (int i = 0; i < typeArguments.length; i++) { + TypeVariable variable = typeVariables[i]; + Type typeArgument = typeArguments[i]; + + if (typeArgument instanceof Class) { + map.put(variable, typeArgument); + } else if (typeArgument instanceof GenericArrayType) { + map.put(variable, typeArgument); + } else if (typeArgument instanceof ParameterizedType) { + map.put(variable, typeArgument); + } else if (typeArgument instanceof TypeVariable) { + TypeVariable typeVariableArgument = (TypeVariable) typeArgument; + if (depthFirst) { + Type existingType = map.get(variable); + if (existingType != null) { + map.put(typeVariableArgument, existingType); + continue; + } + } + + Type resolvedType = map.get(typeVariableArgument); + if (resolvedType == null) + resolvedType = resolveBound(typeVariableArgument); + map.put(variable, resolvedType); + } + } + } + } + + /** + * Resolves the first bound for the {@code typeVariable}, returning {@code Unknown.class} if none can be resolved. + */ + public static Type resolveBound(TypeVariable typeVariable) { + Type[] bounds = typeVariable.getBounds(); + if (bounds.length == 0) + return Unknown.class; + + Type bound = bounds[0]; + if (bound instanceof TypeVariable) + bound = resolveBound((TypeVariable) bound); + + return bound == Object.class ? Unknown.class : bound; + } + +// /** +// * Populates the {@code map} with variable/argument pairs for the {@code functionalInterface}. +// */ +// private static void populateLambdaArgs(Class functionalInterface, final Class lambdaType, +// Map, Type> map) { +// if (RESOLVES_LAMBDAS) { +// // Find SAM +// for (Method m : functionalInterface.getMethods()) { +// if (!isDefaultMethod(m) && !Modifier.isStatic(m.getModifiers()) && !m.isBridge()) { +// // Skip methods that override Object.class +// Method objectMethod = OBJECT_METHODS.get(m.getName()); +// if (objectMethod != null && Arrays.equals(m.getTypeParameters(), objectMethod.getTypeParameters())) +// continue; +// +// // Get functional interface's type params +// Type returnTypeVar = m.getGenericReturnType(); +// Type[] paramTypeVars = m.getGenericParameterTypes(); +// +// Member member = getMemberRef(lambdaType); +// if (member == null) +// return; +// +// // Populate return type argument +// if (returnTypeVar instanceof TypeVariable) { +// Class returnType = member instanceof Method ? ((Method) member).getReturnType() +// : ((Constructor) member).getDeclaringClass(); +// returnType = wrapPrimitives(returnType); +// if (!returnType.equals(Void.class)) +// map.put((TypeVariable) returnTypeVar, returnType); +// } +// +// Class[] arguments = member instanceof Method ? ((Method) member).getParameterTypes() +// : ((Constructor) member).getParameterTypes(); +// +// // Populate object type from arbitrary object method reference +// int paramOffset = 0; +// if (paramTypeVars.length > 0 && paramTypeVars[0] instanceof TypeVariable +// && paramTypeVars.length == arguments.length + 1) { +// Class instanceType = member.getDeclaringClass(); +// map.put((TypeVariable) paramTypeVars[0], instanceType); +// paramOffset = 1; +// } +// +// // Handle additional arguments that are captured from the lambda's enclosing scope +// int argOffset = 0; +// if (paramTypeVars.length < arguments.length) { +// argOffset = arguments.length - paramTypeVars.length; +// } +// +// // Populate type arguments +// for (int i = 0; i + argOffset < arguments.length; i++) { +// if (paramTypeVars[i] instanceof TypeVariable) +// map.put((TypeVariable) paramTypeVars[i + paramOffset], wrapPrimitives(arguments[i + argOffset])); +// } +// +// return; +// } +// } +// } +// } +// +// private static boolean isDefaultMethod(Method m) { +// return JAVA_VERSION >= 1.8 && m.isDefault(); +// } +// +// private static Member getMemberRef(Class type) { +// Object constantPool; +// try { +// constantPool = GET_CONSTANT_POOL.invoke(type); +// } catch (Exception ignore) { +// return null; +// } +// +// Member result = null; +// for (int i = getConstantPoolSize(constantPool) - 1; i >= 0; i--) { +// Member member = getConstantPoolMethodAt(constantPool, i); +// // Skip SerializedLambda constructors and members of the "type" class +// if (member == null +// || (member instanceof Constructor +// && member.getDeclaringClass().getName().equals("java.lang.invoke.SerializedLambda")) +// || member.getDeclaringClass().isAssignableFrom(type)) +// continue; +// +// result = member; +// +// // Return if not valueOf method +// if (!(member instanceof Method) || !isAutoBoxingMethod((Method) member)) +// break; +// } +// +// return result; +// } +// +// private static boolean isAutoBoxingMethod(Method method) { +// Class[] parameters = method.getParameterTypes(); +// return method.getName().equals("valueOf") && parameters.length == 1 && parameters[0].isPrimitive() +// && wrapPrimitives(parameters[0]).equals(method.getDeclaringClass()); +// } +// +// private static Class wrapPrimitives(Class clazz) { +// return clazz.isPrimitive() ? PRIMITIVE_WRAPPERS.get(clazz) : clazz; +// } +// +// private static int getConstantPoolSize(Object constantPool) { +// try { +// return (Integer) GET_CONSTANT_POOL_SIZE.invoke(constantPool); +// } catch (Exception ignore) { +// return 0; +// } +// } +// +// private static Member getConstantPoolMethodAt(Object constantPool, int i) { +// try { +// return (Member) GET_CONSTANT_POOL_METHOD_AT.invoke(constantPool, i); +// } catch (Exception ignore) { +// return null; +// } +// } +} From 1829c746948e4ed54a745beadb1a19ab009824bd Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 12:25:07 +1300 Subject: [PATCH 0031/1036] #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases Initial failing test ... and TypeResolver prior to cleanup --- .../server/type/TypeReflectHelperTest.java | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java diff --git a/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java new file mode 100644 index 000000000..2197ce6d2 --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java @@ -0,0 +1,105 @@ +package io.ebeaninternal.server.type; + +import io.ebean.config.ScalarTypeConverter; +import org.junit.Test; +import org.tests.model.ivo.Money; +import org.tests.model.ivo.Oid; +import org.tests.model.ivo.SysTime; +import org.tests.model.ivo.converter.MoneyTypeConverter; +import org.tests.model.ivo.converter.OidTypeConverter; +import org.tests.model.ivo.converter.SysTimeConverter; + +import javax.persistence.AttributeConverter; +import java.math.BigDecimal; +import java.sql.Timestamp; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TypeReflectHelperTest { + + @Test + public void getParams_MoneyTypeConverter() { + + Class[] params0 = TypeResolver.resolveRawArgs(AttributeConverter.class, MoneyTypeConverter.class); + + Class[] params = TypeReflectHelper.getParams(MoneyTypeConverter.class, AttributeConverter.class); + + assertThat(params.length).isEqualTo(2); + assertThat(params[0]).isEqualTo(Money.class); + assertThat(params[1]).isEqualTo(BigDecimal.class); + + assertThat(params0[0]).isEqualTo(Money.class); + assertThat(params0[1]).isEqualTo(BigDecimal.class); + } + + @Test + public void getParams_OidTypeConverter() { + + Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, OidTypeConverter.class); + + Class[] params = TypeReflectHelper.getParams(OidTypeConverter.class, ScalarTypeConverter.class); + + assertThat(params.length).isEqualTo(2); + assertThat(params[0]).isEqualTo(Oid.class); + assertThat(params[1]).isEqualTo(Long.class); + + assertThat(params0[0]).isEqualTo(Oid.class); + assertThat(params0[1]).isEqualTo(Long.class); + } + + @Test + public void getParams_SysTimeConverter() { + + Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, SysTimeConverter.class); + + Class[] params = TypeReflectHelper.getParams(SysTimeConverter.class, ScalarTypeConverter.class); + + assertThat(params.length).isEqualTo(2); + assertThat(params[0]).isEqualTo(SysTime.class); + assertThat(params[1]).isEqualTo(Timestamp.class); + + assertThat(params0[0]).isEqualTo(SysTime.class); + assertThat(params0[1]).isEqualTo(Timestamp.class); + } + + @Test + public void getParams_RichTextConverter() { + + Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, RichTextConverter.class); + assertThat(params0.length).isEqualTo(2); + assertThat(params0[0]).isEqualTo(RichText.class); + assertThat(params0[1]).isEqualTo(byte[].class); + + // failing test here with NPE + Class[] params = TypeReflectHelper.getParams(RichTextConverter.class, ScalarTypeConverter.class); + + assertThat(params.length).isEqualTo(2); + assertThat(params[0]).isEqualTo(RichText.class); + assertThat(params[1]).isEqualTo(byte[].class); + } + + static class RichText { + + } + + static class RichTextConverter extends Direct {} + + static class Direct implements ScalarTypeConverter { + + @Override + public M getNullValue() { + return null; + } + + @Override + public M wrapValue(byte[] scalarType) { + return null; + } + + @Override + public byte[] unwrapValue(M beanType) { + return new byte[0]; + } + } + +} From ac36172cc61e38b1f982135cc2ab72965d7da0f5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 12:47:10 +1300 Subject: [PATCH 0032/1036] #997 - TypeReflectHelper does not resolve type variables correctly in non-trivial cases Part 2 - Fix the failing test, swap in use of TypeResolver and remove all the unused features. --- .../server/type/TypeReflectHelper.java | 24 +- .../server/type/TypeResolver.java | 421 +++--------------- .../server/type/TypeReflectHelperTest.java | 21 - 3 files changed, 75 insertions(+), 391 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java index 95cc0529f..a69dcd75d 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java @@ -6,13 +6,7 @@ import java.lang.reflect.Type; public class TypeReflectHelper { public static Class[] getParams(Class cls, Class matchRawType) { - - Type[] types = getParamType(cls, matchRawType); - Class[] result = new Class[types.length]; - for (int i = 0; i < result.length; i++) { - result[i] = getClass(types[i]); - } - return result; + return TypeResolver.resolveRawArgs(matchRawType, cls); } public static Class getClass(Type type) { @@ -26,20 +20,4 @@ public class TypeReflectHelper { return (Class) type; } } - - private static Type[] getParamType(Class cls, Class matchRawType) { - - Type[] gis = cls.getGenericInterfaces(); - for (Type type : gis) { - if (type instanceof ParameterizedType) { - ParameterizedType paramType = (ParameterizedType) type; - Type rawType = paramType.getRawType(); - if (rawType.equals(matchRawType)) { - - return paramType.getActualTypeArguments(); - } - } - } - return null; - } } diff --git a/src/main/java/io/ebeaninternal/server/type/TypeResolver.java b/src/main/java/io/ebeaninternal/server/type/TypeResolver.java index 46b91a00a..2fecd6a4b 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeResolver.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeResolver.java @@ -1,10 +1,6 @@ package io.ebeaninternal.server.type; -//import java.lang.ref.Reference; -//import java.lang.ref.WeakReference; -//import java.lang.reflect.AccessibleObject; - import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; @@ -13,87 +9,16 @@ import java.lang.reflect.TypeVariable; import java.util.HashMap; import java.util.Map; -//import java.lang.reflect.Constructor; -//import java.lang.reflect.Field; -//import java.lang.reflect.Member; -//import java.lang.reflect.Method; -//import java.lang.reflect.Modifier; -//import java.security.AccessController; -//import java.security.PrivilegedExceptionAction; -//import java.util.Arrays; -//import java.util.Collections; -//import java.util.WeakHashMap; - -//import sun.misc.Unsafe; - -public class TypeResolver { - - /** Cache of type variable/argument pairs */ -// private static final Map, Reference, Type>>> TYPE_VARIABLE_CACHE = Collections -// .synchronizedMap(new WeakHashMap, Reference, Type>>>()); -// private static volatile boolean CACHE_ENABLED = true; -// private static boolean RESOLVES_LAMBDAS; -// private static Method GET_CONSTANT_POOL; -// private static Method GET_CONSTANT_POOL_SIZE; -// private static Method GET_CONSTANT_POOL_METHOD_AT; -// private static final Map OBJECT_METHODS = new HashMap(); -// private static final Map, Class> PRIMITIVE_WRAPPERS; -// private static final Double JAVA_VERSION; -// -// static { -// JAVA_VERSION = Double.parseDouble(System.getProperty("java.specification.version", "0")); -// -// try { -//// Unsafe unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { -//// @Override -//// public Unsafe run() throws Exception { -//// final Field f = Unsafe.class.getDeclaredField("theUnsafe"); -//// f.setAccessible(true); -//// -//// return (Unsafe) f.get(null); -//// } -//// }); -// -//// GET_CONSTANT_POOL = Class.class.getDeclaredMethod("getConstantPool"); -//// String constantPoolName = JAVA_VERSION < 9 ? "sun.reflect.ConstantPool" : "jdk.internal.reflect.ConstantPool"; -//// Class constantPoolClass = Class.forName(constantPoolName); -//// GET_CONSTANT_POOL_SIZE = constantPoolClass.getDeclaredMethod("getSize"); -//// GET_CONSTANT_POOL_METHOD_AT = constantPoolClass.getDeclaredMethod("getMethodAt", int.class); -// -// // setting the methods as accessible -//// Field overrideField = AccessibleObject.class.getDeclaredField("override"); -//// long overrideFieldOffset = unsafe.objectFieldOffset(overrideField); -//// unsafe.putBoolean(GET_CONSTANT_POOL, overrideFieldOffset, true); -//// unsafe.putBoolean(GET_CONSTANT_POOL_SIZE, overrideFieldOffset, true); -//// unsafe.putBoolean(GET_CONSTANT_POOL_METHOD_AT, overrideFieldOffset, true); -// -// // additional checks - make sure we get a result when invoking the Class::getConstantPool and -// // ConstantPool::getSize on a class -//// Object constantPool = GET_CONSTANT_POOL.invoke(Object.class); -//// GET_CONSTANT_POOL_SIZE.invoke(constantPool); -// -//// for (Method method : Object.class.getDeclaredMethods()) -//// OBJECT_METHODS.put(method.getName(), method); -// -//// RESOLVES_LAMBDAS = true; -// } catch (Exception ignore) { -// } -// -//// Map, Class> types = new HashMap, Class>(); -//// types.put(boolean.class, Boolean.class); -//// types.put(byte.class, Byte.class); -//// types.put(char.class, Character.class); -//// types.put(double.class, Double.class); -//// types.put(float.class, Float.class); -//// types.put(int.class, Integer.class); -//// types.put(long.class, Long.class); -//// types.put(short.class, Short.class); -//// types.put(void.class, Void.class); -//// PRIMITIVE_WRAPPERS = Collections.unmodifiableMap(types); -// } +/** + * This class is a modified version of TypeResolver from https://github.com/jhalterman/typetools + * which is Apache 2 license. + * + * It is a cut down version removing the lambda support and related sun.misc.Unsafe use etc. + */ +class TypeResolver { /** An unknown type. */ - public static final class Unknown { + private static final class Unknown { private Unknown() { } } @@ -101,56 +26,6 @@ public class TypeResolver { private TypeResolver() { } -// /** -// * Enables the internal caching of resolved TypeVariables. -// */ -// public static void enableCache() { -// CACHE_ENABLED = true; -// } -// -// /** -// * Disables the internal caching of resolved TypeVariables. -// */ -// public static void disableCache() { -// TYPE_VARIABLE_CACHE.clear(); -// CACHE_ENABLED = false; -// } - - /** - * Returns the raw class representing the argument for the {@code type} using type variable information from the - * {@code subType}. If no arguments can be resolved then {@code Unknown.class} is returned. - * - * @param type to resolve argument for - * @param subType to extract type variable information from - * @return argument for {@code type} else {@link Unknown}.class if no type arguments are declared - * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code type} - */ - public static Class resolveRawArgument(Class type, Class subType) { - return resolveRawArgument(resolveGenericType(type, subType), subType); - } - - /** - * Returns the raw class representing the argument for the {@code genericType} using type variable information from - * the {@code subType}. If {@code genericType} is an instance of class, then {@code genericType} is returned. If no - * arguments can be resolved then {@code Unknown.class} is returned. - * - * @param genericType to resolve argument for - * @param subType to extract type variable information from - * @return argument for {@code genericType} else {@link Unknown}.class if no type arguments are declared - * @throws IllegalArgumentException if more or less than one argument is resolved for the {@code genericType} - */ - public static Class resolveRawArgument(Type genericType, Class subType) { - Class[] arguments = resolveRawArguments(genericType, subType); - if (arguments == null) - return Unknown.class; - - if (arguments.length != 1) - throw new IllegalArgumentException( - "Expected 1 argument for generic type " + genericType + " but found " + arguments.length); - - return arguments[0]; - } - /** * Returns an array of raw classes representing arguments for the {@code type} using type variable information from * the {@code subType}. Arguments for {@code type} that cannot be resolved are returned as {@code Unknown.class}. If @@ -161,7 +36,7 @@ public class TypeResolver { * @return array of raw classes representing arguments for the {@code type} else {@code null} if no type arguments are * declared */ - public static Class[] resolveRawArgs(Class type, Class subType) { + static Class[] resolveRawArgs(Class type, Class subType) { return resolveRawArguments(resolveGenericType(type, subType), subType); } @@ -175,34 +50,27 @@ public class TypeResolver { * @return array of raw classes representing arguments for the {@code genericType} else {@code null} if no type * arguments are declared */ - public static Class[] resolveRawArguments(Type genericType, Class subType) { + private static Class[] resolveRawArguments(Type genericType, Class subType) { Class[] result = null; - Class functionalInterface = null; - -// // Handle lambdas -// if (RESOLVES_LAMBDAS && subType.isSynthetic()) { -// Class fi = genericType instanceof ParameterizedType -// && ((ParameterizedType) genericType).getRawType() instanceof Class -// ? (Class) ((ParameterizedType) genericType).getRawType() -// : genericType instanceof Class ? (Class) genericType : null; -// if (fi != null && fi.isInterface()) -// functionalInterface = fi; -// } if (genericType instanceof ParameterizedType) { ParameterizedType paramType = (ParameterizedType) genericType; Type[] arguments = paramType.getActualTypeArguments(); result = new Class[arguments.length]; - for (int i = 0; i < arguments.length; i++) - result[i] = resolveRawClass(arguments[i], subType, functionalInterface); + for (int i = 0; i < arguments.length; i++) { + result[i] = resolveRawClass(arguments[i], subType); + } + } else if (genericType instanceof TypeVariable) { result = new Class[1]; - result[0] = resolveRawClass(genericType, subType, functionalInterface); + result[0] = resolveRawClass(genericType, subType); + } else if (genericType instanceof Class) { TypeVariable[] typeParams = ((Class) genericType).getTypeParameters(); result = new Class[typeParams.length]; - for (int i = 0; i < typeParams.length; i++) - result[i] = resolveRawClass(typeParams[i], subType, functionalInterface); + for (int i = 0; i < typeParams.length; i++) { + result[i] = resolveRawClass(typeParams[i], subType); + } } return result; @@ -216,15 +84,17 @@ public class TypeResolver { * @param subType to extract type variable information from * @return generic {@code type} else {@code null} if it cannot be resolved */ - public static Type resolveGenericType(Class type, Type subType) { + private static Type resolveGenericType(Class type, Type subType) { Class rawType; - if (subType instanceof ParameterizedType) + if (subType instanceof ParameterizedType) { rawType = (Class) ((ParameterizedType) subType).getRawType(); - else + } else { rawType = (Class) subType; + } - if (type.equals(rawType)) + if (type.equals(rawType)) { return subType; + } Type result; if (type.isInterface()) { @@ -235,83 +105,65 @@ public class TypeResolver { } Type superClass = rawType.getGenericSuperclass(); - if (superClass != null && !superClass.equals(Object.class)) - if ((result = resolveGenericType(type, superClass)) != null) + if (superClass != null && !superClass.equals(Object.class)) { + if ((result = resolveGenericType(type, superClass)) != null) { return result; + } + } return null; } - /** - * Resolves the raw class for the {@code genericType}, using the type variable information from the {@code subType} - * else {@link Unknown} if the raw class cannot be resolved. - * - * @param genericType to resolve raw class for - * @param subType to extract type variable information from - * @return raw class for the {@code genericType} else {@link Unknown} if it cannot be resolved - */ - public static Class resolveRawClass(Type genericType, Class subType) { - return resolveRawClass(genericType, subType, null); - } - - private static Class resolveRawClass(Type genericType, Class subType, Class functionalInterface) { + private static Class resolveRawClass(Type genericType, Class subType) { if (genericType instanceof Class) { return (Class) genericType; + } else if (genericType instanceof ParameterizedType) { - return resolveRawClass(((ParameterizedType) genericType).getRawType(), subType, functionalInterface); + return resolveRawClass(((ParameterizedType) genericType).getRawType(), subType); + } else if (genericType instanceof GenericArrayType) { GenericArrayType arrayType = (GenericArrayType) genericType; - Class component = resolveRawClass(arrayType.getGenericComponentType(), subType, functionalInterface); + Class component = resolveRawClass(arrayType.getGenericComponentType(), subType); return Array.newInstance(component, 0).getClass(); + } else if (genericType instanceof TypeVariable) { TypeVariable variable = (TypeVariable) genericType; - genericType = getTypeVariableMap(subType, functionalInterface).get(variable); + genericType = getTypeVariableMap(subType).get(variable); genericType = genericType == null ? resolveBound(variable) - : resolveRawClass(genericType, subType, functionalInterface); + : resolveRawClass(genericType, subType); } return genericType instanceof Class ? (Class) genericType : Unknown.class; } - private static Map, Type> getTypeVariableMap(final Class targetType, Class functionalInterface) { + private static Map, Type> getTypeVariableMap(final Class targetType) { - //Reference, Type>> ref = TYPE_VARIABLE_CACHE.get(targetType); - Map, Type> map = null;//ref != null ? ref.get() : null; + Map, Type> map = new HashMap<>(); - if (map == null) { - map = new HashMap, Type>(); + // Populate interfaces + populateSuperTypeArgs(targetType.getGenericInterfaces(), map); -// // Populate lambdas -// if (functionalInterface != null) -// populateLambdaArgs(functionalInterface, targetType, map); - - // Populate interfaces - populateSuperTypeArgs(targetType.getGenericInterfaces(), map, functionalInterface != null); - - // Populate super classes and interfaces - Type genericType = targetType.getGenericSuperclass(); - Class type = targetType.getSuperclass(); - while (type != null && !Object.class.equals(type)) { - if (genericType instanceof ParameterizedType) - populateTypeArgs((ParameterizedType) genericType, map, false); - populateSuperTypeArgs(type.getGenericInterfaces(), map, false); - - genericType = type.getGenericSuperclass(); - type = type.getSuperclass(); + // Populate super classes and interfaces + Type genericType = targetType.getGenericSuperclass(); + Class type = targetType.getSuperclass(); + while (type != null && !Object.class.equals(type)) { + if (genericType instanceof ParameterizedType) { + populateTypeArgs((ParameterizedType) genericType, map); } + populateSuperTypeArgs(type.getGenericInterfaces(), map); - // Populate enclosing classes - type = targetType; - while (type.isMemberClass()) { - genericType = type.getGenericSuperclass(); - if (genericType instanceof ParameterizedType) - populateTypeArgs((ParameterizedType) genericType, map, functionalInterface != null); + genericType = type.getGenericSuperclass(); + type = type.getSuperclass(); + } - type = type.getEnclosingClass(); + // Populate enclosing classes + type = targetType; + while (type.isMemberClass()) { + genericType = type.getGenericSuperclass(); + if (genericType instanceof ParameterizedType) { + populateTypeArgs((ParameterizedType) genericType, map); } - -// if (CACHE_ENABLED) -// TYPE_VARIABLE_CACHE.put(targetType, new WeakReference, Type>>(map)); + type = type.getEnclosingClass(); } return map; @@ -320,20 +172,18 @@ public class TypeResolver { /** * Populates the {@code map} with with variable/argument pairs for the given {@code types}. */ - private static void populateSuperTypeArgs(final Type[] types, final Map, Type> map, - boolean depthFirst) { + private static void populateSuperTypeArgs(final Type[] types, final Map, Type> map) { + for (Type type : types) { if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; - if (!depthFirst) - populateTypeArgs(parameterizedType, map, depthFirst); + populateTypeArgs(parameterizedType, map); Type rawType = parameterizedType.getRawType(); - if (rawType instanceof Class) - populateSuperTypeArgs(((Class) rawType).getGenericInterfaces(), map, depthFirst); - if (depthFirst) - populateTypeArgs(parameterizedType, map, depthFirst); + if (rawType instanceof Class) { + populateSuperTypeArgs(((Class) rawType).getGenericInterfaces(), map); + } } else if (type instanceof Class) { - populateSuperTypeArgs(((Class) type).getGenericInterfaces(), map, depthFirst); + populateSuperTypeArgs(((Class) type).getGenericInterfaces(), map); } } } @@ -341,15 +191,16 @@ public class TypeResolver { /** * Populates the {@code map} with variable/argument pairs for the given {@code type}. */ - private static void populateTypeArgs(ParameterizedType type, Map, Type> map, boolean depthFirst) { + private static void populateTypeArgs(ParameterizedType type, Map, Type> map) { if (type.getRawType() instanceof Class) { TypeVariable[] typeVariables = ((Class) type.getRawType()).getTypeParameters(); Type[] typeArguments = type.getActualTypeArguments(); if (type.getOwnerType() != null) { Type owner = type.getOwnerType(); - if (owner instanceof ParameterizedType) - populateTypeArgs((ParameterizedType) owner, map, depthFirst); + if (owner instanceof ParameterizedType) { + populateTypeArgs((ParameterizedType) owner, map); + } } for (int i = 0; i < typeArguments.length; i++) { @@ -364,14 +215,6 @@ public class TypeResolver { map.put(variable, typeArgument); } else if (typeArgument instanceof TypeVariable) { TypeVariable typeVariableArgument = (TypeVariable) typeArgument; - if (depthFirst) { - Type existingType = map.get(variable); - if (existingType != null) { - map.put(typeVariableArgument, existingType); - continue; - } - } - Type resolvedType = map.get(typeVariableArgument); if (resolvedType == null) resolvedType = resolveBound(typeVariableArgument); @@ -384,134 +227,18 @@ public class TypeResolver { /** * Resolves the first bound for the {@code typeVariable}, returning {@code Unknown.class} if none can be resolved. */ - public static Type resolveBound(TypeVariable typeVariable) { + private static Type resolveBound(TypeVariable typeVariable) { Type[] bounds = typeVariable.getBounds(); - if (bounds.length == 0) + if (bounds.length == 0) { return Unknown.class; + } Type bound = bounds[0]; - if (bound instanceof TypeVariable) + if (bound instanceof TypeVariable) { bound = resolveBound((TypeVariable) bound); + } return bound == Object.class ? Unknown.class : bound; } -// /** -// * Populates the {@code map} with variable/argument pairs for the {@code functionalInterface}. -// */ -// private static void populateLambdaArgs(Class functionalInterface, final Class lambdaType, -// Map, Type> map) { -// if (RESOLVES_LAMBDAS) { -// // Find SAM -// for (Method m : functionalInterface.getMethods()) { -// if (!isDefaultMethod(m) && !Modifier.isStatic(m.getModifiers()) && !m.isBridge()) { -// // Skip methods that override Object.class -// Method objectMethod = OBJECT_METHODS.get(m.getName()); -// if (objectMethod != null && Arrays.equals(m.getTypeParameters(), objectMethod.getTypeParameters())) -// continue; -// -// // Get functional interface's type params -// Type returnTypeVar = m.getGenericReturnType(); -// Type[] paramTypeVars = m.getGenericParameterTypes(); -// -// Member member = getMemberRef(lambdaType); -// if (member == null) -// return; -// -// // Populate return type argument -// if (returnTypeVar instanceof TypeVariable) { -// Class returnType = member instanceof Method ? ((Method) member).getReturnType() -// : ((Constructor) member).getDeclaringClass(); -// returnType = wrapPrimitives(returnType); -// if (!returnType.equals(Void.class)) -// map.put((TypeVariable) returnTypeVar, returnType); -// } -// -// Class[] arguments = member instanceof Method ? ((Method) member).getParameterTypes() -// : ((Constructor) member).getParameterTypes(); -// -// // Populate object type from arbitrary object method reference -// int paramOffset = 0; -// if (paramTypeVars.length > 0 && paramTypeVars[0] instanceof TypeVariable -// && paramTypeVars.length == arguments.length + 1) { -// Class instanceType = member.getDeclaringClass(); -// map.put((TypeVariable) paramTypeVars[0], instanceType); -// paramOffset = 1; -// } -// -// // Handle additional arguments that are captured from the lambda's enclosing scope -// int argOffset = 0; -// if (paramTypeVars.length < arguments.length) { -// argOffset = arguments.length - paramTypeVars.length; -// } -// -// // Populate type arguments -// for (int i = 0; i + argOffset < arguments.length; i++) { -// if (paramTypeVars[i] instanceof TypeVariable) -// map.put((TypeVariable) paramTypeVars[i + paramOffset], wrapPrimitives(arguments[i + argOffset])); -// } -// -// return; -// } -// } -// } -// } -// -// private static boolean isDefaultMethod(Method m) { -// return JAVA_VERSION >= 1.8 && m.isDefault(); -// } -// -// private static Member getMemberRef(Class type) { -// Object constantPool; -// try { -// constantPool = GET_CONSTANT_POOL.invoke(type); -// } catch (Exception ignore) { -// return null; -// } -// -// Member result = null; -// for (int i = getConstantPoolSize(constantPool) - 1; i >= 0; i--) { -// Member member = getConstantPoolMethodAt(constantPool, i); -// // Skip SerializedLambda constructors and members of the "type" class -// if (member == null -// || (member instanceof Constructor -// && member.getDeclaringClass().getName().equals("java.lang.invoke.SerializedLambda")) -// || member.getDeclaringClass().isAssignableFrom(type)) -// continue; -// -// result = member; -// -// // Return if not valueOf method -// if (!(member instanceof Method) || !isAutoBoxingMethod((Method) member)) -// break; -// } -// -// return result; -// } -// -// private static boolean isAutoBoxingMethod(Method method) { -// Class[] parameters = method.getParameterTypes(); -// return method.getName().equals("valueOf") && parameters.length == 1 && parameters[0].isPrimitive() -// && wrapPrimitives(parameters[0]).equals(method.getDeclaringClass()); -// } -// -// private static Class wrapPrimitives(Class clazz) { -// return clazz.isPrimitive() ? PRIMITIVE_WRAPPERS.get(clazz) : clazz; -// } -// -// private static int getConstantPoolSize(Object constantPool) { -// try { -// return (Integer) GET_CONSTANT_POOL_SIZE.invoke(constantPool); -// } catch (Exception ignore) { -// return 0; -// } -// } -// -// private static Member getConstantPoolMethodAt(Object constantPool, int i) { -// try { -// return (Member) GET_CONSTANT_POOL_METHOD_AT.invoke(constantPool, i); -// } catch (Exception ignore) { -// return null; -// } -// } } diff --git a/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java index 2197ce6d2..fe815617d 100644 --- a/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java +++ b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java @@ -20,57 +20,36 @@ public class TypeReflectHelperTest { @Test public void getParams_MoneyTypeConverter() { - Class[] params0 = TypeResolver.resolveRawArgs(AttributeConverter.class, MoneyTypeConverter.class); - Class[] params = TypeReflectHelper.getParams(MoneyTypeConverter.class, AttributeConverter.class); assertThat(params.length).isEqualTo(2); assertThat(params[0]).isEqualTo(Money.class); assertThat(params[1]).isEqualTo(BigDecimal.class); - - assertThat(params0[0]).isEqualTo(Money.class); - assertThat(params0[1]).isEqualTo(BigDecimal.class); } @Test public void getParams_OidTypeConverter() { - Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, OidTypeConverter.class); - Class[] params = TypeReflectHelper.getParams(OidTypeConverter.class, ScalarTypeConverter.class); assertThat(params.length).isEqualTo(2); assertThat(params[0]).isEqualTo(Oid.class); assertThat(params[1]).isEqualTo(Long.class); - - assertThat(params0[0]).isEqualTo(Oid.class); - assertThat(params0[1]).isEqualTo(Long.class); } @Test public void getParams_SysTimeConverter() { - Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, SysTimeConverter.class); - Class[] params = TypeReflectHelper.getParams(SysTimeConverter.class, ScalarTypeConverter.class); assertThat(params.length).isEqualTo(2); assertThat(params[0]).isEqualTo(SysTime.class); assertThat(params[1]).isEqualTo(Timestamp.class); - - assertThat(params0[0]).isEqualTo(SysTime.class); - assertThat(params0[1]).isEqualTo(Timestamp.class); } @Test public void getParams_RichTextConverter() { - Class[] params0 = TypeResolver.resolveRawArgs(ScalarTypeConverter.class, RichTextConverter.class); - assertThat(params0.length).isEqualTo(2); - assertThat(params0[0]).isEqualTo(RichText.class); - assertThat(params0[1]).isEqualTo(byte[].class); - - // failing test here with NPE Class[] params = TypeReflectHelper.getParams(RichTextConverter.class, ScalarTypeConverter.class); assertThat(params.length).isEqualTo(2); From 3d62e84d591d38349d02d37cacc0b85816f37942 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 14:40:35 +1300 Subject: [PATCH 0033/1036] #1263 - ENH: Make Transaction API Fluid such that we can set multiple thing like batchSize and label in a fluid fashion --- src/main/java/io/ebean/Transaction.java | 36 ++++----- .../ebeaninternal/api/ScopedTransaction.java | 4 +- .../api/SpiTransactionProxy.java | 52 ++++++++----- .../transaction/DocStoreOnlyTransaction.java | 5 +- .../ImplicitReadOnlyTransaction.java | 52 ++++++++----- .../server/transaction/JdbcTransaction.java | 55 +++++++++----- .../server/transaction/NoTransaction.java | 73 ++++++++++--------- .../batchinsert/TestBatchInsertFlush.java | 12 +-- .../batchinsert/TestBatchInsertSimple.java | 13 ++-- .../tests/transaction/TestSqlServerBatch.java | 4 +- 10 files changed, 180 insertions(+), 126 deletions(-) diff --git a/src/main/java/io/ebean/Transaction.java b/src/main/java/io/ebean/Transaction.java index 743fcc138..b629c24f9 100644 --- a/src/main/java/io/ebean/Transaction.java +++ b/src/main/java/io/ebean/Transaction.java @@ -57,7 +57,7 @@ public interface Transaction extends AutoCloseable { /** * Register a TransactionCallback with this transaction. */ - void register(TransactionCallback callback); + Transaction register(TransactionCallback callback); /** * Set a label on the transaction. @@ -65,7 +65,7 @@ public interface Transaction extends AutoCloseable { * This label is used to group transaction execution times for performance metrics reporting. *

*/ - void setLabel(String label); + Transaction setLabel(String label); /** * Return true if this transaction is read only. @@ -75,7 +75,7 @@ public interface Transaction extends AutoCloseable { /** * Set whether this transaction should be readOnly. */ - void setReadOnly(boolean readOnly); + Transaction setReadOnly(boolean readOnly); /** * Commits the transaction at this point with the expectation that another @@ -139,7 +139,7 @@ public interface Transaction extends AutoCloseable { /** * Mark the transaction for rollback only. */ - void setRollbackOnly(); + Transaction setRollbackOnly(); /** * Return true if the transaction is marked as rollback only. @@ -172,7 +172,7 @@ public interface Transaction extends AutoCloseable { * to control how that is sent to the document store. *

*/ - void setDocStoreMode(DocStoreMode mode); + Transaction setDocStoreMode(DocStoreMode mode); /** * Set the batch size to use for sending messages to the document store. @@ -184,7 +184,7 @@ public interface Transaction extends AutoCloseable { * Setting this overrides the default of {@link DocStoreConfig#getBulkBatchSize()} *

*/ - void setDocStoreBatchSize(int batchSize); + Transaction setDocStoreBatchSize(int batchSize); /** * Explicitly turn off or on the cascading nature of save() and delete(). This @@ -199,7 +199,7 @@ public interface Transaction extends AutoCloseable { * that do not support getGeneratedKeys. *

*/ - void setPersistCascade(boolean persistCascade); + Transaction setPersistCascade(boolean persistCascade); /** * Set to true when you want all loaded properties to be included in the update @@ -210,7 +210,7 @@ public interface Transaction extends AutoCloseable { * and hence better JDBC batch performance. *

*/ - void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties); + Transaction setUpdateAllLoadedProperties(boolean updateAllLoadedProperties); /** * Set if the L2 cache should be skipped for "find by id" and "find by natural key" queries. @@ -269,7 +269,7 @@ public interface Transaction extends AutoCloseable { * * @see ServerConfig#isSkipCacheAfterWrite() */ - void setSkipCache(boolean skipCache); + Transaction setSkipCache(boolean skipCache); /** * Return true if the L2 cache should be skipped. More accurately if true then find by id @@ -344,7 +344,7 @@ public interface Transaction extends AutoCloseable { * * } */ - void setBatchMode(boolean useBatch); + Transaction setBatchMode(boolean useBatch); /** * The JDBC batch mode to use for this transaction. @@ -356,7 +356,7 @@ public interface Transaction extends AutoCloseable { * @param persistBatchMode the batch mode to use for this transaction * @see io.ebean.config.ServerConfig#setPersistBatch(PersistBatch) */ - void setBatch(PersistBatch persistBatchMode); + Transaction setBatch(PersistBatch persistBatchMode); /** * Return the batch mode at the transaction level. @@ -377,7 +377,7 @@ public interface Transaction extends AutoCloseable { * @param batchOnCascadeMode the batch mode to use per save(), insert(), update() or delete() * @see io.ebean.config.ServerConfig#setPersistBatchOnCascade(PersistBatch) */ - void setBatchOnCascade(PersistBatch batchOnCascadeMode); + Transaction setBatchOnCascade(PersistBatch batchOnCascadeMode); /** * Return the batch mode at the request level (for each save(), insert(), update() or delete()). @@ -387,7 +387,7 @@ public interface Transaction extends AutoCloseable { /** * Specify the number of statements before a batch is flushed automatically. */ - void setBatchSize(int batchSize); + Transaction setBatchSize(int batchSize); /** * Return the current batch size. @@ -405,7 +405,7 @@ public interface Transaction extends AutoCloseable { * number of objects and you don't care about getting back the ids. *

*/ - void setBatchGetGeneratedKeys(boolean getGeneratedKeys); + Transaction setBatchGetGeneratedKeys(boolean getGeneratedKeys); /** * By default when mixing UpdateSql (or CallableSql) with Beans the batch is @@ -422,7 +422,7 @@ public interface Transaction extends AutoCloseable { * have a 2 step process (delayed binding). *

*/ - void setBatchFlushOnMixed(boolean batchFlushOnMixed); + Transaction setBatchFlushOnMixed(boolean batchFlushOnMixed); /** * By default executing a query will automatically flush any batched @@ -432,7 +432,7 @@ public interface Transaction extends AutoCloseable { * execute a query and the batch will not be automatically flushed. *

*/ - void setBatchFlushOnQuery(boolean batchFlushOnQuery); + Transaction setBatchFlushOnQuery(boolean batchFlushOnQuery); /** * Return true if the batch (of persisted beans or executed UpdateSql etc) @@ -498,14 +498,14 @@ public interface Transaction extends AutoCloseable { * caches in synch and maintain text indexes. *

*/ - void addModification(String tableName, boolean inserts, boolean updates, boolean deletes); + Transaction addModification(String tableName, boolean inserts, boolean updates, boolean deletes); /** * Add an arbitrary user object to the transaction. The objects added have no * impact on any internals of ebean and are solely meant as a convenient * method push user information (although somewhat replaced by TransactionCallback). */ - void putUserObject(String name, Object value); + Transaction putUserObject(String name, Object value); /** * Get an object added with {@link #putUserObject(String, Object)}. diff --git a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index 9ecd6a3b7..17f4fae57 100644 --- a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -1,5 +1,6 @@ package io.ebeaninternal.api; +import io.ebean.Transaction; import io.ebeaninternal.server.transaction.TransactionScopeManager; import io.ebeaninternal.server.util.ArrayStack; @@ -93,8 +94,9 @@ public class ScopedTransaction extends SpiTransactionProxy { } @Override - public void setRollbackOnly() { + public Transaction setRollbackOnly() { current.setRollbackOnly(); + return this; } /** diff --git a/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java index b9907aa3a..7c7b1e317 100644 --- a/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java +++ b/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java @@ -1,6 +1,7 @@ package io.ebeaninternal.api; import io.ebean.ProfileLocation; +import io.ebean.Transaction; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; import io.ebean.annotation.PersistBatch; @@ -31,8 +32,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setLabel(String label) { + public Transaction setLabel(String label) { transaction.setLabel(label); + return this; } @Override @@ -101,8 +103,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setDocStoreMode(DocStoreMode mode) { + public Transaction setDocStoreMode(DocStoreMode mode) { transaction.setDocStoreMode(mode); + return this; } @Override @@ -111,8 +114,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setDocStoreBatchSize(int batchSize) { + public Transaction setDocStoreBatchSize(int batchSize) { transaction.setDocStoreBatchSize(batchSize); + return this; } @Override @@ -141,8 +145,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setSkipCache(boolean skipCache) { + public Transaction setSkipCache(boolean skipCache) { transaction.setSkipCache(skipCache); + return this; } @Override @@ -196,8 +201,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void register(TransactionCallback callback) { + public Transaction register(TransactionCallback callback) { transaction.register(callback); + return this; } @Override @@ -206,8 +212,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setReadOnly(boolean readOnly) { + public Transaction setReadOnly(boolean readOnly) { transaction.setReadOnly(readOnly); + return this; } @Override @@ -216,13 +223,15 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setPersistCascade(boolean persistCascade) { + public Transaction setPersistCascade(boolean persistCascade) { transaction.setPersistCascade(persistCascade); + return this; } @Override - public void setUpdateAllLoadedProperties(boolean updateAllLoaded) { + public Transaction setUpdateAllLoadedProperties(boolean updateAllLoaded) { transaction.setUpdateAllLoadedProperties(updateAllLoaded); + return this; } @Override @@ -231,13 +240,15 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setBatchMode(boolean useBatch) { + public Transaction setBatchMode(boolean useBatch) { transaction.setBatchMode(useBatch); + return this; } @Override - public void setBatch(PersistBatch persistBatchMode) { + public Transaction setBatch(PersistBatch persistBatchMode) { transaction.setBatch(persistBatchMode); + return this; } @Override @@ -246,8 +257,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setBatchOnCascade(PersistBatch batchOnCascadeMode) { + public Transaction setBatchOnCascade(PersistBatch batchOnCascadeMode) { transaction.setBatchOnCascade(batchOnCascadeMode); + return this; } @Override @@ -256,8 +268,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setBatchSize(int batchSize) { + public Transaction setBatchSize(int batchSize) { transaction.setBatchSize(batchSize); + return this; } @Override @@ -266,8 +279,9 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) { + public Transaction setBatchGetGeneratedKeys(boolean getGeneratedKeys) { transaction.setBatchGetGeneratedKeys(getGeneratedKeys); + return this; } @Override @@ -276,13 +290,15 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void setBatchFlushOnMixed(boolean batchFlushOnMixed) { + public Transaction setBatchFlushOnMixed(boolean batchFlushOnMixed) { transaction.setBatchFlushOnMixed(batchFlushOnMixed); + return this; } @Override - public void setBatchFlushOnQuery(boolean batchFlushOnQuery) { + public Transaction setBatchFlushOnQuery(boolean batchFlushOnQuery) { transaction.setBatchFlushOnQuery(batchFlushOnQuery); + return this; } @Override @@ -306,13 +322,15 @@ abstract class SpiTransactionProxy implements SpiTransaction { } @Override - public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { + public Transaction addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { transaction.addModification(tableName, inserts, updates, deletes); + return this; } @Override - public void putUserObject(String name, Object value) { + public Transaction putUserObject(String name, Object value) { transaction.putUserObject(name, value); + return this; } @Override diff --git a/src/main/java/io/ebeaninternal/server/transaction/DocStoreOnlyTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/DocStoreOnlyTransaction.java index 4bb23735e..dbf1ce00d 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/DocStoreOnlyTransaction.java +++ b/src/main/java/io/ebeaninternal/server/transaction/DocStoreOnlyTransaction.java @@ -1,5 +1,7 @@ package io.ebeaninternal.server.transaction; +import io.ebean.Transaction; + import java.sql.Connection; import java.sql.SQLException; @@ -21,8 +23,9 @@ public class DocStoreOnlyTransaction extends JdbcTransaction { } @Override - public void setReadOnly(boolean readOnly) { + public Transaction setReadOnly(boolean readOnly) { // do nothing + return this; } @Override diff --git a/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java index 0e95880cb..6f39932bc 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java +++ b/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; +import io.ebean.Transaction; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; import io.ebean.annotation.PersistBatch; @@ -85,8 +86,9 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setLabel(String label) { + public Transaction setLabel(String label) { // do nothing + return this; } @Override @@ -130,7 +132,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setSkipCache(boolean skipCache) { + public Transaction setSkipCache(boolean skipCache) { + return this; } @Override @@ -149,7 +152,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void register(TransactionCallback callback) { + public Transaction register(TransactionCallback callback) { throw new IllegalStateException(notExpectedMessage); } @@ -159,7 +162,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setDocStoreBatchSize(int docStoreBatchSize) { + public Transaction setDocStoreBatchSize(int docStoreBatchSize) { throw new IllegalStateException(notExpectedMessage); } @@ -169,7 +172,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setDocStoreMode(DocStoreMode docStoreMode) { + public Transaction setDocStoreMode(DocStoreMode docStoreMode) { throw new IllegalStateException(notExpectedMessage); } @@ -244,19 +247,21 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setReadOnly(boolean readOnly) { + public Transaction setReadOnly(boolean readOnly) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } try { connection.setReadOnly(readOnly); + return this; } catch (SQLException e) { throw new PersistenceException(e); } } @Override - public void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { + public Transaction setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { + return this; } @Override @@ -265,13 +270,13 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setBatchMode(boolean batchMode) { - + public Transaction setBatchMode(boolean batchMode) { + return this; } @Override - public void setBatch(PersistBatch batchMode) { - + public Transaction setBatch(PersistBatch batchMode) { + return this; } @Override @@ -280,7 +285,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setBatchOnCascade(PersistBatch batchOnCascadeMode) { + public Transaction setBatchOnCascade(PersistBatch batchOnCascadeMode) { + return this; } @Override @@ -294,11 +300,13 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) { + public Transaction setBatchGetGeneratedKeys(boolean getGeneratedKeys) { + return this; } @Override - public void setBatchFlushOnMixed(boolean batchFlushOnMixed) { + public Transaction setBatchFlushOnMixed(boolean batchFlushOnMixed) { + return this; } /** @@ -313,7 +321,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setBatchSize(int batchSize) { + public Transaction setBatchSize(int batchSize) { + return this; } @Override @@ -322,7 +331,8 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setBatchFlushOnQuery(boolean batchFlushOnQuery) { + public Transaction setBatchFlushOnQuery(boolean batchFlushOnQuery) { + return this; } /** @@ -536,7 +546,7 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode * Mark the transaction as rollback only. */ @Override - public void setRollbackOnly() { + public Transaction setRollbackOnly() { // expect AutoCommit so we can't really support rollbackOnly throw new IllegalStateException(notExpectedMessage); } @@ -586,11 +596,12 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void setPersistCascade(boolean persistCascade) { + public Transaction setPersistCascade(boolean persistCascade) { + return this; } @Override - public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { + public Transaction addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { throw new IllegalStateException(notExpectedMessage); } @@ -600,11 +611,12 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode } @Override - public void putUserObject(String name, Object value) { + public Transaction putUserObject(String name, Object value) { if (userObjects == null) { userObjects = new HashMap<>(); } userObjects.put(name, value); + return this; } @Override diff --git a/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java index 322f70725..d0b60fea9 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java +++ b/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; +import io.ebean.Transaction; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; import io.ebean.annotation.PersistBatch; @@ -217,8 +218,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setLabel(String label) { + public Transaction setLabel(String label) { this.label = label; + return this; } @Override @@ -288,8 +290,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setSkipCache(boolean skipCache) { + public Transaction setSkipCache(boolean skipCache) { this.skipCache = skipCache; + return this; } @Override @@ -318,11 +321,12 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void register(TransactionCallback callback) { + public Transaction register(TransactionCallback callback) { if (callbackList == null) { callbackList = new ArrayList<>(4); } callbackList.add(callback); + return this; } protected void firePreRollback() { @@ -385,8 +389,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setDocStoreBatchSize(int docStoreBatchSize) { + public Transaction setDocStoreBatchSize(int docStoreBatchSize) { this.docStoreBatchSize = docStoreBatchSize; + return this; } @Override @@ -395,8 +400,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setDocStoreMode(DocStoreMode docStoreMode) { + public Transaction setDocStoreMode(DocStoreMode docStoreMode) { this.docStoreMode = docStoreMode; + return this; } @Override @@ -529,21 +535,23 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setReadOnly(boolean readOnly) { + public Transaction setReadOnly(boolean readOnly) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } try { localReadOnly = readOnly; connection.setReadOnly(readOnly); + return this; } catch (SQLException e) { throw new PersistenceException(e); } } @Override - public void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { + public Transaction setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { this.updateAllLoadedProperties = updateAllLoadedProperties; + return this; } @Override @@ -552,19 +560,21 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setBatchMode(boolean batchMode) { + public Transaction setBatchMode(boolean batchMode) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } this.batchMode = (batchMode) ? PersistBatch.ALL : PersistBatch.NONE; + return this; } @Override - public void setBatch(PersistBatch batchMode) { + public Transaction setBatch(PersistBatch batchMode) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } this.batchMode = batchMode; + return this; } @Override @@ -573,11 +583,12 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setBatchOnCascade(PersistBatch batchOnCascadeMode) { + public Transaction setBatchOnCascade(PersistBatch batchOnCascadeMode) { if (!isActive()) { throw new IllegalStateException(illegalStateMessage); } this.batchOnCascadeMode = batchOnCascadeMode; + return this; } @Override @@ -591,19 +602,21 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) { + public Transaction setBatchGetGeneratedKeys(boolean getGeneratedKeys) { this.batchGetGeneratedKeys = getGeneratedKeys; if (batchControl != null) { batchControl.setGetGeneratedKeys(getGeneratedKeys); } + return this; } @Override - public void setBatchFlushOnMixed(boolean batchFlushOnMixed) { + public Transaction setBatchFlushOnMixed(boolean batchFlushOnMixed) { this.batchFlushOnMixed = batchFlushOnMixed; if (batchControl != null) { batchControl.setBatchFlushOnMixed(batchFlushOnMixed); } + return this; } /** @@ -618,11 +631,12 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setBatchSize(int batchSize) { + public Transaction setBatchSize(int batchSize) { this.batchSize = batchSize; if (batchControl != null) { batchControl.setBatchSize(batchSize); } + return this; } @Override @@ -631,8 +645,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setBatchFlushOnQuery(boolean batchFlushOnQuery) { + public Transaction setBatchFlushOnQuery(boolean batchFlushOnQuery) { this.batchFlushOnQuery = batchFlushOnQuery; + return this; } /** @@ -1113,8 +1128,9 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { * Mark the transaction as rollback only. */ @Override - public void setRollbackOnly() { + public Transaction setRollbackOnly() { this.rollbackOnly = true; + return this; } /** @@ -1182,13 +1198,15 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void setPersistCascade(boolean persistCascade) { + public Transaction setPersistCascade(boolean persistCascade) { this.persistCascade = persistCascade; + return this; } @Override - public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { + public Transaction addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { getEvent().add(tableName, inserts, updates, deletes); + return this; } @Override @@ -1201,11 +1219,12 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes { } @Override - public void putUserObject(String name, Object value) { + public Transaction putUserObject(String name, Object value) { if (userObjects == null) { userObjects = new HashMap<>(); } userObjects.put(name, value); + return this; } @Override diff --git a/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java index 9ee156066..73c6eb930 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java +++ b/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.ProfileLocation; +import io.ebean.Transaction; import io.ebean.TransactionCallback; import io.ebean.annotation.DocStoreMode; import io.ebean.annotation.PersistBatch; @@ -28,8 +29,8 @@ class NoTransaction implements SpiTransaction { static final NoTransaction INSTANCE = new NoTransaction(); @Override - public void setLabel(String label) { - // do nothing + public Transaction setLabel(String label) { + return this; } @Override @@ -150,8 +151,8 @@ class NoTransaction implements SpiTransaction { } @Override - public void register(TransactionCallback callback) { - + public Transaction register(TransactionCallback callback) { + return this; } @Override @@ -160,13 +161,13 @@ class NoTransaction implements SpiTransaction { } @Override - public void setReadOnly(boolean readOnly) { - + public Transaction setReadOnly(boolean readOnly) { + return this; } @Override - public void setRollbackOnly() { - + public Transaction setRollbackOnly() { + return this; } @Override @@ -176,28 +177,28 @@ class NoTransaction implements SpiTransaction { @Override - public void setDocStoreMode(DocStoreMode mode) { - + public Transaction setDocStoreMode(DocStoreMode mode) { + return this; } @Override - public void setDocStoreBatchSize(int batchSize) { - + public Transaction setDocStoreBatchSize(int batchSize) { + return this; } @Override - public void setPersistCascade(boolean persistCascade) { - + public Transaction setPersistCascade(boolean persistCascade) { + return this; } @Override - public void setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { - + public Transaction setUpdateAllLoadedProperties(boolean updateAllLoadedProperties) { + return this; } @Override - public void setSkipCache(boolean skipCache) { - + public Transaction setSkipCache(boolean skipCache) { + return this; } @Override @@ -206,13 +207,13 @@ class NoTransaction implements SpiTransaction { } @Override - public void setBatchMode(boolean useBatch) { - + public Transaction setBatchMode(boolean useBatch) { + return this; } @Override - public void setBatch(PersistBatch persistBatchMode) { - + public Transaction setBatch(PersistBatch persistBatchMode) { + return this; } @Override @@ -221,8 +222,8 @@ class NoTransaction implements SpiTransaction { } @Override - public void setBatchOnCascade(PersistBatch batchOnCascadeMode) { - + public Transaction setBatchOnCascade(PersistBatch batchOnCascadeMode) { + return this; } @Override @@ -231,8 +232,8 @@ class NoTransaction implements SpiTransaction { } @Override - public void setBatchSize(int batchSize) { - + public Transaction setBatchSize(int batchSize) { + return this; } @Override @@ -241,18 +242,18 @@ class NoTransaction implements SpiTransaction { } @Override - public void setBatchGetGeneratedKeys(boolean getGeneratedKeys) { - + public Transaction setBatchGetGeneratedKeys(boolean getGeneratedKeys) { + return this; } @Override - public void setBatchFlushOnMixed(boolean batchFlushOnMixed) { - + public Transaction setBatchFlushOnMixed(boolean batchFlushOnMixed) { + return this; } @Override - public void setBatchFlushOnQuery(boolean batchFlushOnQuery) { - + public Transaction setBatchFlushOnQuery(boolean batchFlushOnQuery) { + return this; } @Override @@ -276,13 +277,13 @@ class NoTransaction implements SpiTransaction { } @Override - public void addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { - + public Transaction addModification(String tableName, boolean inserts, boolean updates, boolean deletes) { + return this; } @Override - public void putUserObject(String name, Object value) { - + public Transaction putUserObject(String name, Object value) { + return this; } @Override diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java index f1618b8d3..d5b5add3f 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java @@ -32,13 +32,13 @@ public class TestBatchInsertFlush extends BaseTestCase { MetaInfoManager metaInfoManager = server.getMetaInfoManager(); metaInfoManager.collectTransactionStatistics(true); - Transaction transaction = server.beginTransaction(); - try { - transaction.setPersistCascade(false); - transaction.setBatchSize(10); - transaction.setBatch(PersistBatch.ALL); - transaction.setLabel("TestBatchInsertFlush.no_cascade"); + Transaction transaction = server.beginTransaction() + .setPersistCascade(false) + .setBatchSize(10) + .setBatch(PersistBatch.ALL) + .setLabel("TestBatchInsertFlush.no_cascade"); + try { LoggedSqlCollector.start(); diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java b/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java index 97b13a649..b49aebc75 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java @@ -3,11 +3,11 @@ package org.tests.batchinsert; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; -import io.ebean.annotation.Transactional; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Transactional; +import org.junit.Test; import org.tests.model.basic.UTDetail; import org.tests.model.basic.UTMaster; -import org.junit.Test; import java.util.ArrayList; import java.util.List; @@ -128,11 +128,12 @@ public class TestBatchInsertSimple extends BaseTestCase { masters.add(createMasterAndDetails(i, 7)); } - Transaction transaction = Ebean.beginTransaction(); + Transaction transaction = Ebean.beginTransaction() + .setBatch(PersistBatch.NONE) + .setBatchOnCascade(PersistBatch.ALL) + .setBatchSize(20); + try { - transaction.setBatch(PersistBatch.NONE); - transaction.setBatchOnCascade(PersistBatch.ALL); - transaction.setBatchSize(20); // escalate based on batchOnCascade value Ebean.saveAll(masters); diff --git a/src/test/java/org/tests/transaction/TestSqlServerBatch.java b/src/test/java/org/tests/transaction/TestSqlServerBatch.java index 6b463236b..38cd60050 100644 --- a/src/test/java/org/tests/transaction/TestSqlServerBatch.java +++ b/src/test/java/org/tests/transaction/TestSqlServerBatch.java @@ -22,10 +22,8 @@ public class TestSqlServerBatch extends BaseTestCase { @Test public void testBasicIdentityBatch() { - Transaction txn = Ebean.beginTransaction(); + Transaction txn = Ebean.beginTransaction().setBatchMode(true).setBatchSize(3); try { - txn.setBatchMode(true); - txn.setBatchSize(3); for (int i = 0; i < 10; i++) { ESimple model = new ESimple(); From 70ccc6588d8f1c3214be6ca8c5b1456d508d43e6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 14:45:16 +1300 Subject: [PATCH 0034/1036] [maven-release-plugin] prepare release ebean-11.10.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index be7fed8e4..3c6cbf87b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.6-SNAPSHOT + 11.10.6 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.10.6 From a1d0fbb19484bcd9f9cd25fc986883bf06a1dd07 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 16 Feb 2018 14:45:29 +1300 Subject: [PATCH 0035/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3c6cbf87b..e60b0ec7e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.6 + 11.10.7-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.10.6 + HEAD From b8aa822a3038260017c356a54ced8baa706122b4 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 19 Feb 2018 04:15:28 +0100 Subject: [PATCH 0036/1036] [utf8mb4-support] limited the size of all indexed string columns, as max key length on mysql/mariadb is 767 bytes (which are <= 191 chars on utf8mb4) (#1264) --- src/test/ddl-review/h2-create.sql | 4 +-- src/test/ddl-review/ms-create.sql | 4 +-- src/test/ddl-review/mysql-create.sql | 4 +-- src/test/ddl-review/ora-create.sql | 4 +-- src/test/ddl-review/pg-create.sql | 4 +-- src/test/java/misc/migration/v1_0/EBasic.java | 30 ++++++++++++------- src/test/java/misc/migration/v1_1/EBasic.java | 9 ++++++ src/test/java/misc/migration/v1_2/EBasic.java | 24 ++++++++++----- .../org/tests/compositekeys/db/ItemKey.java | 6 +++- .../org/tests/model/basic/BWithQIdent.java | 3 ++ .../org/tests/model/basic/CKeyParentId.java | 2 ++ .../java/org/tests/model/basic/Contact.java | 5 ++++ .../java/org/tests/model/basic/EBasic.java | 3 ++ .../model/basic/EBasicWithUniqueCon.java | 7 +++++ .../java/org/tests/model/basic/ECustomId.java | 2 ++ .../java/org/tests/model/basic/TSDetail.java | 2 ++ .../org/tests/model/carwheeltruck/TCar.java | 3 ++ .../tests/model/composite/RCustomerKey.java | 5 ++++ .../org/tests/model/composite/ROrder.java | 2 ++ .../org/tests/model/composite/ROrderPK.java | 5 +++- .../org/tests/model/draftable/Document.java | 2 ++ .../tests/model/orderentity/OrderEntity.java | 3 ++ .../model/orderentity/OrderItemEntity.java | 3 ++ .../java/org/tests/model/pview/Wview.java | 3 ++ .../java/org/tests/update/EPersonOnline.java | 3 ++ .../ModelBuild_compoundKeyTest/apply.sql | 4 +-- src/test/resources/assert/changeset-apply.txt | 4 +-- .../resources/assert/changeset-pg-apply.sql | 4 +-- .../resources/container/test-compoundkey.xml | 4 +-- .../migrationtest/db2/1.0__initial.sql | 16 +++++----- .../migrationtest/h2/1.0__initial.sql | 16 +++++----- .../migrationtest/hsqldb/1.0__initial.sql | 16 +++++----- .../model/1.0__initial.model.xml | 16 +++++----- .../migrationtest/mysql/1.0__initial.sql | 16 +++++----- .../migrationtest/oracle/1.0__initial.sql | 16 +++++----- .../migrationtest/postgres/1.0__initial.sql | 16 +++++----- .../migrationtest/sqlite/1.0__initial.sql | 16 +++++----- .../migrationtest/sqlserver/1.0__initial.sql | 16 +++++----- 38 files changed, 193 insertions(+), 109 deletions(-) diff --git a/src/test/ddl-review/h2-create.sql b/src/test/ddl-review/h2-create.sql index 660744c0c..af29ea19d 100644 --- a/src/test/ddl-review/h2-create.sql +++ b/src/test/ddl-review/h2-create.sql @@ -177,14 +177,14 @@ create table ckey_detail ( id integer not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create sequence ckey_detail_seq; create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/ddl-review/ms-create.sql b/src/test/ddl-review/ms-create.sql index 0ae653fbe..62ac79821 100644 --- a/src/test/ddl-review/ms-create.sql +++ b/src/test/ddl-review/ms-create.sql @@ -158,13 +158,13 @@ create table ckey_detail ( id integer identity(1,1) not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/ddl-review/mysql-create.sql b/src/test/ddl-review/mysql-create.sql index f81a883cd..974b5461d 100644 --- a/src/test/ddl-review/mysql-create.sql +++ b/src/test/ddl-review/mysql-create.sql @@ -158,13 +158,13 @@ create table ckey_detail ( id integer auto_increment not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/ddl-review/ora-create.sql b/src/test/ddl-review/ora-create.sql index f857a9ecf..5dc24914c 100644 --- a/src/test/ddl-review/ora-create.sql +++ b/src/test/ddl-review/ora-create.sql @@ -177,14 +177,14 @@ create table ckey_detail ( id number(10) not null, something varchar2(255), one_key number(10), - two_key varchar2(255), + two_key varchar2(127), constraint pk_ckey_detail primary key (id) ); create sequence ckey_detail_seq; create table ckey_parent ( one_key number(10) not null, - two_key varchar2(255) not null, + two_key varchar2(127) not null, name varchar2(255), assoc_id number(10), version number(10) not null, diff --git a/src/test/ddl-review/pg-create.sql b/src/test/ddl-review/pg-create.sql index 7eb9473f7..4956fd1bb 100644 --- a/src/test/ddl-review/pg-create.sql +++ b/src/test/ddl-review/pg-create.sql @@ -159,13 +159,13 @@ create table ckey_detail ( id serial not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/java/misc/migration/v1_0/EBasic.java b/src/test/java/misc/migration/v1_0/EBasic.java index ebdcceb3f..8c90882ef 100644 --- a/src/test/java/misc/migration/v1_0/EBasic.java +++ b/src/test/java/misc/migration/v1_0/EBasic.java @@ -8,6 +8,8 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.sql.Timestamp; @Entity @@ -29,9 +31,11 @@ public class EBasic { Integer id; Status status; - + + @Size(max=127) String name; + @Size(max=127) String description; Timestamp someDate; @@ -42,28 +46,34 @@ public class EBasic { @ManyToOne ERef eref; - - + + // test add & remove indices @Index + @Size(max=127) String indextest1; - + @Index(unique = true) + @Size(max=127) String indextest2; - + + @Size(max=127) String indextest3; - + + @Size(max=127) String indextest4; - + @Index(unique = false) + @Size(max=127) String indextest5; - + @Index(unique = true) + @Size(max=127) String indextest6; - + @NotNull int user_id; - + public EBasic() { } diff --git a/src/test/java/misc/migration/v1_1/EBasic.java b/src/test/java/misc/migration/v1_1/EBasic.java index f4dc7c990..b11c6f9e2 100644 --- a/src/test/java/misc/migration/v1_1/EBasic.java +++ b/src/test/java/misc/migration/v1_1/EBasic.java @@ -11,6 +11,7 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; import java.sql.Timestamp; @@ -51,11 +52,13 @@ public class EBasic { Status status; @Index(unique = true) + @Size(max=127) String name; @DbMigration(preAlter = "-- rename all collisions") @Column(unique = true) + @Size(max=127) String description; @NotNull @@ -75,20 +78,26 @@ public class EBasic { @DbDefault("true") boolean newBooleanField2; + @Size(max=127) String indextest1; + @Size(max=127) String indextest2; @Index + @Size(max=127) String indextest3; @Index(unique = true) + @Size(max=127) String indextest4; @Index(unique = true) + @Size(max=127) String indextest5; @Index(unique = false) + @Size(max=127) String indextest6; @NotNull diff --git a/src/test/java/misc/migration/v1_2/EBasic.java b/src/test/java/misc/migration/v1_2/EBasic.java index 16f459775..5753cb767 100644 --- a/src/test/java/misc/migration/v1_2/EBasic.java +++ b/src/test/java/misc/migration/v1_2/EBasic.java @@ -9,6 +9,8 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.sql.Timestamp; @Entity @@ -30,9 +32,11 @@ public class EBasic { Integer id; Status status; - + + @Size(max=127) String name; + @Size(max=127) String description; Timestamp someDate; @@ -47,21 +51,27 @@ public class EBasic { // test add & remove indices @Index + @Size(max=127) String indextest1; - + @Index(unique = true) + @Size(max=127) String indextest2; - + + @Size(max=127) String indextest3; - + + @Size(max=127) String indextest4; - + @Index(unique = false) + @Size(max=127) String indextest5; - + @Index(unique = true) + @Size(max=127) String indextest6; - + @NotNull @DbDefault("23") int user_id; diff --git a/src/test/java/org/tests/compositekeys/db/ItemKey.java b/src/test/java/org/tests/compositekeys/db/ItemKey.java index 0f35d91ea..0f4589612 100644 --- a/src/test/java/org/tests/compositekeys/db/ItemKey.java +++ b/src/test/java/org/tests/compositekeys/db/ItemKey.java @@ -2,12 +2,16 @@ package org.tests.compositekeys.db; import javax.persistence.Column; import javax.persistence.Embeddable; +import javax.validation.constraints.Size; + @Embeddable public class ItemKey { + @Size(max=127) private int customer; - @Column(name = "itemNumber") + @Column(name = "itemnumber") + @Size(max=127) private String itemNumber; public int getCustomer() { diff --git a/src/test/java/org/tests/model/basic/BWithQIdent.java b/src/test/java/org/tests/model/basic/BWithQIdent.java index d101c2e0a..329d40f41 100644 --- a/src/test/java/org/tests/model/basic/BWithQIdent.java +++ b/src/test/java/org/tests/model/basic/BWithQIdent.java @@ -4,6 +4,8 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Version; +import javax.validation.constraints.Size; + import java.sql.Timestamp; @Entity @@ -13,6 +15,7 @@ public class BWithQIdent { Integer id; @Column(name = "`Name`", unique = true) + @Size(max = 191) // key must not exceed 767 Bytes, so max key len for mysql with utf8mb4 = 191*4 = 764 bytes String name; @Version diff --git a/src/test/java/org/tests/model/basic/CKeyParentId.java b/src/test/java/org/tests/model/basic/CKeyParentId.java index b57313779..a0d8c828c 100644 --- a/src/test/java/org/tests/model/basic/CKeyParentId.java +++ b/src/test/java/org/tests/model/basic/CKeyParentId.java @@ -1,11 +1,13 @@ package org.tests.model.basic; import javax.persistence.Embeddable; +import javax.validation.constraints.Size; @Embeddable public class CKeyParentId { Integer oneKey; + @Size(max = 127) String twoKey; public CKeyParentId() { diff --git a/src/test/java/org/tests/model/basic/Contact.java b/src/test/java/org/tests/model/basic/Contact.java index e15f572b2..402a4fc2a 100644 --- a/src/test/java/org/tests/model/basic/Contact.java +++ b/src/test/java/org/tests/model/basic/Contact.java @@ -13,6 +13,8 @@ import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Version; +import javax.validation.constraints.Size; + import java.sql.Timestamp; import java.util.List; @@ -26,7 +28,10 @@ public class Contact { @Id int id; + @Size(max=127) String firstName; + + @Size(max=127) String lastName; String phone; diff --git a/src/test/java/org/tests/model/basic/EBasic.java b/src/test/java/org/tests/model/basic/EBasic.java index 5b67551f8..278328f92 100644 --- a/src/test/java/org/tests/model/basic/EBasic.java +++ b/src/test/java/org/tests/model/basic/EBasic.java @@ -6,6 +6,8 @@ import io.ebean.annotation.Index; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.sql.Timestamp; @Entity @@ -29,6 +31,7 @@ public class EBasic { Status status; @Index + @Size(max=127) String name; String description; diff --git a/src/test/java/org/tests/model/basic/EBasicWithUniqueCon.java b/src/test/java/org/tests/model/basic/EBasicWithUniqueCon.java index 63c09d4de..4766414dc 100644 --- a/src/test/java/org/tests/model/basic/EBasicWithUniqueCon.java +++ b/src/test/java/org/tests/model/basic/EBasicWithUniqueCon.java @@ -6,6 +6,8 @@ import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.UniqueConstraint; import javax.persistence.Version; +import javax.validation.constraints.Size; + import java.sql.Timestamp; @Entity @@ -17,10 +19,15 @@ public class EBasicWithUniqueCon { Integer id; @Column(unique = true) + @Size(max=127) String name; + @Size(max=127) String other; + + @Size(max=127) String otherOne; + String description; @Version diff --git a/src/test/java/org/tests/model/basic/ECustomId.java b/src/test/java/org/tests/model/basic/ECustomId.java index fc6c94d2c..0655ac781 100644 --- a/src/test/java/org/tests/model/basic/ECustomId.java +++ b/src/test/java/org/tests/model/basic/ECustomId.java @@ -3,12 +3,14 @@ package org.tests.model.basic; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.validation.constraints.Size; @Entity public class ECustomId { @Id @GeneratedValue(generator = "shortUid") + @Size(max=127) String id; String name; diff --git a/src/test/java/org/tests/model/basic/TSDetail.java b/src/test/java/org/tests/model/basic/TSDetail.java index b89ec11f4..cca4584cc 100644 --- a/src/test/java/org/tests/model/basic/TSDetail.java +++ b/src/test/java/org/tests/model/basic/TSDetail.java @@ -8,6 +8,7 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; /** * A basic entity to test simple things. @@ -26,6 +27,7 @@ public class TSDetail { String description; @Index(unique = true) + @Size(max=127) String someUniqueValue; boolean active; diff --git a/src/test/java/org/tests/model/carwheeltruck/TCar.java b/src/test/java/org/tests/model/carwheeltruck/TCar.java index 5274259a2..1a8aa356c 100644 --- a/src/test/java/org/tests/model/carwheeltruck/TCar.java +++ b/src/test/java/org/tests/model/carwheeltruck/TCar.java @@ -8,6 +8,8 @@ import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.OneToMany; +import javax.validation.constraints.Size; + import java.util.List; @Entity @@ -17,6 +19,7 @@ import java.util.List; public class TCar { @Id + @Size(max=32) String plateNo; @OneToMany(cascade = CascadeType.ALL) diff --git a/src/test/java/org/tests/model/composite/RCustomerKey.java b/src/test/java/org/tests/model/composite/RCustomerKey.java index 881d01674..a871d49aa 100644 --- a/src/test/java/org/tests/model/composite/RCustomerKey.java +++ b/src/test/java/org/tests/model/composite/RCustomerKey.java @@ -2,10 +2,15 @@ package org.tests.model.composite; import javax.persistence.Embeddable; +import javax.validation.constraints.Size; @Embeddable public class RCustomerKey { + + @Size(max=127) private String company; + + @Size(max=127) private String name; public RCustomerKey() { diff --git a/src/test/java/org/tests/model/composite/ROrder.java b/src/test/java/org/tests/model/composite/ROrder.java index 56b8639df..14fd2d9c9 100644 --- a/src/test/java/org/tests/model/composite/ROrder.java +++ b/src/test/java/org/tests/model/composite/ROrder.java @@ -8,6 +8,7 @@ import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; /** @@ -28,6 +29,7 @@ public class ROrder { private RCustomer customer; @Column(name = "customerName") + @Size(max=127) private String customerName; private String item; diff --git a/src/test/java/org/tests/model/composite/ROrderPK.java b/src/test/java/org/tests/model/composite/ROrderPK.java index 72962acff..2c808d82b 100644 --- a/src/test/java/org/tests/model/composite/ROrderPK.java +++ b/src/test/java/org/tests/model/composite/ROrderPK.java @@ -4,6 +4,7 @@ package org.tests.model.composite; import java.io.Serializable; import javax.persistence.Embeddable; +import javax.validation.constraints.Size; /** * @author rnentjes @@ -12,8 +13,10 @@ import javax.persistence.Embeddable; public class ROrderPK implements Serializable { private static final long serialVersionUID = 7632735517186104883L; - + @Size(max=127) private String company; + + @Size(max=127) private Integer orderNumber; public ROrderPK() { diff --git a/src/test/java/org/tests/model/draftable/Document.java b/src/test/java/org/tests/model/draftable/Document.java index acfff0ff6..5340ee4fe 100644 --- a/src/test/java/org/tests/model/draftable/Document.java +++ b/src/test/java/org/tests/model/draftable/Document.java @@ -8,6 +8,7 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.validation.constraints.Size; import java.sql.Timestamp; import java.util.List; @@ -19,6 +20,7 @@ public class Document extends BaseDomain { public static DocumentFinder find = new DocumentFinder(); @Column(unique = true) + @Size(max=127) String title; String body; diff --git a/src/test/java/org/tests/model/orderentity/OrderEntity.java b/src/test/java/org/tests/model/orderentity/OrderEntity.java index 6b2acd451..2a1e032dc 100644 --- a/src/test/java/org/tests/model/orderentity/OrderEntity.java +++ b/src/test/java/org/tests/model/orderentity/OrderEntity.java @@ -7,6 +7,8 @@ import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.util.List; @Entity @@ -19,6 +21,7 @@ public class OrderEntity { */ @Id @Column(name = "uuid") + @Size(max=40) private String id; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "order") diff --git a/src/test/java/org/tests/model/orderentity/OrderItemEntity.java b/src/test/java/org/tests/model/orderentity/OrderItemEntity.java index 024be3cc6..d1d40961c 100644 --- a/src/test/java/org/tests/model/orderentity/OrderItemEntity.java +++ b/src/test/java/org/tests/model/orderentity/OrderItemEntity.java @@ -6,6 +6,8 @@ import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.math.BigDecimal; @Entity @@ -18,6 +20,7 @@ public class OrderItemEntity { */ @Id @Column(name = "uuid") + @Size(max=40) private String id; @Column(name = "product_variant_uuid") diff --git a/src/test/java/org/tests/model/pview/Wview.java b/src/test/java/org/tests/model/pview/Wview.java index f88c65d19..364b73bf0 100644 --- a/src/test/java/org/tests/model/pview/Wview.java +++ b/src/test/java/org/tests/model/pview/Wview.java @@ -5,6 +5,8 @@ import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.util.UUID; @Entity @@ -17,6 +19,7 @@ public class Wview { @Basic(optional = false) @Column(unique = true) + @Size(max=127) private String name; public UUID getId() { diff --git a/src/test/java/org/tests/update/EPersonOnline.java b/src/test/java/org/tests/update/EPersonOnline.java index f9a3e3e04..7b1f2bb88 100644 --- a/src/test/java/org/tests/update/EPersonOnline.java +++ b/src/test/java/org/tests/update/EPersonOnline.java @@ -6,6 +6,8 @@ import io.ebean.annotation.WhenModified; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; +import javax.validation.constraints.Size; + import java.time.Instant; @Entity @@ -16,6 +18,7 @@ public class EPersonOnline { Long id; @Index(unique = true) + @Size(max=127) String email; boolean online; diff --git a/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql b/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql index 6c5a6587c..e0789ab8a 100644 --- a/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql +++ b/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql @@ -8,13 +8,13 @@ create table ckey_detail ( id integer auto_increment not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/resources/assert/changeset-apply.txt b/src/test/resources/assert/changeset-apply.txt index 46bf5c1b1..16d68bacc 100644 --- a/src/test/resources/assert/changeset-apply.txt +++ b/src/test/resources/assert/changeset-apply.txt @@ -177,14 +177,14 @@ create table ckey_detail ( id integer not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create sequence ckey_detail_seq; create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/resources/assert/changeset-pg-apply.sql b/src/test/resources/assert/changeset-pg-apply.sql index ec2f0f3f0..c995e7c84 100644 --- a/src/test/resources/assert/changeset-pg-apply.sql +++ b/src/test/resources/assert/changeset-pg-apply.sql @@ -158,13 +158,13 @@ create table ckey_detail ( id serial not null, something varchar(255), one_key integer, - two_key varchar(255), + two_key varchar(127), constraint pk_ckey_detail primary key (id) ); create table ckey_parent ( one_key integer not null, - two_key varchar(255) not null, + two_key varchar(127) not null, name varchar(255), assoc_id integer, version integer not null, diff --git a/src/test/resources/container/test-compoundkey.xml b/src/test/resources/container/test-compoundkey.xml index a38205d98..20955a77a 100644 --- a/src/test/resources/container/test-compoundkey.xml +++ b/src/test/resources/container/test-compoundkey.xml @@ -13,13 +13,13 @@ - + - + diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql index 8cb33ca98..ac49b8e02 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer generated by default as identity not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date timestamp, old_boolean boolean default false not null, old_boolean2 boolean, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql index 92ce9e535..60dc196b2 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer auto_increment not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date timestamp, old_boolean boolean default false not null, old_boolean2 boolean, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql index 98a8aefd4..b5ba4b578 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer generated by default as identity (start with 1) not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date timestamp, old_boolean boolean default false not null, old_boolean2 boolean, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml index a01d7db52..e489d342c 100644 --- a/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml +++ b/src/test/resources/dbmigration/migrationtest/model/1.0__initial.model.xml @@ -5,18 +5,18 @@ - - + + - - - - - - + + + + + + diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql index 8fe02c94c..d0cd55dbd 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer auto_increment not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date datetime(6), old_boolean tinyint(1) default 0 not null, old_boolean2 tinyint(1) default 0, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql index 439cc5a00..9cb945a13 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id number(10) not null, status varchar2(1), - name varchar2(255), - description varchar2(255), + name varchar2(127), + description varchar2(127), some_date timestamp, old_boolean number(1) default 0 not null, old_boolean2 number(1) default 0, eref_id number(10), - indextest1 varchar2(255), - indextest2 varchar2(255), - indextest3 varchar2(255), - indextest4 varchar2(255), - indextest5 varchar2(255), - indextest6 varchar2(255), + indextest1 varchar2(127), + indextest2 varchar2(127), + indextest3 varchar2(127), + indextest4 varchar2(127), + indextest5 varchar2(127), + indextest6 varchar2(127), user_id number(10) not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql index 372bcf4ba..09be87a42 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id serial not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date timestamptz, old_boolean boolean default false not null, old_boolean2 boolean, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql index 88d329a2b..fb9e4c859 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date timestamp, old_boolean int default 0 not null, old_boolean2 int default 0, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint uq_migtest_e_basic_indextest2 unique (indextest2), diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql index 39fff72cf..7c8eb6b47 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql @@ -2,18 +2,18 @@ create table migtest_e_basic ( id integer identity(1,1) not null, status varchar(1), - name varchar(255), - description varchar(255), + name varchar(127), + description varchar(127), some_date datetime2, old_boolean bit default 0 not null, old_boolean2 bit default 0, eref_id integer, - indextest1 varchar(255), - indextest2 varchar(255), - indextest3 varchar(255), - indextest4 varchar(255), - indextest5 varchar(255), - indextest6 varchar(255), + indextest1 varchar(127), + indextest2 varchar(127), + indextest3 varchar(127), + indextest4 varchar(127), + indextest5 varchar(127), + indextest6 varchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) From 40634412f5c43340a1af17bc8afdb3c789ee45b5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 19 Feb 2018 22:24:37 +1300 Subject: [PATCH 0037/1036] #323 - DDL Generation support for foreign key cascade options --- .../ddlgeneration/platform/BaseTableDdl.java | 84 +++------------ .../ddlgeneration/platform/Oracle10Ddl.java | 18 +++- .../ddlgeneration/platform/PlatformDdl.java | 63 ++++++++--- .../ddlgeneration/platform/SQLiteDdl.java | 8 +- .../ddlgeneration/platform/SplitColumns.java | 12 +++ .../ddlgeneration/platform/SqlServerDdl.java | 9 +- .../platform/WriteForeignKey.java | 100 ++++++++++++++++++ .../dbmigration/migration/AlterColumn.java | 51 ++++++++- .../dbmigration/migration/Column.java | 51 ++++++++- .../dbmigration/migration/ForeignKey.java | 47 +++++++- .../dbmigration/model/MColumn.java | 28 ++++- .../build/ModelBuildPropertyVisitor.java | 26 +++-- .../server/deploy/BeanDescriptorManager.java | 15 ++- .../server/deploy/BeanPropertyAssocOne.java | 15 +++ .../server/deploy/PropertyForeignKey.java | 35 ++++++ .../meta/DeployBeanPropertyAssocOne.java | 12 +++ .../deploy/parse/AnnotationAssocOnes.java | 7 ++ src/main/resources/ebean-dbmigration-1.0.xsd | 6 ++ .../platform/Oracle10DdlTest.java | 54 ++++++++++ .../org/tests/cascade/TestOrderedList.java | 7 +- src/test/java/org/tests/ddl/DfkCascade.java | 50 +++++++++ .../java/org/tests/ddl/DfkCascadeOne.java | 47 ++++++++ src/test/java/org/tests/ddl/DfkNone.java | 49 +++++++++ src/test/java/org/tests/ddl/DfkOne.java | 33 ++++++ src/test/java/org/tests/ddl/DfkSetNull.java | 50 +++++++++ .../org/tests/ddl/TestForeignKeyModes.java | 77 ++++++++++++++ .../onetoone/TestOneToOnePrimaryKeyJoin.java | 4 +- .../TestOneToOnePrimaryKeyJoinBidi.java | 4 +- .../TestOneToOnePrimaryKeyJoinOptional.java | 4 +- .../java/org/tests/update/EPersonOnline.java | 11 +- .../org/tests/update/TestSqlUpdateUpsert.java | 24 ++--- 31 files changed, 868 insertions(+), 133 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SplitColumns.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteForeignKey.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java create mode 100644 src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10DdlTest.java create mode 100644 src/test/java/org/tests/ddl/DfkCascade.java create mode 100644 src/test/java/org/tests/ddl/DfkCascadeOne.java create mode 100644 src/test/java/org/tests/ddl/DfkNone.java create mode 100644 src/test/java/org/tests/ddl/DfkOne.java create mode 100644 src/test/java/org/tests/ddl/DfkSetNull.java create mode 100644 src/test/java/org/tests/ddl/TestForeignKeyModes.java diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 80da05f97..8969e7c7d 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -389,14 +389,7 @@ public class BaseTableDdl implements TableDdl { protected void writeInlineForeignKey(DdlWrite write, Column column) throws IOException { - String references = column.getReferences(); - int pos = references.lastIndexOf('.'); - if (pos == -1) { - throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]"); - } - String refTableName = references.substring(0, pos); - String refColumnName = references.substring(pos + 1); - String fkConstraint = platformDdl.tableInlineForeignKey(new String[]{column.getName()}, refTableName, new String[]{refColumnName}); + String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, column)); write.apply().append(",").newLine().append(" ").append(fkConstraint); } @@ -404,11 +397,7 @@ public class BaseTableDdl implements TableDdl { List foreignKey = createTable.getForeignKey(); for (ForeignKey key : foreignKey) { - String refTableName = key.getRefTableName(); - String[] cols = toColumnNamesSplit(key.getColumnNames()); - String[] refColumns = toColumnNamesSplit(key.getRefColumnNames()); - - String fkConstraint = platformDdl.tableInlineForeignKey(cols, refTableName, refColumns); + String fkConstraint = platformDdl.tableInlineForeignKey(new WriteForeignKey(null, key)); write.apply().append(",").newLine().append(" ").append(fkConstraint); } } @@ -433,61 +422,42 @@ public class BaseTableDdl implements TableDdl { List foreignKey = createTable.getForeignKey(); for (ForeignKey key : foreignKey) { - - String refTableName = key.getRefTableName(); - String fkName = key.getName(); - String[] cols = toColumnNamesSplit(key.getColumnNames()); - String[] refColumns = toColumnNamesSplit(key.getRefColumnNames()); - - writeForeignKey(write, fkName, tableName, cols, refTableName, refColumns, key.getIndexName()); + writeForeignKey(write, new WriteForeignKey(tableName, key)); } } protected void writeForeignKey(DdlWrite write, String tableName, Column column) throws IOException { - - String fkName = column.getForeignKeyName(); - String references = column.getReferences(); - int pos = references.lastIndexOf('.'); - if (pos == -1) { - throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]"); - } - String refTableName = references.substring(0, pos); - String refColumnName = references.substring(pos + 1); - - String[] cols = {column.getName()}; - String[] refCols = {refColumnName}; - - writeForeignKey(write, fkName, tableName, cols, refTableName, refCols, column.getForeignKeyIndex()); + writeForeignKey(write, new WriteForeignKey(tableName, column)); } - protected void writeForeignKey(DdlWrite write, String fkName, String tableName, String[] columns, String refTable, String[] refColumns, String indexName) throws IOException { + protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException { - tableName = lowerTableName(tableName); + String tableName = lowerTableName(request.table()); DdlBuffer fkeyBuffer = write.applyForeignKeys(); - alterTableAddForeignKey(fkeyBuffer, fkName, tableName, columns, refTable, refColumns); + alterTableAddForeignKey(fkeyBuffer, request); - if (indexName != null) { + if (request.indexName() != null) { // no matching unique constraint so add the index - fkeyBuffer.append(platformDdl.createIndex(indexName, tableName, columns)).endOfStatement(); + fkeyBuffer.append(platformDdl.createIndex(request.indexName(), tableName, request.cols())).endOfStatement(); } fkeyBuffer.end(); write.dropAllForeignKeys() - .append(platformDdl.alterTableDropForeignKey(tableName, fkName)).endOfStatement(); + .append(platformDdl.alterTableDropForeignKey(tableName, request.fkName())).endOfStatement(); - if (indexName != null) { + if (request.indexName() != null) { write.dropAllForeignKeys() - .append(platformDdl.dropIndex(indexName, tableName)).endOfStatement(); + .append(platformDdl.dropIndex(request.indexName(), tableName)).endOfStatement(); } write.dropAllForeignKeys().end(); } - protected void alterTableAddForeignKey(DdlBuffer buffer, String fkName, String tableName, String[] columns, String refTable, String[] refColumns) throws IOException { + protected void alterTableAddForeignKey(DdlBuffer buffer, WriteForeignKey request) throws IOException { - String fkConstraint = platformDdl.alterTableAddForeignKey(tableName, fkName, columns, refTable, refColumns); + String fkConstraint = platformDdl.alterTableAddForeignKey(request); if (fkConstraint != null && !fkConstraint.isEmpty()) { buffer.append(fkConstraint).endOfStatement(); } @@ -554,7 +524,7 @@ public class BaseTableDdl implements TableDdl { for (UniqueConstraint uniqueConstraint : uniqueConstraints) { if (inlineUniqueWhenNull) { String uqName = uniqueConstraint.getName(); - String[] columns = toColumnNamesSplit(uniqueConstraint.getColumnNames()); + String[] columns = SplitColumns.split(uniqueConstraint.getColumnNames()); apply.append(",").newLine(); apply.append(" constraint ").append(uqName).append(" unique"); appendColumns(columns, apply); @@ -625,13 +595,6 @@ public class BaseTableDdl implements TableDdl { return cols; } - /** - * Return as an array of string column names. - */ - protected String[] toColumnNamesSplit(String columns) { - return columns.split(","); - } - /** * Convert the table lower case. */ @@ -662,7 +625,7 @@ public class BaseTableDdl implements TableDdl { @Override public void generate(DdlWrite writer, CreateIndex createIndex) throws IOException { - String[] cols = toColumnNamesSplit(createIndex.getColumns()); + String[] cols = SplitColumns.split(createIndex.getColumns()); writer.apply() .append(platformDdl.createIndex(createIndex.getIndexName(), createIndex.getTableName(), cols)) .endOfStatement(); @@ -931,22 +894,9 @@ public class BaseTableDdl implements TableDdl { } } - protected void alterColumnAddForeignKey(DdlWrite writer, AlterColumn alterColumn) throws IOException { - String tableName = alterColumn.getTableName(); - String fkName = alterColumn.getForeignKeyName(); - String[] cols = {alterColumn.getColumnName()}; - String references = alterColumn.getReferences(); - int pos = references.lastIndexOf('.'); - if (pos == -1) { - throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]"); - } - String refTableName = references.substring(0, pos); - String refColumnName = references.substring(pos + 1); - String[] refCols = {refColumnName}; - - alterTableAddForeignKey(writer.apply(), fkName, tableName, cols, refTableName, refCols); + alterTableAddForeignKey(writer.apply(), new WriteForeignKey(alterColumn)); } protected void alterColumnDropForeignKey(DdlWrite writer, AlterColumn alter) throws IOException { diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10Ddl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10Ddl.java index 2e4ae9b9c..2071a94e2 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10Ddl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10Ddl.java @@ -1,5 +1,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; +import io.ebean.annotation.ConstraintMode; import io.ebean.config.dbplatform.DatabasePlatform; /** @@ -14,7 +15,6 @@ public class Oracle10Ddl extends PlatformDdl { this.dropConstraintIfExists = "drop constraint"; this.dropIndexIfExists = "drop index "; this.dropTableCascade = " cascade constraints purge"; - this.foreignKeyRestrict = ""; this.alterColumn = "modify"; this.columnSetNotnull = "not null"; this.columnSetNull = "null"; @@ -22,4 +22,20 @@ public class Oracle10Ddl extends PlatformDdl { this.identitySuffix = " generated always as identity"; } + @Override + protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { + // do nothing, no on update clause for oracle + } + + @Override + protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) { + switch (mode) { + case SET_NULL: + case CASCADE: + super.appendForeignKeyMode(buffer, onMode, mode); + default: + // do nothing, defaults to RESTRICT effectively + } + } + } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index c870608f2..3088e49c1 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -1,11 +1,13 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; +import io.ebean.annotation.ConstraintMode; import io.ebean.config.DbConstraintNaming; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbDefaultValue; import io.ebean.config.dbplatform.DbIdentity; import io.ebean.config.dbplatform.IdType; +import io.ebean.util.StringHelper; import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler; import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; @@ -17,7 +19,6 @@ import io.ebeaninternal.dbmigration.migration.Column; import io.ebeaninternal.dbmigration.migration.DropHistoryTable; import io.ebeaninternal.dbmigration.migration.IdentityType; import io.ebeaninternal.dbmigration.model.MTable; -import io.ebean.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,7 +63,8 @@ public class PlatformDdl { */ protected String dropSequenceIfExists = "drop sequence if exists "; - protected String foreignKeyRestrict = "on delete restrict on update restrict"; + protected String foreignKeyOnDelete = "on delete"; + protected String foreignKeyOnUpdate = "on update"; protected String identitySuffix = " auto_increment"; @@ -351,37 +353,68 @@ public class PlatformDdl { /** * Return the foreign key constraint when used inline with create table. */ - public String tableInlineForeignKey(String[] columns, String refTable, String[] refColumns) { + public String tableInlineForeignKey(WriteForeignKey request) { StringBuilder buffer = new StringBuilder(90); buffer.append("foreign key"); - appendColumns(columns, buffer); - buffer.append(" references ").append(lowerTableName(refTable)); - appendColumns(refColumns, buffer); - appendWithSpace(foreignKeyRestrict, buffer); + appendColumns(request.cols(), buffer); + buffer.append(" references ").append(lowerTableName(request.refTable())); + appendColumns(request.refCols(), buffer); + appendForeignKeySuffix(request, buffer); return buffer.toString(); } /** * Add foreign key. */ - public String alterTableAddForeignKey(String tableName, String fkName, String[] columns, String refTable, String[] refColumns) { + public String alterTableAddForeignKey(WriteForeignKey request) { StringBuilder buffer = new StringBuilder(90); buffer - .append("alter table ").append(tableName) - .append(" add constraint ").append(fkName) + .append("alter table ").append(lowerTableName(request.table())) + .append(" add constraint ").append(request.fkName()) .append(" foreign key"); - appendColumns(columns, buffer); + appendColumns(request.cols(), buffer); buffer .append(" references ") - .append(lowerTableName(refTable)); - appendColumns(refColumns, buffer); - appendWithSpace(foreignKeyRestrict, buffer); - + .append(lowerTableName(request.refTable())); + appendColumns(request.refCols(), buffer); + appendForeignKeySuffix(request, buffer); return buffer.toString(); } + protected void appendForeignKeySuffix(WriteForeignKey request, StringBuilder buffer) { + appendForeignKeyOnDelete(buffer, withDefault(request.onDelete())); + appendForeignKeyOnUpdate(buffer, withDefault(request.onDelete())); + } + + protected ConstraintMode withDefault(ConstraintMode mode) { + return (mode == null || mode == ConstraintMode.GLOBAL_DEFAULT) ? ConstraintMode.RESTRICT : mode; + } + + protected void appendForeignKeyOnDelete(StringBuilder buffer, ConstraintMode mode) { + appendForeignKeyMode(buffer, foreignKeyOnDelete, mode); + } + + protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { + appendForeignKeyMode(buffer, foreignKeyOnUpdate, mode); + } + + protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) { + buffer.append(" ").append(onMode).append(" ").append(translate(mode)); + } + + protected String translate(ConstraintMode mode) { + switch(mode) { + case SET_NULL: return "set null"; + case SET_DEFAULT: return "set default"; + case RESTRICT: return "restrict"; + case CASCADE: return "cascade"; + default: + throw new IllegalStateException("Unknown mode "+mode); + } + } + /** * Drop a unique constraint from the table (Sometimes this is an index). */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SQLiteDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SQLiteDdl.java index 0f555d097..bd2b41830 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SQLiteDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SQLiteDdl.java @@ -3,8 +3,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; -import java.io.IOException; - /** * DB2 platform specific DDL. */ @@ -17,17 +15,17 @@ public class SQLiteDdl extends PlatformDdl { } @Override - public void addTableComment(DdlBuffer apply, String tableName, String tableComment) throws IOException { + public void addTableComment(DdlBuffer apply, String tableName, String tableComment) { // not supported } @Override - public void addColumnComment(DdlBuffer apply, String table, String column, String comment) throws IOException { + public void addColumnComment(DdlBuffer apply, String table, String column, String comment) { // not supported } @Override - public String alterTableAddForeignKey(String tableName, String fkName, String[] columns, String refTable, String[] refColumns) { + public String alterTableAddForeignKey(WriteForeignKey request) { // not supported return null; } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SplitColumns.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SplitColumns.java new file mode 100644 index 000000000..a1c83c4e2 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SplitColumns.java @@ -0,0 +1,12 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +public class SplitColumns { + + /** + * Return as an array of string column names. + */ + public static String[] split(String columns) { + return columns.split(","); + } + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java index 5fd7d9175..16b541d88 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java @@ -1,5 +1,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; +import io.ebean.annotation.ConstraintMode; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; import io.ebeaninternal.dbmigration.migration.AlterColumn; @@ -14,7 +15,6 @@ public class SqlServerDdl extends PlatformDdl { public SqlServerDdl(DatabasePlatform platform) { super(platform); this.identitySuffix = " identity(1,1)"; - this.foreignKeyRestrict = ""; this.alterTableIfExists = ""; this.addColumn = "add"; this.inlineUniqueWhenNullable = false; @@ -23,6 +23,13 @@ public class SqlServerDdl extends PlatformDdl { this.historyDdl = new SqlServerHistoryDdl(); } + @Override + protected void appendForeignKeyMode(StringBuilder buffer, String onMode, ConstraintMode mode) { + if (mode != ConstraintMode.RESTRICT) { + super.appendForeignKeyMode(buffer, onMode, mode); + } + } + @Override public String dropTable(String tableName) { StringBuilder buffer = new StringBuilder(); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteForeignKey.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteForeignKey.java new file mode 100644 index 000000000..f9fab239d --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteForeignKey.java @@ -0,0 +1,100 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.annotation.ConstraintMode; +import io.ebeaninternal.dbmigration.migration.AlterColumn; +import io.ebeaninternal.dbmigration.migration.Column; +import io.ebeaninternal.dbmigration.migration.ForeignKey; + +class WriteForeignKey { + + private final String fkName; + private final String tableName; + private final String[] cols; + private String refTableName; + private String[] refCols; + private final String indexName; + private final ConstraintMode onDelete; + private final ConstraintMode onUpdate; + + WriteForeignKey(AlterColumn alterColumn) { + this.tableName = alterColumn.getTableName(); + this.indexName = alterColumn.getForeignKeyIndex(); + this.fkName = alterColumn.getForeignKeyName(); + this.cols = new String[]{alterColumn.getColumnName()}; + setReferences(alterColumn.getReferences()); + this.onDelete = modeOf(alterColumn.getForeignKeyOnDelete()); + this.onUpdate = modeOf(alterColumn.getForeignKeyOnUpdate()); + } + + WriteForeignKey(String tableName, ForeignKey key) { + this.tableName = tableName; + this.indexName = key.getIndexName(); + this.fkName = key.getName(); + this.cols = toCols(key.getColumnNames()); + this.refTableName = key.getRefTableName(); + this.refCols = toCols(key.getRefColumnNames()); + this.onDelete = modeOf(key.getOnDelete()); + this.onUpdate = modeOf(key.getOnUpdate()); + } + + WriteForeignKey(String tableName, Column column) { + this.tableName = tableName; + this.indexName = column.getForeignKeyIndex(); + this.fkName = column.getForeignKeyName(); + this.cols = new String[]{column.getName()}; + setReferences(column.getReferences()); + this.onDelete = modeOf(column.getForeignKeyOnDelete()); + this.onUpdate = modeOf(column.getForeignKeyOnUpdate()); + } + + private void setReferences(String references) { + int pos = references.lastIndexOf('.'); + if (pos == -1) { + throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]"); + } + this.refTableName = references.substring(0, pos); + String refColumnName = references.substring(pos + 1); + this.refCols = new String[]{refColumnName}; + } + + private String[] toCols(String columns) { + return SplitColumns.split(columns); + } + + private ConstraintMode modeOf(String value) { + return (value == null) ? null : ConstraintMode.valueOf(value); + } + + public String table() { + return tableName; + } + + public String[] cols() { + return cols; + } + + public String indexName() { + return indexName; + } + + public String fkName() { + return fkName; + } + + public String refTable() { + return refTableName; + } + + public String[] refCols() { + return refCols; + } + + public ConstraintMode onDelete() { + return onDelete; + } + + public ConstraintMode onUpdate() { + return onUpdate; + } + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/AlterColumn.java b/src/main/java/io/ebeaninternal/dbmigration/migration/AlterColumn.java index 4e2ab2b02..47f9a413b 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/migration/AlterColumn.java +++ b/src/main/java/io/ebeaninternal/dbmigration/migration/AlterColumn.java @@ -1,14 +1,13 @@ package io.ebeaninternal.dbmigration.migration; -import java.util.ArrayList; -import java.util.List; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; /** @@ -40,6 +39,8 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="references" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="foreignKeyName" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="foreignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyOnDelete" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyOnUpdate" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="dropForeignKey" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="dropForeignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> @@ -99,6 +100,10 @@ public class AlterColumn { protected String foreignKeyName; @XmlAttribute(name = "foreignKeyIndex") protected String foreignKeyIndex; + @XmlAttribute(name = "foreignKeyOnDelete") + protected String foreignKeyOnDelete; + @XmlAttribute(name = "foreignKeyOnUpdate") + protected String foreignKeyOnUpdate; @XmlAttribute(name = "dropForeignKey") protected String dropForeignKey; @XmlAttribute(name = "dropForeignKeyIndex") @@ -504,6 +509,46 @@ public class AlterColumn { this.foreignKeyIndex = value; } + /** + * Gets the value of the foreignKeyOnDelete property. + * + * @return possible object is + * {@link String } + */ + public String getForeignKeyOnDelete() { + return foreignKeyOnDelete; + } + + /** + * Sets the value of the foreignKeyOnDelete property. + * + * @param value allowed object is + * {@link String } + */ + public void setForeignKeyOnDelete(String value) { + this.foreignKeyOnDelete = value; + } + + /** + * Gets the value of the foreignKeyOnUpdate property. + * + * @return possible object is + * {@link String } + */ + public String getForeignKeyOnUpdate() { + return foreignKeyOnUpdate; + } + + /** + * Sets the value of the foreignKeyOnUpdate property. + * + * @param value allowed object is + * {@link String } + */ + public void setForeignKeyOnUpdate(String value) { + this.foreignKeyOnUpdate = value; + } + /** * Gets the value of the dropForeignKey property. * diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/Column.java b/src/main/java/io/ebeaninternal/dbmigration/migration/Column.java index a2385b2a9..0aefdfbc8 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/migration/Column.java +++ b/src/main/java/io/ebeaninternal/dbmigration/migration/Column.java @@ -1,14 +1,13 @@ package io.ebeaninternal.dbmigration.migration; -import java.util.ArrayList; -import java.util.List; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; /** @@ -34,6 +33,8 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="references" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="foreignKeyName" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="foreignKeyIndex" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyOnDelete" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="foreignKeyOnUpdate" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="comment" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> @@ -80,6 +81,10 @@ public class Column { protected String foreignKeyName; @XmlAttribute(name = "foreignKeyIndex") protected String foreignKeyIndex; + @XmlAttribute(name = "foreignKeyOnDelete") + protected String foreignKeyOnDelete; + @XmlAttribute(name = "foreignKeyOnUpdate") + protected String foreignKeyOnUpdate; @XmlAttribute(name = "comment") protected String comment; @@ -378,6 +383,46 @@ public class Column { this.foreignKeyIndex = value; } + /** + * Gets the value of the foreignOnDelete property. + * + * @return possible object is + * {@link String } + */ + public String getForeignKeyOnDelete() { + return foreignKeyOnDelete; + } + + /** + * Sets the value of the foreignKeyOnDelete property. + * + * @param value allowed object is + * {@link String } + */ + public void setForeignKeyOnDelete(String value) { + this.foreignKeyOnDelete = value; + } + + /** + * Gets the value of the foreignOnUpdate property. + * + * @return possible object is + * {@link String } + */ + public String getForeignKeyOnUpdate() { + return foreignKeyOnUpdate; + } + + /** + * Sets the value of the foreignKeyOnUpdate property. + * + * @param value allowed object is + * {@link String } + */ + public void setForeignKeyOnUpdate(String value) { + this.foreignKeyOnUpdate = value; + } + /** * Gets the value of the comment property. * diff --git a/src/main/java/io/ebeaninternal/dbmigration/migration/ForeignKey.java b/src/main/java/io/ebeaninternal/dbmigration/migration/ForeignKey.java index 8aa3763d3..37d314207 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/migration/ForeignKey.java +++ b/src/main/java/io/ebeaninternal/dbmigration/migration/ForeignKey.java @@ -21,6 +21,8 @@ import javax.xml.bind.annotation.XmlType; * <attribute name="refColumnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="refTableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" /> * <attribute name="indexName" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="onDelete" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="onUpdate" type="{http://www.w3.org/2001/XMLSchema}string" /> * </restriction> * </complexContent> * </complexType> @@ -41,7 +43,10 @@ public class ForeignKey { protected String refTableName; @XmlAttribute(name = "indexName") protected String indexName; - + @XmlAttribute(name = "onDelete") + protected String onDelete; + @XmlAttribute(name = "onUpdate") + protected String onUpdate; /** * Gets the value of the name property. * @@ -142,4 +147,44 @@ public class ForeignKey { this.indexName = value; } + /** + * Gets the value of the onDelete property. + * + * @return possible object is + * {@link String } + */ + public String getOnDelete() { + return onDelete; + } + + /** + * Sets the value of the onDelete property. + * + * @param value allowed object is + * {@link String } + */ + public void setOnDelete(String value) { + this.onDelete = value; + } + + /** + * Gets the value of the onUpdate property. + * + * @return possible object is + * {@link String } + */ + public String getOnUpdate() { + return onUpdate; + } + + /** + * Sets the value of the onUpdate property. + * + * @param value allowed object is + * {@link String } + */ + public void setOnUpdate(String value) { + this.onUpdate = value; + } + } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java b/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java index 1ed8ff067..f9eb80a8c 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MColumn.java @@ -1,13 +1,14 @@ package io.ebeaninternal.dbmigration.model; -import java.util.List; - +import io.ebean.annotation.ConstraintMode; import io.ebeaninternal.dbmigration.ddlgeneration.platform.DdlHelp; import io.ebeaninternal.dbmigration.migration.AlterColumn; import io.ebeaninternal.dbmigration.migration.Column; import io.ebeaninternal.dbmigration.migration.DdlScript; import io.ebeaninternal.server.deploy.DbMigrationInfo; +import java.util.List; + /** * A column in the logical model. */ @@ -21,6 +22,8 @@ public class MColumn { private String references; private String foreignKeyName; private String foreignKeyIndex; + private ConstraintMode fkeyOnDelete; + private ConstraintMode fkeyOnUpdate; private String comment; private boolean historyExclude; @@ -55,6 +58,8 @@ public class MColumn { this.references = column.getReferences(); this.foreignKeyName = column.getForeignKeyName(); this.foreignKeyIndex = column.getForeignKeyIndex(); + this.fkeyOnDelete = fkeyMode(column.getForeignKeyOnDelete()); + this.fkeyOnUpdate = fkeyMode(column.getForeignKeyOnUpdate()); this.notnull = Boolean.TRUE.equals(column.isNotnull()); this.primaryKey = Boolean.TRUE.equals(column.isPrimaryKey()); this.identity = Boolean.TRUE.equals(column.isIdentity()); @@ -63,6 +68,10 @@ public class MColumn { this.historyExclude = Boolean.TRUE.equals(column.isHistoryExclude()); } + private ConstraintMode fkeyMode(String mode) { + return (mode == null) ? null : ConstraintMode.valueOf(mode); + } + public MColumn(String name, String type) { this.name = name; this.type = type; @@ -89,6 +98,8 @@ public class MColumn { copy.comment = comment; copy.foreignKeyName = foreignKeyName; copy.foreignKeyIndex = foreignKeyIndex; + copy.fkeyOnUpdate = fkeyOnUpdate; + copy.fkeyOnDelete = fkeyOnDelete; copy.historyExclude = historyExclude; copy.notnull = notnull; copy.primaryKey = primaryKey; @@ -154,6 +165,11 @@ public class MColumn { this.foreignKeyIndex = foreignKeyIndex; } + public void setForeignKeyModes(ConstraintMode onDelete, ConstraintMode onUpdate) { + this.fkeyOnDelete = onDelete; + this.fkeyOnUpdate = onUpdate; + } + public String getDefaultValue() { return defaultValue; } @@ -196,7 +212,7 @@ public class MColumn { /** * Set unique specifically for OneToOne mapping. - * We need special DDL for this case for MsSqlServer. + * We need special DDL for this case for SqlServer. */ public void setUniqueOneToOne(String uniqueOneToOne) { this.uniqueOneToOne = uniqueOneToOne; @@ -260,6 +276,8 @@ public class MColumn { c.setReferences(references); c.setForeignKeyName(foreignKeyName); c.setForeignKeyIndex(foreignKeyIndex); + c.setForeignKeyOnDelete(fkeyModeOf(fkeyOnDelete)); + c.setForeignKeyOnUpdate(fkeyModeOf(fkeyOnUpdate)); c.setDefaultValue(defaultValue); c.setComment(comment); c.setUnique(unique); @@ -286,6 +304,10 @@ public class MColumn { return c; } + private String fkeyModeOf(ConstraintMode mode) { + return (mode == null) ? null : mode.name(); + } + protected static boolean different(String val1, String val2) { return (val1 == null) ? val2 != null : !val1.equals(val2); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index ba90cdd1c..b5b631458 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -11,6 +11,7 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.PropertyForeignKey; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoinColumn; import io.ebeaninternal.server.deploy.id.ImportedId; @@ -156,6 +157,8 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { List modelColumns = new ArrayList<>(columns.length); + PropertyForeignKey foreignKey = p.getForeignKey(); + MCompoundForeignKey compoundKey = null; if (columns.length > 1) { // compound foreign key @@ -180,15 +183,22 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { col.setDbMigrationInfos(p.getDbMigrationInfos()); col.setDefaultValue(p.getDbColumnDefault()); if (columns.length == 1) { - // single references column (put it on the column) - String refTable = importedProperty.getBeanDescriptor().getBaseTable(); - if (refTable == null) { - // odd case where an EmbeddedId only has 1 property - refTable = p.getTargetDescriptor().getBaseTable(); + if (p.hasForeignKey()) { + // single references column (put it on the column) + String refTable = importedProperty.getBeanDescriptor().getBaseTable(); + if (refTable == null) { + // odd case where an EmbeddedId only has 1 property + refTable = p.getTargetDescriptor().getBaseTable(); + } + col.setReferences(refTable + "." + refColumn); + col.setForeignKeyName(determineForeignKeyConstraintName(col.getName())); + if (p.hasForeignKeyIndex()) { + col.setForeignKeyIndex(determineForeignKeyIndexName(col.getName())); + } + if (foreignKey != null) { + col.setForeignKeyModes(foreignKey.getOnDelete(), foreignKey.getOnUpdate()); + } } - col.setReferences(refTable + "." + refColumn); - col.setForeignKeyName(determineForeignKeyConstraintName(col.getName())); - col.setForeignKeyIndex(determineForeignKeyIndexName(col.getName())); } else { compoundKey.addColumnPair(dbCol, refColumn); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index d523bb739..134d4c3e6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.BackgroundExecutor; import io.ebean.Model; import io.ebean.RawSqlBuilder; +import io.ebean.annotation.ConstraintMode; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebean.config.EncryptKey; @@ -1156,7 +1157,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // get the mappedBy property DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy); if (mappedProp == null) { - String m = "Error on " + prop.getFullBeanName(); m += " Can not find mappedBy property [" + mappedBy + "] "; m += "in [" + targetDesc + "]"; @@ -1179,6 +1179,19 @@ public class BeanDescriptorManager implements BeanDescriptorMap { otherTableJoin.copyTo(tableJoin, true, tableJoin.getTable()); } + PropertyForeignKey foreignKey = mappedAssocOne.getForeignKey(); + if (foreignKey != null) { + ConstraintMode onDelete = foreignKey.getOnDelete(); + switch (onDelete) { + case SET_DEFAULT: + case SET_NULL: + case CASCADE: { + // turn off cascade delete when we are using the foreign + // key constraint to cascade the delete or set null + prop.getCascadeInfo().setDelete(false); + } + } + } } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 2bc1bd27c..04e953aca 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -41,6 +41,8 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { private final boolean primaryKeyExport; + private final PropertyForeignKey foreignKey; + private AssocOneHelp localHelp; protected final BeanProperty[] embeddedProps; @@ -69,6 +71,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { super(descriptor, deploy); + foreignKey = deploy.getForeignKey(); primaryKeyExport = deploy.isPrimaryKeyExport(); importedPrimaryKey = deploy.isImportedPrimaryKey(); oneToOne = deploy.isOneToOne(); @@ -309,6 +312,18 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } + public PropertyForeignKey getForeignKey() { + return foreignKey; + } + + public boolean hasForeignKey() { + return foreignKey == null || !foreignKey.isNoConstraint(); + } + + public boolean hasForeignKeyIndex() { + return foreignKey == null || !foreignKey.isNoIndex(); + } + /** * Return true if this a OneToOne property. Otherwise assumed ManyToOne. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java new file mode 100644 index 000000000..ab5b75111 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java @@ -0,0 +1,35 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.annotation.ConstraintMode; +import io.ebean.annotation.DbForeignKey; + +public class PropertyForeignKey { + + private final boolean noIndex; + private final boolean noConstraint; + private final ConstraintMode onDelete; + private final ConstraintMode onUpdate; + + public PropertyForeignKey(DbForeignKey dbForeignKey) { + this.noIndex = dbForeignKey.noIndex(); + this.noConstraint = dbForeignKey.noConstraint(); + this.onDelete = dbForeignKey.onDelete(); + this.onUpdate = dbForeignKey.onUpdate(); + } + + public boolean isNoIndex() { + return noIndex; + } + + public boolean isNoConstraint() { + return noConstraint; + } + + public ConstraintMode getOnDelete() { + return onDelete; + } + + public ConstraintMode getOnUpdate() { + return onUpdate; + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index 9e257def2..93c57efb7 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -1,5 +1,7 @@ package io.ebeaninternal.server.deploy.meta; +import io.ebeaninternal.server.deploy.PropertyForeignKey; + import javax.persistence.CascadeType; /** @@ -21,6 +23,8 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { private String columnPrefix; + private PropertyForeignKey foreignKey; + /** * Create the property. */ @@ -148,4 +152,12 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { cascadeInfo.setType(CascadeType.ALL); } } + + public void setForeignKey(PropertyForeignKey foreignKey) { + this.foreignKey = foreignKey; + } + + public PropertyForeignKey getForeignKey() { + return foreignKey; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 4e5b04e36..6294c5e82 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -1,10 +1,12 @@ package io.ebeaninternal.server.deploy.parse; +import io.ebean.annotation.DbForeignKey; import io.ebean.annotation.FetchPreference; import io.ebean.annotation.Where; import io.ebean.config.NamingConvention; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.BeanTable; +import io.ebeaninternal.server.deploy.PropertyForeignKey; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; @@ -89,6 +91,11 @@ public class AnnotationAssocOnes extends AnnotationParser { prop.setNullable(false); } + DbForeignKey dbForeignKey = get(prop, DbForeignKey.class); + if (dbForeignKey != null){ + prop.setForeignKey(new PropertyForeignKey(dbForeignKey)); + } + Where where = get(prop, Where.class); if (where != null) { // not expecting this to be used on assoc one properties diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd index 4233f28ef..ade3fc9a7 100644 --- a/src/main/resources/ebean-dbmigration-1.0.xsd +++ b/src/main/resources/ebean-dbmigration-1.0.xsd @@ -136,6 +136,8 @@ + + @@ -221,6 +223,8 @@ + + @@ -271,6 +275,8 @@ + + diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10DdlTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10DdlTest.java new file mode 100644 index 000000000..efd8c395c --- /dev/null +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/Oracle10DdlTest.java @@ -0,0 +1,54 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.annotation.ConstraintMode; +import io.ebean.config.dbplatform.oracle.OraclePlatform; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class Oracle10DdlTest { + + Oracle10Ddl create() { + return new Oracle10Ddl(new OraclePlatform()); + } + + @Test + public void appendForeignKeyOnDelete_expectEmtpy_when_nullRestrictSetDefault() { + + Oracle10Ddl oracle = create(); + + StringBuilder sb = new StringBuilder(); + oracle.appendForeignKeyOnDelete(sb, oracle.withDefault(null)); + assertThat(sb.toString()).isEqualTo(""); + + sb = new StringBuilder(); + oracle.appendForeignKeyOnDelete(sb, ConstraintMode.RESTRICT); + assertThat(sb.toString()).isEqualTo(""); + + + sb = new StringBuilder(); + oracle.appendForeignKeyOnDelete(sb, ConstraintMode.SET_DEFAULT); + assertThat(sb.toString()).isEqualTo(""); + } + + @Test + public void appendForeignKeyOnDelete_setNull() { + + Oracle10Ddl oracle = create(); + + StringBuilder sb = new StringBuilder(); + oracle.appendForeignKeyOnDelete(sb, ConstraintMode.SET_NULL); + assertThat(sb.toString()).isEqualTo(" on delete set null"); + } + + @Test + public void appendForeignKeyOnDelete_cascade() { + + Oracle10Ddl oracle = create(); + + StringBuilder sb = new StringBuilder(); + oracle.appendForeignKeyOnDelete(sb, ConstraintMode.CASCADE); + assertThat(sb.toString()).isEqualTo(" on delete cascade"); + } + +} diff --git a/src/test/java/org/tests/cascade/TestOrderedList.java b/src/test/java/org/tests/cascade/TestOrderedList.java index 9baf7a601..4b8540adb 100644 --- a/src/test/java/org/tests/cascade/TestOrderedList.java +++ b/src/test/java/org/tests/cascade/TestOrderedList.java @@ -27,7 +27,12 @@ public class TestOrderedList extends BaseTestCase { List sql = LoggedSqlCollector.current(); assertThat(sql.size()).isGreaterThan(1); assertThat(sql.get(0)).contains("insert into om_ordered_master"); - assertThat(sql.get(1)).contains("insert into om_ordered_detail (name, version, sort_order, master_id) values (?,?,?,?)"); + boolean hasId = sql.get(1).contains(" (id, name"); + if (hasId) { + assertThat(sql.get(1)).contains("insert into om_ordered_detail (id, name, version, sort_order, master_id) values (?,?,?,?,?)"); + } else { + assertThat(sql.get(1)).contains("insert into om_ordered_detail (name, version, sort_order, master_id) values (?,?,?,?)"); + } // update without any changes Ebean.save(master); diff --git a/src/test/java/org/tests/ddl/DfkCascade.java b/src/test/java/org/tests/ddl/DfkCascade.java new file mode 100644 index 000000000..18f4f8201 --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkCascade.java @@ -0,0 +1,50 @@ +package org.tests.ddl; + +import io.ebean.annotation.ConstraintMode; +import io.ebean.annotation.DbForeignKey; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class DfkCascade { + + @Id + long id; + + String name; + + @ManyToOne + @DbForeignKey(onDelete = ConstraintMode.CASCADE) + DfkCascadeOne one; + + public DfkCascade(String name, DfkCascadeOne one) { + this.name = name; + this.one = one; + } + + 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 DfkCascadeOne getOne() { + return one; + } + + public void setOne(DfkCascadeOne one) { + this.one = one; + } +} diff --git a/src/test/java/org/tests/ddl/DfkCascadeOne.java b/src/test/java/org/tests/ddl/DfkCascadeOne.java new file mode 100644 index 000000000..fa3c14c2c --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkCascadeOne.java @@ -0,0 +1,47 @@ +package org.tests.ddl; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import java.util.List; + +@Entity +public class DfkCascadeOne { + + @Id + long id; + + String name; + + @OneToMany(mappedBy = "one", cascade = CascadeType.ALL) + List details; + + public DfkCascadeOne(String name) { + this.name = name; + } + + 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 getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } +} diff --git a/src/test/java/org/tests/ddl/DfkNone.java b/src/test/java/org/tests/ddl/DfkNone.java new file mode 100644 index 000000000..995ba990d --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkNone.java @@ -0,0 +1,49 @@ +package org.tests.ddl; + +import io.ebean.annotation.DbForeignKey; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class DfkNone { + + @Id + long id; + + String name; + + @ManyToOne + @DbForeignKey(noConstraint = true) + DfkOne one; + + public DfkNone(String name, DfkOne one) { + this.name = name; + this.one = one; + } + + 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 DfkOne getOne() { + return one; + } + + public void setOne(DfkOne one) { + this.one = one; + } +} diff --git a/src/test/java/org/tests/ddl/DfkOne.java b/src/test/java/org/tests/ddl/DfkOne.java new file mode 100644 index 000000000..84bb826d8 --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkOne.java @@ -0,0 +1,33 @@ +package org.tests.ddl; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class DfkOne { + + @Id + long id; + + String name; + + public DfkOne(String name) { + this.name = name; + } + + 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; + } +} diff --git a/src/test/java/org/tests/ddl/DfkSetNull.java b/src/test/java/org/tests/ddl/DfkSetNull.java new file mode 100644 index 000000000..5f55e3f0b --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkSetNull.java @@ -0,0 +1,50 @@ +package org.tests.ddl; + +import io.ebean.annotation.ConstraintMode; +import io.ebean.annotation.DbForeignKey; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class DfkSetNull { + + @Id + long id; + + String name; + + @ManyToOne + @DbForeignKey(onDelete = ConstraintMode.SET_NULL) + DfkOne one; + + public DfkSetNull(String name, DfkOne one) { + this.name = name; + this.one = one; + } + + 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 DfkOne getOne() { + return one; + } + + public void setOne(DfkOne one) { + this.one = one; + } +} diff --git a/src/test/java/org/tests/ddl/TestForeignKeyModes.java b/src/test/java/org/tests/ddl/TestForeignKeyModes.java new file mode 100644 index 000000000..d0e8bdccf --- /dev/null +++ b/src/test/java/org/tests/ddl/TestForeignKeyModes.java @@ -0,0 +1,77 @@ +package org.tests.ddl; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestForeignKeyModes extends BaseTestCase { + + @Test + public void none() { + + DfkOne one = new DfkOne("one"); + Ebean.save(one); + + DfkNone none = new DfkNone("none", one); + Ebean.save(none); + + // fails unless there is no Foreign key ... + Ebean.delete(one); + + DfkNone found = Ebean.find(DfkNone.class, none.getId()); + assertThat(found).isNotNull(); + // we still reference one ... even though it does not exist anymore + assertThat(found.getOne()).isNotNull(); + } + + + @Test + public void setNullOnDelete() { + + DfkOne one = new DfkOne("one2"); + Ebean.save(one); + + DfkSetNull other = new DfkSetNull("none", one); + Ebean.save(other); + + // success with ... fkey value set to null + Ebean.delete(one); + + DfkSetNull found = Ebean.find(DfkSetNull.class, other.getId()); + assertThat(found).isNotNull(); + assertThat(found.getOne()).isNull(); + + } + + @Test + public void onDeleteCascade() { + + DfkCascadeOne one = new DfkCascadeOne("one3"); + + + DfkCascade other = new DfkCascade("cascade1", one); + one.getDetails().add(other); + one.getDetails().add(new DfkCascade("cascade2", one)); + one.getDetails().add(new DfkCascade("cascade3", one)); + + Ebean.save(one); + + + LoggedSqlCollector.start(); + Ebean.delete(one); + + List sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("delete from dfk_cascade_one where id=?"); + + DfkCascade found = Ebean.find(DfkCascade.class, other.getId()); + assertThat(found).isNull(); + + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java index b2ab2d1c6..0b207f938 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoin.java @@ -35,7 +35,7 @@ public class TestOneToOnePrimaryKeyJoin extends BaseTestCase { OtoPrime found = query.findOne(); assertThat(found).isNotNull(); - assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_prime t0 where t0.pid = ?") + assertThat(sqlOf(query, 10)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_prime t0 where t0.pid = ?") .as("we don't join to oto_prime_extra"); assertThat(found.getName()).isEqualTo("p" + desc); @@ -47,7 +47,7 @@ public class TestOneToOnePrimaryKeyJoin extends BaseTestCase { OtoPrime oneWith = queryWithFetch.findOne(); assertThat(oneWith).isNotNull(); - assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_prime t0 join oto_prime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + assertThat(sqlOf(queryWithFetch, 10)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_prime t0 join oto_prime_extra t1 on t1.eid = t0.pid where t0.pid = ?") .as("we join to oto_prime_extra"); diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java index 8becdfe02..7903abc02 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinBidi.java @@ -35,7 +35,7 @@ public class TestOneToOnePrimaryKeyJoinBidi extends BaseTestCase { OtoUBPrime found = query.findOne(); assertThat(found).isNotNull(); - assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_ubprime t0 where t0.pid = ?") + assertThat(sqlOf(query, 10)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_ubprime t0 where t0.pid = ?") .as("we don't join to oto_ubprime_extra"); assertThat(found.getName()).isEqualTo("u" + desc); @@ -47,7 +47,7 @@ public class TestOneToOnePrimaryKeyJoinBidi extends BaseTestCase { OtoUBPrime oneWith = queryWithFetch.findOne(); assertThat(oneWith).isNotNull(); - assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version, t1.eid from oto_ubprime t0 left join oto_ubprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + assertThat(sqlOf(queryWithFetch, 10)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version, t1.eid from oto_ubprime t0 left join oto_ubprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") .as("we join to oto_prime_extra"); diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java index 64835b68b..259991b85 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOnePrimaryKeyJoinOptional.java @@ -35,7 +35,7 @@ public class TestOneToOnePrimaryKeyJoinOptional extends BaseTestCase { OtoUPrime found = query.findOne(); assertThat(found).isNotNull(); - assertThat(sqlOf(query)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_uprime t0 where t0.pid = ?") + assertThat(sqlOf(query, 4)).contains("select t0.pid, t0.name, t0.version, t0.pid from oto_uprime t0 where t0.pid = ?") .as("we don't join to oto_uprime_extra"); assertThat(found.getName()).isEqualTo("u" + desc); @@ -47,7 +47,7 @@ public class TestOneToOnePrimaryKeyJoinOptional extends BaseTestCase { OtoUPrime oneWith = queryWithFetch.findOne(); assertThat(oneWith).isNotNull(); - assertThat(sqlOf(queryWithFetch)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_uprime t0 left join oto_uprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") + assertThat(sqlOf(queryWithFetch, 6)).contains("select t0.pid, t0.name, t0.version, t1.eid, t1.extra, t1.version from oto_uprime t0 left join oto_uprime_extra t1 on t1.eid = t0.pid where t0.pid = ?") .as("we join to oto_prime_extra"); diff --git a/src/test/java/org/tests/update/EPersonOnline.java b/src/test/java/org/tests/update/EPersonOnline.java index 7b1f2bb88..232226652 100644 --- a/src/test/java/org/tests/update/EPersonOnline.java +++ b/src/test/java/org/tests/update/EPersonOnline.java @@ -7,7 +7,6 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.Size; - import java.time.Instant; @Entity @@ -21,7 +20,7 @@ public class EPersonOnline { @Size(max=127) String email; - boolean online; + boolean onlineStatus; @WhenModified Instant whenUpdated; @@ -42,12 +41,12 @@ public class EPersonOnline { this.email = email; } - public boolean isOnline() { - return online; + public boolean isOnlineStatus() { + return onlineStatus; } - public void setOnline(boolean online) { - this.online = online; + public void setOnlineStatus(boolean onlineStatus) { + this.onlineStatus = onlineStatus; } public Instant getWhenUpdated() { diff --git a/src/test/java/org/tests/update/TestSqlUpdateUpsert.java b/src/test/java/org/tests/update/TestSqlUpdateUpsert.java index 92aa0dd3f..eeb761b4b 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateUpsert.java +++ b/src/test/java/org/tests/update/TestSqlUpdateUpsert.java @@ -15,7 +15,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { @Test public void h2Merge() { - String sql = "merge into e_person_online (email, online, when_updated) key(email) values (?, ?, now())"; + String sql = "merge into e_person_online (email, online_status, when_updated) key(email) values (?, ?, now())"; String email = "baz@one.com"; @@ -28,9 +28,9 @@ public class TestSqlUpdateUpsert extends BaseTestCase { EPersonOnline found = Ebean.find(EPersonOnline.class, key); assertThat(found).isNotNull(); assertThat(found.getEmail()).isEqualTo(email); - assertThat(found.isOnline()).isTrue(); + assertThat(found.isOnlineStatus()).isTrue(); - String sqlNamed = "merge into e_person_online (email, online, when_updated) key(email) values (:email, :online, now())"; + String sqlNamed = "merge into e_person_online (email, online_status, when_updated) key(email) values (:email, :online, now())"; SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) .setGetGeneratedKeys(true) @@ -45,7 +45,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { assertThat(found2).isNotNull(); assertThat(found2.getId()).isEqualTo(key); assertThat(found2.getEmail()).isEqualTo(email); - assertThat(found2.isOnline()).isFalse(); + assertThat(found2.isOnlineStatus()).isFalse(); assertThat(found2.getWhenUpdated()).isGreaterThan(found.getWhenUpdated()); } @@ -53,7 +53,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { @Test public void postgresUpsert() { - String sql = "insert into e_person_online (email, online, when_updated) values (?, ?, now()) on conflict (email) do update set when_updated=now(), online = ?"; + String sql = "insert into e_person_online (email, online_status, when_updated) values (?, ?, now()) on conflict (email) do update set when_updated=now(), online_status = ?"; String email = "foo@one.com"; @@ -67,10 +67,10 @@ public class TestSqlUpdateUpsert extends BaseTestCase { EPersonOnline found = Ebean.find(EPersonOnline.class, key); assertThat(found).isNotNull(); assertThat(found.getEmail()).isEqualTo("foo@one.com"); - assertThat(found.isOnline()).isTrue(); + assertThat(found.isOnlineStatus()).isTrue(); - String sqlNamed = "insert into e_person_online (email, online, when_updated) values (:email, :online, now()) on conflict (email) do update set when_updated=now(), online = :online"; + String sqlNamed = "insert into e_person_online (email, online_status, when_updated) values (:email, :online, now()) on conflict (email) do update set when_updated=now(), online_status = :online"; SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) .setGetGeneratedKeys(true) .setParameter("email", email) @@ -82,7 +82,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { assertThat(found2).isNotNull(); assertThat(found2.getId()).isEqualTo(key); assertThat(found2.getEmail()).isEqualTo("foo@one.com"); - assertThat(found2.isOnline()).isFalse(); + assertThat(found2.isOnlineStatus()).isFalse(); assertThat(found2.getWhenUpdated()).isGreaterThan(found.getWhenUpdated()); } @@ -93,7 +93,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { String email = "bar@one.com"; - String sql = "insert into e_person_online (email, online, when_updated) values (?, ?, current_time) on duplicate key update when_updated=current_time, online = ?"; + String sql = "insert into e_person_online (email, online_status, when_updated) values (?, ?, current_time) on duplicate key update when_updated=current_time, online_status = ?"; SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql) .setGetGeneratedKeys(true) .setParameter(1, email) @@ -106,10 +106,10 @@ public class TestSqlUpdateUpsert extends BaseTestCase { EPersonOnline found = Ebean.find(EPersonOnline.class, key); assertThat(found).isNotNull(); assertThat(found.getEmail()).isEqualTo("bar@one.com"); - assertThat(found.isOnline()).isTrue(); + assertThat(found.isOnlineStatus()).isTrue(); - String sqlNamed = "insert into e_person_online (email, online, when_updated) values (:email, :online, current_time) on duplicate key update when_updated=current_time, online = :online"; + String sqlNamed = "insert into e_person_online (email, online_status, when_updated) values (:email, :online, current_time) on duplicate key update when_updated=current_time, online_status = :online"; SqlUpdate sqlUpdate2 = Ebean.createSqlUpdate(sqlNamed) .setGetGeneratedKeys(true) .setParameter("email", email) @@ -122,7 +122,7 @@ public class TestSqlUpdateUpsert extends BaseTestCase { assertThat(found2).isNotNull(); assertThat(found2.getId()).isEqualTo(key); assertThat(found2.getEmail()).isEqualTo("bar@one.com"); - assertThat(found2.isOnline()).isFalse(); + assertThat(found2.isOnlineStatus()).isFalse(); } } From 183d079b58606509ede02dea2afda7a11df12795 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 19 Feb 2018 22:24:51 +1300 Subject: [PATCH 0038/1036] #323 - DDL Generation support for foreign key cascade options --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e60b0ec7e..b5f9956c8 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ io.ebean ebean-annotation - 3.6 + 3.7 From 2be3099d55147249ebc78743c1a35f7697342230 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 19 Feb 2018 22:45:47 +1300 Subject: [PATCH 0039/1036] #1228 - Add support to not generate FK Constraint when @JoinColumn(foreignKey=@ForeignKey(ConstraintMode.NO_CONSTRAINT)) --- .../server/deploy/PropertyForeignKey.java | 13 +++++ .../deploy/parse/AnnotationAssocOnes.java | 10 ++++ .../java/org/tests/ddl/DfkNoneViaJoin.java | 50 +++++++++++++++++++ .../org/tests/ddl/TestForeignKeyModes.java | 18 +++++++ 4 files changed, 91 insertions(+) create mode 100644 src/test/java/org/tests/ddl/DfkNoneViaJoin.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java index ab5b75111..8badce0ce 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java +++ b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java @@ -10,6 +10,19 @@ public class PropertyForeignKey { private final ConstraintMode onDelete; private final ConstraintMode onUpdate; + /** + * Construct for "No Constraint". + */ + public PropertyForeignKey() { + this.noConstraint = true; + this.noIndex = false; + this.onDelete = ConstraintMode.GLOBAL_DEFAULT; + this.onUpdate = ConstraintMode.GLOBAL_DEFAULT; + } + + /** + * Construct for the mapping annotation. + */ public PropertyForeignKey(DbForeignKey dbForeignKey) { this.noIndex = dbForeignKey.noIndex(); this.noConstraint = dbForeignKey.noConstraint(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 6294c5e82..15a3ed4de 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -16,8 +16,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.Column; +import javax.persistence.ConstraintMode; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; +import javax.persistence.ForeignKey; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; @@ -131,6 +133,7 @@ public class AnnotationAssocOnes extends AnnotationParser { if (!joinColumn.nullable()) { prop.setNullable(false); } + checkForNoConstraint(prop, joinColumn); } @@ -171,6 +174,13 @@ public class AnnotationAssocOnes extends AnnotationParser { } } + private void checkForNoConstraint(DeployBeanPropertyAssocOne prop, JoinColumn joinColumn) { + ForeignKey foreignKey = joinColumn.foreignKey(); + if (foreignKey != null && foreignKey.value() == ConstraintMode.NO_CONSTRAINT) { + prop.setForeignKey(new PropertyForeignKey()); + } + } + private String errorMsgMissingBeanTable(Class type, String from) { return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered?"; } diff --git a/src/test/java/org/tests/ddl/DfkNoneViaJoin.java b/src/test/java/org/tests/ddl/DfkNoneViaJoin.java new file mode 100644 index 000000000..148e219b9 --- /dev/null +++ b/src/test/java/org/tests/ddl/DfkNoneViaJoin.java @@ -0,0 +1,50 @@ +package org.tests.ddl; + +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.ForeignKey; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +@Entity +public class DfkNoneViaJoin { + + @Id + long id; + + String name; + + @ManyToOne + @JoinColumn(name = "one_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + DfkOne one; + + public DfkNoneViaJoin(String name, DfkOne one) { + this.name = name; + this.one = one; + } + + 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 DfkOne getOne() { + return one; + } + + public void setOne(DfkOne one) { + this.one = one; + } +} diff --git a/src/test/java/org/tests/ddl/TestForeignKeyModes.java b/src/test/java/org/tests/ddl/TestForeignKeyModes.java index d0e8bdccf..a9b1216b2 100644 --- a/src/test/java/org/tests/ddl/TestForeignKeyModes.java +++ b/src/test/java/org/tests/ddl/TestForeignKeyModes.java @@ -30,6 +30,24 @@ public class TestForeignKeyModes extends BaseTestCase { } + @Test + public void noneViaJoin() { + + DfkOne one = new DfkOne("one2"); + Ebean.save(one); + + DfkNoneViaJoin none = new DfkNoneViaJoin("none2", one); + Ebean.save(none); + + // fails unless there is no Foreign key ... + Ebean.delete(one); + + DfkNoneViaJoin found = Ebean.find(DfkNoneViaJoin.class, none.getId()); + assertThat(found).isNotNull(); + // we still reference one ... even though it does not exist anymore + assertThat(found.getOne()).isNotNull(); + } + @Test public void setNullOnDelete() { From 81d48d67a798f7f2e23fc163310a33922a283547 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Feb 2018 14:40:21 +1300 Subject: [PATCH 0040/1036] #123 - Mapping - Add support for OneToMany JoinTables --- .../java/io/ebean/bean/BeanCollection.java | 5 + .../ebean/common/AbstractBeanCollection.java | 5 + .../ddlgeneration/platform/BaseTableDdl.java | 17 ++- .../platform/WriteUniqueConstraint.java | 47 +++++++ .../dbmigration/model/MTable.java | 1 - .../build/ModelBuildIntersectionTable.java | 4 +- .../build/ModelBuildPropertyVisitor.java | 13 +- .../server/deploy/BeanDescriptorManager.java | 6 +- .../server/deploy/BeanPropertyAssocMany.java | 87 ++++++------- .../meta/DeployBeanPropertyAssocMany.java | 12 ++ .../deploy/meta/DeployBeanPropertyLists.java | 10 +- .../deploy/parse/AnnotationAssocManys.java | 6 +- .../server/persist/DefaultPersister.java | 29 ++++- .../server/persist/SaveManyPropRequest.java | 2 +- .../server/query/SqlTreeNodeBean.java | 4 +- .../server/query/SqlTreeNodeExtraJoin.java | 2 +- .../query/SqlTreeNodeManyWhereJoin.java | 2 +- src/test/java/io/ebean/BaseTestCase.java | 11 +- .../org/tests/o2m/jointable/JtMonkey.java | 57 +++++++++ .../org/tests/o2m/jointable/JtTrainer.java | 66 ++++++++++ .../java/org/tests/o2m/jointable/JtTroop.java | 65 ++++++++++ .../o2m/jointable/TestOneToManyJoinTable.java | 115 ++++++++++++++++++ 22 files changed, 478 insertions(+), 88 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteUniqueConstraint.java create mode 100644 src/test/java/org/tests/o2m/jointable/JtMonkey.java create mode 100644 src/test/java/org/tests/o2m/jointable/JtTrainer.java create mode 100644 src/test/java/org/tests/o2m/jointable/JtTroop.java create mode 100644 src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java diff --git a/src/main/java/io/ebean/bean/BeanCollection.java b/src/main/java/io/ebean/bean/BeanCollection.java index 28b17bd05..8c3b95b08 100644 --- a/src/main/java/io/ebean/bean/BeanCollection.java +++ b/src/main/java/io/ebean/bean/BeanCollection.java @@ -191,6 +191,11 @@ public interface BeanCollection extends Serializable { */ void setModifyListening(ModifyListenMode modifyListenMode); + /** + * Return the current modify listening mode. Can be null for on newly created beans. + */ + ModifyListenMode getModifyListening(); + /** * Add an object to the additions list. *

diff --git a/src/main/java/io/ebean/common/AbstractBeanCollection.java b/src/main/java/io/ebean/common/AbstractBeanCollection.java index d02c0ffc7..866d8d0c0 100644 --- a/src/main/java/io/ebean/common/AbstractBeanCollection.java +++ b/src/main/java/io/ebean/common/AbstractBeanCollection.java @@ -140,6 +140,11 @@ abstract class AbstractBeanCollection implements BeanCollection { // Support for modify additions deletions etc - ManyToMany // --------------------------------------------------------- + @Override + public ModifyListenMode getModifyListening() { + return modifyListenMode; + } + /** * set modifyListening to be on or off. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 8969e7c7d..d94c59837 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -541,17 +541,14 @@ public class BaseTableDdl implements TableDdl { boolean inlineUniqueWhenNullable = platformDdl.isInlineUniqueWhenNullable(); - List columns = createTable.getColumn(); + List columns = new WriteUniqueConstraint(createTable.getColumn()).uniqueKeys(); for (Column column : columns) { - if (!Boolean.TRUE.equals(column.isPrimaryKey()) - && (hasValue(column.getUnique()) || hasValue(column.getUniqueOneToOne()))) { - if (Boolean.TRUE.equals(column.isNotnull()) || inlineUniqueWhenNullable) { - // normal mechanism for adding unique constraint - inlineUniqueConstraintSingle(apply, column); - } else { - // MsSqlServer & DB2 specific mechanism for adding unique constraints (that allow nulls) - externalUnique.add(column); - } + if (Boolean.TRUE.equals(column.isNotnull()) || inlineUniqueWhenNullable) { + // normal mechanism for adding unique constraint + inlineUniqueConstraintSingle(apply, column); + } else { + // SqlServer & DB2 specific mechanism for adding unique constraints (that allow nulls) + externalUnique.add(column); } } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteUniqueConstraint.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteUniqueConstraint.java new file mode 100644 index 000000000..b3e1c242b --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/WriteUniqueConstraint.java @@ -0,0 +1,47 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebeaninternal.dbmigration.migration.Column; + +import java.util.ArrayList; +import java.util.List; + +class WriteUniqueConstraint { + + private final List primaryKeys = new ArrayList<>(); + private final List uniqueKeys = new ArrayList<>(); + + WriteUniqueConstraint(List columns) { + + // filter for unique and primary keys + for (Column column : columns) { + if (Boolean.TRUE.equals(column.isPrimaryKey())) { + primaryKeys.add(column); + } + if (hasValue(column.getUnique()) || hasValue(column.getUniqueOneToOne())){ + uniqueKeys.add(column); + } + } + } + + /** + * Return true if null or trimmed string is empty. + */ + boolean hasValue(String value) { + return value != null && !value.trim().isEmpty(); + } + + /** + * Return the single columns with unique constraints (that are not the primary key). + */ + public List uniqueKeys() { + if (uniqueKeys.isEmpty() || primaryKeys.size() > 1) { + // all single column unique constraints are valid + return uniqueKeys; + } + // filter out PFK + for (Column primaryKey : primaryKeys) { + uniqueKeys.remove(primaryKey); + } + return uniqueKeys; + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index 2401d6b31..7e02a0e03 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -408,7 +408,6 @@ public class MTable { * Return all the columns (excluding columns marked as dropped). */ public Collection allColumns() { - return columns.values(); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java index a0b70e594..9bf4d50c0 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java @@ -9,7 +9,6 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.TableJoinColumn; - /** * Add the intersection table to the model. */ @@ -32,7 +31,7 @@ public class ModelBuildIntersectionTable { this.tableJoin = manyProp.getTableJoin(); } - public void build() { + public MTable build() { intersectionTable = createTable(); MTable existingTable = ctx.addTable(intersectionTable); @@ -47,6 +46,7 @@ public class ModelBuildIntersectionTable { ctx.createDraft(intersectionTable, false); } + return intersectionTable; } private void buildFkConstraints() { diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index b5b631458..8d9f64be5 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -17,6 +17,7 @@ import io.ebeaninternal.server.deploy.TableJoinColumn; import io.ebeaninternal.server.deploy.id.ImportedId; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -120,7 +121,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { @Override public void visitMany(BeanPropertyAssocMany p) { - if (p.isManyToMany()) { + if (p.hasJoinTable()) { if (p.getMappedBy() == null) { // only create on other 'owning' side @@ -130,7 +131,15 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { // build the create table and fkey constraints // putting the DDL into ctx for later output as we are // in the middle of rendering the create table DDL - new ModelBuildIntersectionTable(ctx, p).build(); + MTable intersectionTable = new ModelBuildIntersectionTable(ctx, p).build(); + if (p.isO2mJoinTable()) { + Collection cols = intersectionTable.allColumns(); + if (cols.size() == 2) { + // always the second column that we put the unique constraint on + MColumn col = new ArrayList<>(cols).get(1); + col.setUnique(determineUniqueConstraintName(col.getName())); + } + } } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 134d4c3e6..ed2945ef6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1138,14 +1138,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap { if (prop.getMappedBy() == null) { // if we are doc store only we are done - // this allowes the use of @OneToMany in @DocStore - Entities + // this allows the use of @OneToMany in @DocStore - Entities if (info.getDescriptor().isDocStoreOnly()) { prop.setUnidirectional(); return; } if (!findMappedBy(prop)) { - makeUnidirectional(info, prop); + if (!prop.isO2mJoinTable()) { + makeUnidirectional(info, prop); + } return; } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 8f902c047..7c2f3cc08 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -58,6 +58,8 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ private final boolean unidirectional; + private final boolean o2mJoinTable; + /** * Flag to indicate that the target has a order column to auto populate. */ @@ -114,6 +116,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { public BeanPropertyAssocMany(BeanDescriptor descriptor, DeployBeanPropertyAssocMany deploy) { super(descriptor, deploy); this.unidirectional = deploy.isUnidirectional(); + this.o2mJoinTable = deploy.isO2mJoinTable(); this.hasOrderColumn = deploy.hasOrderColumn(); this.manyToMany = deploy.isManyToMany(); this.manyType = deploy.getManyType(); @@ -139,8 +142,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { if (!isTransient) { this.help = BeanCollectionHelpFactory.create(this); - if (manyToMany) { - // only manyToMany's have imported properties + if (hasJoinTable()) { importedId = createImportedId(this, targetDescriptor, tableJoin); } else { @@ -169,7 +171,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { sb.append(", "); } // these fk columns are either on the intersection (int_) or base table (t0) - String fkTableAlias = isManyToMany() ? "int_" : "t0"; + String fkTableAlias = hasJoinTable() ? "int_" : "t0"; sb.append(fkTableAlias).append(".").append(exportedProperties[i].getForeignDbColumn()); } sb.append(", ").append(fetchOrderBy); @@ -178,7 +180,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } String delStmt; - if (manyToMany) { + if (hasJoinTable()) { delStmt = "delete from " + inverseJoin.getTable() + " where "; } else { delStmt = "delete from " + targetDescriptor.getBaseTable() + " where "; @@ -347,8 +349,8 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ private void addWhereParentIdIn(SpiQuery query, List parentIds) { - String tableAlias = manyToMany ? "int_." : "t0."; - if (manyToMany) { + String tableAlias = hasJoinTable() ? "int_." : "t0."; + if (hasJoinTable()) { query.setM2MIncludeJoin(inverseJoin); } String rawWhere = deriveWhereParentIdSql(true, tableAlias); @@ -475,12 +477,12 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { StringBuilder sb = new StringBuilder(50); SpiQuery query = request.getQueryRequest().getQuery(); - if (manyToMany) { + if (hasJoinTable()) { sb.append(query.isAsDraft() ? intersectionDraftTable : intersectionPublishTable); } else { sb.append(targetDescriptor.getBaseTable(query.getTemporalMode())); } - if (softDelete && manyToMany) { + if (softDelete && hasJoinTable()) { sb.append(" x join "); sb.append(targetDescriptor.getBaseTable(query.getTemporalMode())); sb.append(" x2 on "); @@ -497,7 +499,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { exportedProperties[i].appendWhere(sb, "x.", path); } if (softDelete) { - String alias = (manyToMany) ? "x2" : "x"; + String alias = hasJoinTable() ? "x2" : "x"; sb.append(" and ").append(targetDescriptor.getSoftDeletePredicate(alias)); } return sb.toString(); @@ -574,6 +576,20 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return manyType; } + /** + * Return true if this is many to many. + */ + public boolean hasJoinTable() { + return manyToMany || o2mJoinTable; + } + + /** + * Return true if this is a one to many with a join table. + */ + public boolean isO2mJoinTable() { + return o2mJoinTable; + } + /** * Return true if this is many to many. */ @@ -661,7 +677,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { public void addSelectExported(DbSqlContext ctx, String tableAlias) { - String alias = manyToMany ? "int_" : tableAlias; + String alias = hasJoinTable() ? "int_" : tableAlias; if (alias == null) { alias = "t0"; } @@ -694,45 +710,6 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return sb.toString(); } -// public void setPredicates(SpiQuery query, EntityBean parentBean) { -// -// if (manyToMany){ -// // for ManyToMany lazy loading we need to include a -// // join to the intersection table. The predicate column -// // is not on the 'destination many table'. -// query.setIncludeTableJoin(inverseJoin); -// } -// -// if (embeddedExportedProperties) { -// // use the EmbeddedId object instead of the parentBean -// BeanProperty idProp = descriptor.getIdProperty(); -// parentBean = (EntityBean)idProp.getValue(parentBean); -// } -// -// for (int i = 0; i < exportedProperties.length; i++) { -// Object val = exportedProperties[i].getValue(parentBean); -// String fkColumn = exportedProperties[i].getForeignDbColumn(); -// if (!manyToMany){ -// fkColumn = targetDescriptor.getBaseTableAlias()+"."+fkColumn; -// } else { -// // use hard coded alias for intersection table -// fkColumn = "int_."+fkColumn; -// } -// query.where().eq(fkColumn, val); -// } -// -// if (extraWhere != null){ -// // replace the table alias place holder -// String ta = targetDescriptor.getBaseTableAlias(); -// String where = StringHelper.replaceString(extraWhere, "${ta}", ta); -// query.where().raw(where); -// } -// -// if (fetchOrderBy != null){ -// query.order(fetchOrderBy); -// } -// } - /** * Create the array of ExportedProperty used to build reference objects. */ @@ -776,7 +753,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { String searchTable; TableJoinColumn[] columns; - if (manyToMany) { + if (hasJoinTable()) { // look for column going to intersection columns = intersectionJoin.columns(); searchTable = intersectionJoin.getTable(); @@ -1024,4 +1001,14 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return liveMap; } + public boolean isIncludeCascadeSave() { + // Note ManyToMany always included as we always 'save' + // the relationship via insert/delete of intersection table + // REMOVALS means including PrivateOwned relationships + return cascadeInfo.isSave() || hasJoinTable() || ModifyListenMode.REMOVALS == modifyListenMode; + } + + public boolean isIncludeCascadeDelete() { + return cascadeInfo.isDelete() || o2mJoinTable || ModifyListenMode.REMOVALS == modifyListenMode; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java index 121938fab..112223110 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java @@ -21,6 +21,8 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { */ private boolean manyToMany; + private boolean o2mJoinTable; + /** * Flag to indicate this is a unidirectional relationship. */ @@ -220,4 +222,14 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { public boolean hasOrderColumn() { return orderColumn != null; } + + public boolean isO2mJoinTable() { + return o2mJoinTable; + } + + public void setO2mJoinTable() { + this.o2mJoinTable = true; + setModifyListenMode(ModifyListenMode.ALL); + } } + diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index c8bcfc6ce..b67093ec3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.deploy.meta; -import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanDescriptorMap; import io.ebeaninternal.server.deploy.BeanProperty; @@ -437,17 +436,12 @@ public class DeployBeanPropertyLists { for (BeanPropertyAssocMany prop : manys) { switch (mode) { case Save: - if (prop.getCascadeInfo().isSave() || prop.isManyToMany() - || ModifyListenMode.REMOVALS == prop.getModifyListenMode()) { - // Note ManyToMany always included as we always 'save' - // the relationship via insert/delete of intersection table - // REMOVALS means including PrivateOwned relationships + if (prop.isIncludeCascadeSave()) { list.add(prop); } break; case Delete: - if (prop.getCascadeInfo().isDelete() || ModifyListenMode.REMOVALS == prop.getModifyListenMode()) { - // REMOVALS means including PrivateOwned relationships + if (prop.isIncludeCascadeDelete()) { list.add(prop); } break; diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index a451886ba..df4edb1d6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -122,8 +122,10 @@ class AnnotationAssocManys extends AnnotationParser { readJoinTable(joinTable, prop); } else { - // OneToMany in theory - prop.getTableJoin().addJoinColumn(true, joinTable.joinColumns(), beanTable); + // OneToMany with @JoinTable + prop.setO2mJoinTable(); + readJoinTable(joinTable, prop); + manyToManyDefaultJoins(prop); } } diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 3c9effc4d..41cce82bf 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -825,7 +825,7 @@ public final class DefaultPersister implements Persister { private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) { - if (saveMany.getMany().isManyToMany()) { + if (saveMany.getMany().hasJoinTable()) { // check if we can save the m2m intersection in this direction // we only allow one direction based on first traversed basis @@ -925,13 +925,19 @@ public final class DefaultPersister implements Persister { throw new PersistenceException(msg); } if (!vanillaCollection) { - ((BeanCollection) value).modifyReset(); + BeanCollection manyValue = (BeanCollection) value; + setListenMode(manyValue, prop); + manyValue.modifyReset(); } } else { // BeanCollection so get the additions/deletions BeanCollection manyValue = (BeanCollection) value; - additions = manyValue.getModifyAdditions(); - deletions = manyValue.getModifyRemovals(); + if (setListenMode(manyValue, prop)) { + additions = manyValue.getActualDetails(); + } else { + additions = manyValue.getModifyAdditions(); + deletions = manyValue.getModifyRemovals(); + } // reset so the changes are only processed once manyValue.modifyReset(); } @@ -986,6 +992,19 @@ public final class DefaultPersister implements Persister { t.depth(-1); } + /** + * Check if we need to set the listen mode (on new collections persisted for the first time). + */ + private boolean setListenMode(BeanCollection manyValue, BeanPropertyAssocMany prop) { + ModifyListenMode mode = manyValue.getModifyListening(); + if (mode == null) { + // new collection persisted for the first time + manyValue.setModifyListening(prop.getModifyListenMode()); + return true; + } + return false; + } + private int deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany many, Transaction t, boolean publish) { // delete all intersection rows for this bean @@ -1039,7 +1058,7 @@ public final class DefaultPersister implements Persister { // Many's with delete cascade BeanPropertyAssocMany[] manys = desc.propertiesManyDelete(); for (BeanPropertyAssocMany many : manys) { - if (many.isManyToMany()) { + if (many.hasJoinTable()) { if (!softDelete) { // delete associated rows from intersection table (but not during soft delete) deleteAssocManyIntersection(parentBean, many, t, request.isPublish()); diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java index f25fd9d48..4556edcd2 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java @@ -175,7 +175,7 @@ class SaveManyPropRequest { if (detailBean instanceof EntityBean) { EntityBean detail = (EntityBean) detailBean; EntityBeanIntercept ebi = detail._ebean_getIntercept(); - if (many.isManyToMany()) { + if (many.hasJoinTable()) { skipSavingThisBean = targetDescriptor.isReference(ebi); } else { if (orderColumn != null) { diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index a041c49c2..22a3be01d 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -12,8 +12,8 @@ import io.ebeaninternal.api.SpiQuery.Mode; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.InheritInfo; @@ -597,7 +597,7 @@ class SqlTreeNodeBean implements SqlTreeNode { if (nodeBeanProp instanceof BeanPropertyAssocMany) { BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) nodeBeanProp; - if (manyProp.isManyToMany()) { + if (manyProp.hasJoinTable()) { String alias = ctx.getTableAlias(prefix); String[] split = SplitName.split(prefix); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index 93d664c79..d6d642166 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -105,7 +105,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { if (assocBeanProperty instanceof BeanPropertyAssocMany) { BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) assocBeanProperty; - if (manyProp.isManyToMany()) { + if (manyProp.hasJoinTable()) { manyToMany = true; diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index 3ec80cbab..07ab86398 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -96,7 +96,7 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode { } else { BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) nodeBeanProp; - if (!manyProp.isManyToMany()) { + if (!manyProp.hasJoinTable()) { manyProp.addJoin(joinType, parentAlias, alias, ctx); } else { diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index effac9205..a7cbb0644 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -40,7 +40,7 @@ public abstract class BaseTestCase { * Return the generated sql trimming column alias if required. */ protected String sqlOf(Query query) { - return trimSql(query.getGeneratedSql(), 0); + return trimSql(query.getGeneratedSql()); } /** @@ -50,6 +50,15 @@ public abstract class BaseTestCase { return trimSql(query.getGeneratedSql(), columns); } + protected String trimSql(String sql) { + + if (sql.contains(" c1,")) { + // for oracle we include column alias so lets remove those + return trimSql(sql, 10); + } + return trimSql(sql, 0); + } + /** * Trim out column alias if required from the generated sql. */ diff --git a/src/test/java/org/tests/o2m/jointable/JtMonkey.java b/src/test/java/org/tests/o2m/jointable/JtMonkey.java new file mode 100644 index 000000000..eda26cf3d --- /dev/null +++ b/src/test/java/org/tests/o2m/jointable/JtMonkey.java @@ -0,0 +1,57 @@ +package org.tests.o2m.jointable; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.Version; + +@Entity +@Table(name="monkey") +public class JtMonkey { + + @Id + long mid; + + String name; + + String foodPreference; + + @Version + long version; + + public JtMonkey(String name) { + this.name = name; + } + + public long getMid() { + return mid; + } + + public void setMid(long mid) { + this.mid = mid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFoodPreference() { + return foodPreference; + } + + public void setFoodPreference(String foodPreference) { + this.foodPreference = foodPreference; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/o2m/jointable/JtTrainer.java b/src/test/java/org/tests/o2m/jointable/JtTrainer.java new file mode 100644 index 000000000..66a2e3474 --- /dev/null +++ b/src/test/java/org/tests/o2m/jointable/JtTrainer.java @@ -0,0 +1,66 @@ +package org.tests.o2m.jointable; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Version; +import java.util.List; + +@Entity +@Table(name="trainer") +public class JtTrainer { + + @Id + long tid; + + String name; + + /** + * Cascade so maintain join table and save any dirty Monkey beans. + */ + @OneToMany(cascade = CascadeType.PERSIST) + @JoinTable(name = "trainer_monkey") + List monkeys; + + @Version + long version; + + public JtTrainer(String name) { + this.name = name; + } + + public long getTid() { + return tid; + } + + public void setTid(long tid) { + this.tid = tid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getMonkeys() { + return monkeys; + } + + public void setMonkeys(List monkeys) { + this.monkeys = monkeys; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/o2m/jointable/JtTroop.java b/src/test/java/org/tests/o2m/jointable/JtTroop.java new file mode 100644 index 000000000..06a4b79eb --- /dev/null +++ b/src/test/java/org/tests/o2m/jointable/JtTroop.java @@ -0,0 +1,65 @@ +package org.tests.o2m.jointable; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Version; +import java.util.List; + +@Entity +@Table(name="troop") +public class JtTroop { + + @Id + long pid; + + String name; + + /** + * No cascading over to Monkey but we do maintain the join table regardless. + */ + @OneToMany + @JoinTable(name = "troop_monkey") + List monkeys; + + @Version + long version; + + public JtTroop(String name) { + this.name = name; + } + + public long getPid() { + return pid; + } + + public void setPid(long pid) { + this.pid = pid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getMonkeys() { + return monkeys; + } + + public void setMonkeys(List monkeys) { + this.monkeys = monkeys; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java new file mode 100644 index 000000000..dd7f6b6c1 --- /dev/null +++ b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java @@ -0,0 +1,115 @@ +package org.tests.o2m.jointable; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToManyJoinTable extends BaseTestCase { + + private JtTroop troop = new JtTroop("Blue"); + + private JtMonkey m0 = new JtMonkey("Sim"); + private JtMonkey m1 = new JtMonkey("Tim"); + private JtMonkey m2 = new JtMonkey("Uim"); + + private void initialInsert() { + Ebean.saveAll(Arrays.asList(troop, m0, m1, m2)); + } + + @Test + public void base() { + + initialInsert(); + + LoggedSqlCollector.start(); + + // make m0 dirty ... but no cascade saved? + m0.setFoodPreference("banana"); + troop.getMonkeys().add(m0); + troop.getMonkeys().add(m1); + + Ebean.save(troop); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)"); + + int intersectionRows = Ebean.createSqlQuery("select count(*) as total from troop_monkey where troop_pid = ?") + .setParameter(1, troop.getPid()) + .findOne() + .getInteger("total"); + + assertThat(intersectionRows).isEqualTo(2); + + LoggedSqlCollector.current(); + JtTroop fetchTroop = Ebean.find(JtTroop.class) + .fetch("monkeys") + .where().idEq(troop.getPid()) + .findOne(); + + assertThat(fetchTroop.getMonkeys()).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(trimSql(sql.get(0))).contains("from troop t0 left join troop_monkey t1z_ on t1z_.troop_pid = t0.pid left join monkey t1 on t1.mid = t1z_.monkey_mid where t0.pid = ?"); + assertThat(trimSql(sql.get(0))).contains("select t0.pid, t0.name, t0.version, t1.mid, t1.name, t1.food_preference, t1.version"); + + Ebean.delete(troop); + + sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from troop_monkey where troop_pid = ?"); + assertThat(sql.get(1)).contains("delete from troop where pid=? and version=?"); + + + insertWithCascade(); + } + + private void insertWithCascade() { + + JtTrainer trainer = new JtTrainer("Frank"); + + // make m2 dirty ... cascades to an update on Uim + m2.setFoodPreference("Apple"); + trainer.getMonkeys().add(m2); + trainer.getMonkeys().add(Ebean.getReference(JtMonkey.class, m1.getMid())); + trainer.getMonkeys().add(new JtMonkey("FAlp")); + trainer.getMonkeys().add(new JtMonkey("FBet")); + trainer.getMonkeys().add(new JtMonkey("FThe")); + + LoggedSqlCollector.start(); + Ebean.save(trainer); + + List sql = LoggedSqlCollector.current(); + + assertThat(sql).hasSize(6); + assertThat(sql.get(0)).contains("insert into trainer "); + assertThat(sql.get(1)).contains("insert into monkey "); + assertThat(sql.get(4)).contains("update monkey set name=?, food_preference=?, version=? where mid=? and version=?"); + assertThat(sql.get(5)).contains("insert into trainer_monkey "); + + + int intersectionRows = Ebean.createSqlQuery("select count(*) as total from trainer_monkey where trainer_tid = ?") + .setParameter(1, trainer.getTid()) + .findOne() + .getInteger("total"); + + assertThat(intersectionRows).isEqualTo(5); + + + LoggedSqlCollector.current(); + Ebean.delete(trainer); + + sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from trainer_monkey where trainer_tid = ?"); + assertThat(sql.get(1)).contains("delete from trainer where tid=?"); + + } +} From 3e8b06e38ea9864cec2d5fe7c6405ce1ce29c8b0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Feb 2018 16:59:55 +1300 Subject: [PATCH 0041/1036] #994 - @OneToOne cacade does not honor orphanRemoval = true --- .../server/core/PersistRequestBean.java | 16 +++- .../server/deploy/BeanPropertyAssocOne.java | 7 ++ .../meta/DeployBeanPropertyAssocOne.java | 10 +++ .../deploy/parse/AnnotationAssocOnes.java | 1 + .../server/persist/DefaultPersister.java | 9 +++ .../org/tests/model/onetoone/OtoCust.java | 61 +++++++++++++++ .../tests/model/onetoone/OtoCustAddress.java | 76 +++++++++++++++++++ .../onetoone/TestOneToOneOrphanRemove.java | 50 ++++++++++++ 8 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/tests/model/onetoone/OtoCust.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoCustAddress.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 3cfca39d7..6160691c2 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -11,8 +11,8 @@ import io.ebean.event.BeanPersistRequest; import io.ebean.event.changelog.BeanChange; import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.SpiProfileTransactionEvent; +import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.TransactionEvent; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.deploy.BeanDescriptor; @@ -713,6 +713,20 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return intercept.isLoadedProperty(prop.getPropertyIndex()); } + /** + * Return true if the property is dirty. + */ + public boolean isDirtyProperty(BeanProperty prop) { + return intercept.isDirtyProperty(prop.getPropertyIndex()); + } + + /** + * Return the original / old value for the given property. + */ + public Object getOrigValue(BeanProperty prop) { + return intercept.getOrigValue(prop.getPropertyIndex()); + } + @Override public int executeNow() { if (getterCallback) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 04e953aca..df0a7b8ae 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -37,6 +37,8 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { private final boolean oneToOneExported; + private final boolean orphanRemoval; + private final boolean importedPrimaryKey; private final boolean primaryKeyExport; @@ -76,6 +78,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { importedPrimaryKey = deploy.isImportedPrimaryKey(); oneToOne = deploy.isOneToOne(); oneToOneExported = deploy.isOneToOneExported(); + orphanRemoval = deploy.isOrphanRemoval(); if (embedded) { // Overriding of the columns and use table alias of owning BeanDescriptor @@ -338,6 +341,10 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { return oneToOneExported; } + public boolean isOrphanRemoval() { + return orphanRemoval; + } + /** * If true this bean maps to the primary key. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index 93c57efb7..021f5e2f8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -25,6 +25,8 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { private PropertyForeignKey foreignKey; + private boolean orphanRemoval; + /** * Create the property. */ @@ -160,4 +162,12 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { public PropertyForeignKey getForeignKey() { return foreignKey; } + + public void setOrphanRemoval(boolean orphanRemoval) { + this.orphanRemoval = orphanRemoval; + } + + public boolean isOrphanRemoval() { + return orphanRemoval; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 15a3ed4de..872d97c0d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -216,6 +216,7 @@ public class AnnotationAssocOnes extends AnnotationParser { prop.setMappedBy(propAnn.mappedBy()); if (!"".equals(propAnn.mappedBy())) { prop.setOneToOneExported(); + prop.setOrphanRemoval(propAnn.orphanRemoval()); } setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo()); diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 41cce82bf..48538582a 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -1173,6 +1173,15 @@ public final class DefaultPersister implements Persister { } } } + + for (BeanPropertyAssocOne prop : desc.propertiesOneExportedSave()) { + if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) { + Object origValue = request.getOrigValue(prop); + if (origValue instanceof EntityBean) { + delete((EntityBean) origValue, request.getTransaction(), true); + } + } + } } /** diff --git a/src/test/java/org/tests/model/onetoone/OtoCust.java b/src/test/java/org/tests/model/onetoone/OtoCust.java new file mode 100644 index 000000000..50f5efad6 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoCust.java @@ -0,0 +1,61 @@ +package org.tests.model.onetoone; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class OtoCust { + + @Id + long cid; + + String name; + + /** + * Orphan removal so must delete 'old' address when it has been replace or set to null. + */ + @OneToOne(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true) + OtoCustAddress address; + + @Version + long version; + + public OtoCust(String name) { + this.name = name; + } + + public long getCid() { + return cid; + } + + public void setCid(long cid) { + this.cid = cid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public OtoCustAddress getAddress() { + return address; + } + + public void setAddress(OtoCustAddress address) { + this.address = address; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/OtoCustAddress.java b/src/test/java/org/tests/model/onetoone/OtoCustAddress.java new file mode 100644 index 000000000..25bba8431 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoCustAddress.java @@ -0,0 +1,76 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class OtoCustAddress { + + @Id + long aid; + + String line1; + String line2; + String line3; + + @OneToOne + OtoCust customer; + + @Version + long version; + + public OtoCustAddress(String line1, String line2) { + this.line1 = line1; + this.line2 = line2; + } + + public long getAid() { + return aid; + } + + public void setAid(long aid) { + this.aid = aid; + } + + public OtoCust getCustomer() { + return customer; + } + + public void setCustomer(OtoCust customer) { + this.customer = customer; + } + + public String getLine1() { + return line1; + } + + public void setLine1(String line1) { + this.line1 = line1; + } + + public String getLine2() { + return line2; + } + + public void setLine2(String line2) { + this.line2 = line2; + } + + public String getLine3() { + return line3; + } + + public void setLine3(String line3) { + this.line3 = line3; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java new file mode 100644 index 000000000..8ab94707e --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java @@ -0,0 +1,50 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOneOrphanRemove extends BaseTestCase { + + @Test + public void base() { + + OtoCust jack = new OtoCust("Jack"); + + OtoCustAddress address = new OtoCustAddress("line1", "line2"); + + jack.setAddress(address); + Ebean.save(jack); + + // set new address + OtoCustAddress address2 = new OtoCustAddress("other1", "other2"); + jack.setAddress(address2); + + // Fail do to uniqueness constraint + LoggedSqlCollector.start(); + Ebean.save(jack); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("delete from oto_cust_address where aid=? and version=?"); + assertThat(sql.get(1)).contains("update oto_cust set version=? where cid=? and version=?"); + assertThat(sql.get(2)).contains("insert into oto_cust_address (line1, line2, line3, version, customer_cid)"); + + jack.setAddress(null); + Ebean.save(jack); + + sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from oto_cust_address where aid=? and version=?"); + assertThat(sql.get(1)).contains("update oto_cust set version=? where cid=? and version=?"); + + OtoCustAddress foundAddress = Ebean.find(OtoCustAddress.class, address2.getAid()); + assertThat(foundAddress).isNull(); + } + +} From 0b1c3a4233f553cfbc8109b483a203d977a6b854 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 21 Feb 2018 09:44:07 +1300 Subject: [PATCH 0042/1036] Bump version to 11.11.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b5f9956c8..28d25e71c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.10.7-SNAPSHOT + 11.11.1-SNAPSHOT jar ebean From eaa48468cdacbaec6d0692481955c8ead5f3c5bb Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 21 Feb 2018 09:44:37 +1300 Subject: [PATCH 0043/1036] #1174 - ENH: Support mapping @TenantId to an entity bean via @ManyToOne --- .../server/core/PersistRequestBean.java | 2 +- .../server/deploy/BeanDescriptor.java | 27 +++++++++++++++++-- .../server/deploy/BeanProperty.java | 17 +++++++++++- .../server/deploy/BeanPropertyAssocMany.java | 2 +- .../server/deploy/BeanPropertyAssocOne.java | 13 ++++++++- .../deploy/meta/DeployBeanPropertyLists.java | 5 ++-- .../deploy/parse/AnnotationAssocOnes.java | 4 +++ .../server/persist/DefaultPersister.java | 2 +- .../server/deploy/BeanDescriptorTest.java | 5 +++- 9 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 6160691c2..8c0113b1e 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -642,7 +642,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP * Create and return a new reference bean matching this beans Id value. */ public T createReference() { - return beanDescriptor.createReference(Boolean.FALSE, false, getBeanId(), null); + return beanDescriptor.createReference(getBeanId(), null); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 1c34a0783..87161ce55 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1204,7 +1204,7 @@ public class BeanDescriptor implements BeanType { if (tenant != null && !query.isNativeSql()) { Object tenantId = ebeanServer.currentTenantId(); if (tenantId != null) { - query.where().eq(tenant.getName(), tenantId); + tenant.addTenant(query, tenantId); } } if (isDocStoreOnly()) { @@ -1872,6 +1872,29 @@ public class BeanDescriptor implements BeanType { } } + /** + * Create a non read only reference bean without checking cacheSharableBeans. + */ + @SuppressWarnings("unchecked") + public T createReference(Object id, PersistenceContext pc) { + + try { + EntityBean eb = createEntityBean(); + id = convertSetId(id, eb); + EntityBeanIntercept ebi = eb._ebean_getIntercept(); + ebi.setBeanLoader(ebeanServer); + ebi.setReference(idPropertyIndex); + if (pc != null) { + contextPut(pc, id, eb); + ebi.setPersistenceContext(pc); + } + return (T) eb; + + } catch (Exception ex) { + throw new PersistenceException(ex); + } + } + /** * Return the bean property traversing the object graph and taking into * account inheritance. @@ -2725,7 +2748,7 @@ public class BeanDescriptor implements BeanType { */ public void setTenantId(EntityBean entityBean, Object tenantId) { if (tenant != null) { - tenant.setValue(entityBean, tenantId); + tenant.setTenantValue(entityBean, tenantId); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 05f1d8d70..03b4bb2bd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -9,8 +9,10 @@ import io.ebean.config.dbplatform.DbEncryptFunction; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.plugin.Property; import io.ebean.text.StringParser; +import io.ebean.util.SplitName; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedWhenCreated; @@ -20,7 +22,6 @@ import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.properties.BeanPropertyGetter; import io.ebeaninternal.server.properties.BeanPropertySetter; -import io.ebean.util.SplitName; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; import io.ebeaninternal.server.text.json.ReadJson; @@ -720,6 +721,20 @@ public class BeanProperty implements ElPropertyValue, Property { bean._ebean_getIntercept().setChangedProperty(propertyIndex); } + /** + * Add the tenantId predicate to the query. + */ + public void addTenant(SpiQuery query, Object tenantId) { + query.where().eq(name, tenantId); + } + + /** + * Set the tenantId onto the bean. + */ + public void setTenantValue(EntityBean entityBean, Object tenantId) { + setValue(entityBean, tenantId); + } + /** * Set the value of the property without interception or * PropertyChangeSupport. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 7c2f3cc08..c58c658db 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -967,7 +967,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { if (isManyToMany()) { if (liveBean == null) { // add new relationship (Map not allowed here) - liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, false, id, null)); + liveVal.addBean(targetDescriptor.createReference(id, null)); } } else { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index df0a7b8ae..584f0fbfb 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -8,6 +8,7 @@ import io.ebean.ValuePair; import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; import io.ebean.util.SplitName; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.cache.CachedBeanData; import io.ebeaninternal.server.core.DefaultSqlUpdate; @@ -419,7 +420,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { // cacheData is the id value, maybe already in persistence context Object assocBean = targetDescriptor.contextGet(context, cacheData); if (assocBean == null) { - assocBean = targetDescriptor.createReference(Boolean.FALSE, false, cacheData, context); + assocBean = targetDescriptor.createReference(cacheData, context); } setValue(bean, assocBean); } @@ -605,6 +606,16 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { return localHelp.read(ctx); } + public void addTenant(SpiQuery query, Object tenantId) { + T refBean = targetDescriptor.createReference(tenantId, null); + query.where().eq(name, refBean); + } + + public void setTenantValue(EntityBean entityBean, Object tenantId) { + T refBean = targetDescriptor.createReference(tenantId, null); + setValue(entityBean, refBean); + } + @Override public void setValue(EntityBean bean, Object value) { super.setValue(bean, value); diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index b67093ec3..8c849e76b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -207,6 +207,9 @@ public class DeployBeanPropertyLists { } else { nonManys.add(prop); + if (prop.isTenantId()) { + tenant = prop; + } if (prop instanceof BeanPropertyAssocOne) { BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne) prop; if (prop.isEmbedded()) { @@ -227,8 +230,6 @@ public class DeployBeanPropertyLists { } } else if (prop.isDraftDirty()) { draftDirty = prop; - } else if (prop.isTenantId()) { - tenant = prop; } if (!prop.isAggregation()) { baseScalar.add(prop); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 872d97c0d..7c614dee6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.parse; import io.ebean.annotation.DbForeignKey; import io.ebean.annotation.FetchPreference; +import io.ebean.annotation.TenantId; import io.ebean.annotation.Where; import io.ebean.config.NamingConvention; import io.ebeaninternal.server.deploy.BeanDescriptorManager; @@ -63,6 +64,9 @@ public class AnnotationAssocOnes extends AnnotationParser { ManyToOne manyToOne = get(prop, ManyToOne.class); if (manyToOne != null) { readManyToOne(manyToOne, prop); + if (get(prop, TenantId.class) != null) { + prop.setTenantId(); + } } OneToOne oneToOne = get(prop, OneToOne.class); if (oneToOne != null) { diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 48538582a..bc6a5cfe8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -1138,7 +1138,7 @@ public final class DefaultPersister implements Persister { // convert into a list of reference objects and perform delete by object List refList = new ArrayList<>(childIds.size()); for (Object id : childIds) { - refList.add(targetDesc.createReference(null, false, id, null)); + refList.add(targetDesc.createReference(id, null)); } deleteList(refList, t, softDelete); diff --git a/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java b/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java index 795ffe6f4..fa9762127 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/BeanDescriptorTest.java @@ -3,9 +3,9 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; import io.ebean.bean.EntityBean; import io.ebean.plugin.Property; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.Order; -import org.junit.Test; import java.util.Collection; @@ -35,6 +35,9 @@ public class BeanDescriptorTest extends BaseTestCase { Customer bean = customerDesc.createReference(Boolean.FALSE, false, 42, null); assertThat(server().getBeanState(bean).isReadOnly()).isFalse(); + + bean = customerDesc.createReference(42, null); + assertThat(server().getBeanState(bean).isReadOnly()).isFalse(); } @Test From 83384c6f0e3f87d2f9dd458674f86eef58fe4a36 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 21 Feb 2018 11:04:04 +1300 Subject: [PATCH 0044/1036] #323 - DDL Generation support for foreign key cascade options Tidy up, no GLOBAL_DEFAULT. --- pom.xml | 2 +- .../dbmigration/ddlgeneration/platform/PlatformDdl.java | 2 +- .../io/ebeaninternal/server/deploy/PropertyForeignKey.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 28d25e71c..1a19a7abd 100644 --- a/pom.xml +++ b/pom.xml @@ -103,7 +103,7 @@ io.ebean ebean-annotation - 3.7 + 3.8 diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index 3088e49c1..55057bddf 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -389,7 +389,7 @@ public class PlatformDdl { } protected ConstraintMode withDefault(ConstraintMode mode) { - return (mode == null || mode == ConstraintMode.GLOBAL_DEFAULT) ? ConstraintMode.RESTRICT : mode; + return (mode == null) ? ConstraintMode.RESTRICT : mode; } protected void appendForeignKeyOnDelete(StringBuilder buffer, ConstraintMode mode) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java index 8badce0ce..480362e2a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java +++ b/src/main/java/io/ebeaninternal/server/deploy/PropertyForeignKey.java @@ -16,8 +16,8 @@ public class PropertyForeignKey { public PropertyForeignKey() { this.noConstraint = true; this.noIndex = false; - this.onDelete = ConstraintMode.GLOBAL_DEFAULT; - this.onUpdate = ConstraintMode.GLOBAL_DEFAULT; + this.onDelete = ConstraintMode.RESTRICT; + this.onUpdate = ConstraintMode.RESTRICT; } /** From 4d122ea05be13b6f960262525cec89ada54dd90d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:09:53 +1300 Subject: [PATCH 0045/1036] #1267 - DDL issue on @OneToMany @JoinTable ... extra unnecessary index created on fk column --- .../java/io/ebeaninternal/dbmigration/model/MTable.java | 8 ++++++++ .../model/build/ModelBuildPropertyVisitor.java | 1 + 2 files changed, 9 insertions(+) diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index 7e02a0e03..a92408496 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -656,4 +656,12 @@ public class MTable { return draftTableName + "." + references.substring(lastDot + 1); } + /** + * Clear the indexes on the foreign keys as they are covered by unique constraints. + */ + public void clearForeignKeyIndexes() { + for (MCompoundForeignKey compoundKey : compoundKeys) { + compoundKey.setIndexName(null); + } + } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index 8d9f64be5..f6a939d1a 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -133,6 +133,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { // in the middle of rendering the create table DDL MTable intersectionTable = new ModelBuildIntersectionTable(ctx, p).build(); if (p.isO2mJoinTable()) { + intersectionTable.clearForeignKeyIndexes(); Collection cols = intersectionTable.allColumns(); if (cols.size() == 2) { // always the second column that we put the unique constraint on From dd907cc4bc9aa138365e79f1a0b458ce615367ec Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:10:59 +1300 Subject: [PATCH 0046/1036] Test only change - fix keys for testing against Oracle --- src/test/java/org/tests/compositekeys/db/ItemKey.java | 4 ++-- src/test/java/org/tests/model/composite/ROrderPK.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/tests/compositekeys/db/ItemKey.java b/src/test/java/org/tests/compositekeys/db/ItemKey.java index 0f4589612..adc176769 100644 --- a/src/test/java/org/tests/compositekeys/db/ItemKey.java +++ b/src/test/java/org/tests/compositekeys/db/ItemKey.java @@ -7,11 +7,11 @@ import javax.validation.constraints.Size; @Embeddable public class ItemKey { - @Size(max=127) + private int customer; @Column(name = "itemnumber") - @Size(max=127) + @Size(max = 127) private String itemNumber; public int getCustomer() { diff --git a/src/test/java/org/tests/model/composite/ROrderPK.java b/src/test/java/org/tests/model/composite/ROrderPK.java index 2c808d82b..3952899e2 100644 --- a/src/test/java/org/tests/model/composite/ROrderPK.java +++ b/src/test/java/org/tests/model/composite/ROrderPK.java @@ -1,10 +1,9 @@ package org.tests.model.composite; -import java.io.Serializable; - import javax.persistence.Embeddable; import javax.validation.constraints.Size; +import java.io.Serializable; /** * @author rnentjes @@ -16,7 +15,6 @@ public class ROrderPK implements Serializable { @Size(max=127) private String company; - @Size(max=127) private Integer orderNumber; public ROrderPK() { From 20bd2241e4b471116361a855e2b0c68a1429529c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:11:36 +1300 Subject: [PATCH 0047/1036] Test only change - fix test assert to support sequence and identity insert --- .../java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java index 8ab94707e..3dca53db0 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanRemove.java @@ -33,7 +33,7 @@ public class TestOneToOneOrphanRemove extends BaseTestCase { assertThat(sql).hasSize(3); assertThat(sql.get(0)).contains("delete from oto_cust_address where aid=? and version=?"); assertThat(sql.get(1)).contains("update oto_cust set version=? where cid=? and version=?"); - assertThat(sql.get(2)).contains("insert into oto_cust_address (line1, line2, line3, version, customer_cid)"); + assertThat(sql.get(2)).contains("insert into oto_cust_address "); jack.setAddress(null); Ebean.save(jack); From f2d438f21af8f671813dadb3b33ce6de5ad17702 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:11:56 +1300 Subject: [PATCH 0048/1036] Test only change - fix test assert for sql server --- src/test/java/org/tests/query/finder/TestCustomerFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/src/test/java/org/tests/query/finder/TestCustomerFinder.java index 554c6c9a1..bfd51e476 100644 --- a/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -154,7 +154,7 @@ public class TestCustomerFinder extends BaseTestCase { Customer.find.byId(3); List planStats = metaInfoManager.collectQueryPlanStatistics(true); - assertThat(planStats).hasSize(6); + assertThat(planStats.size()).isGreaterThan(4); for (MetaQueryPlanStatistic planStat : planStats) { System.out.println(planStat); From ec7b376612e1277283bc40256fba8f455c735b5d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:12:30 +1300 Subject: [PATCH 0049/1036] Test only change - fix test assert for sql server --- src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java index e88673a5f..9b97f5888 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java @@ -58,7 +58,7 @@ public class DbMigrationTest extends BaseTestCase { } } - @IgnorePlatform(Platform.ORACLE) + @IgnorePlatform({Platform.ORACLE, Platform.SQLSERVER}) @Test public void testRunMigration() throws IOException { // first clean up previously created objects From 8ee68ac5e1f860444296f8b9ed6187d5c5b78634 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:40:22 +1300 Subject: [PATCH 0050/1036] #1269 - Paging queries should not ALWAYS append an order by ID ... but only when the order by is empty --- .../server/deploy/BeanDescriptor.java | 13 ++++--------- .../ebeaninternal/server/query/CQueryEngine.java | 2 +- .../server/querydefn/DefaultOrmQuery.java | 9 +++++++++ src/test/java/io/ebean/EbeanServer_eqlTest.java | 4 ++-- .../java/io/ebean/TestUnsetLoadedProperties.java | 9 +++++++-- .../query/TestAddOrderByWithFirstRowsMaxRows.java | 6 +++--- .../org/tests/query/TestLimitAlterFetchMany.java | 4 ++-- .../java/org/tests/rawsql/TestRawSqlOrmQuery.java | 15 ++++++++++----- 8 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 87161ce55..696fa5dbf 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.deploy; -import io.ebean.OrderBy; import io.ebean.PersistenceContextScope; import io.ebean.ProfileLocation; import io.ebean.Query; @@ -3055,14 +3054,10 @@ public class BeanDescriptor implements BeanType { public void appendOrderById(SpiQuery query) { if (idProperty != null && !idProperty.isEmbedded()) { - OrderBy orderBy = query.getOrderBy(); - if (orderBy == null || orderBy.isEmpty()) { - SpiRawSql rawSql = query.getRawSql(); - if (rawSql != null) { - query.order(rawSql.getSql().getOrderBy()); - } - query.order().asc(idProperty.getName()); - } else if (!orderBy.containsProperty(idProperty.getName())) { + SpiRawSql rawSql = query.getRawSql(); + if (rawSql != null) { + query.order(rawSql.getSql().getOrderBy()); + } else { query.order().asc(idProperty.getName()); } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java index 96b95bb46..541a6f1ab 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java @@ -333,7 +333,7 @@ public class CQueryEngine { */ private void prepareForPaging(OrmQueryRequest request) { SpiQuery query = request.getQuery(); - if (!query.isDistinct() && (query.getMaxRows() > 1 || query.getFirstRow() > 0)) { + if (query.checkPagingOrderBy()) { request.getBeanDescriptor().appendOrderById(query); } } diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index a2cb55362..bc14d10d7 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1372,6 +1372,15 @@ public class DefaultOrmQuery implements SpiQuery { return this; } + @Override + public boolean checkPagingOrderBy() { + return (maxRows > 1 || firstRow > 0) && !distinct && orderByIsEmpty(); + } + + private boolean orderByIsEmpty() { + return orderBy == null || orderBy.isEmpty(); + } + @Override public OrderBy getOrderBy() { return orderBy; diff --git a/src/test/java/io/ebean/EbeanServer_eqlTest.java b/src/test/java/io/ebean/EbeanServer_eqlTest.java index a31f87a03..42dfc0905 100644 --- a/src/test/java/io/ebean/EbeanServer_eqlTest.java +++ b/src/test/java/io/ebean/EbeanServer_eqlTest.java @@ -78,12 +78,12 @@ public class EbeanServer_eqlTest extends BaseTestCase { query.findList(); if (isSqlServer()) { - assertThat(query.getGeneratedSql()).endsWith("order by t0.name, t0.id offset 3 rows fetch next 10 rows only"); + assertThat(query.getGeneratedSql()).endsWith("order by t0.name offset 3 rows fetch next 10 rows only"); } else if (isOracle()) { assertThat(query.getGeneratedSql()).contains("where rownum <= 13"); assertThat(query.getGeneratedSql()).contains("where rn_ > 3"); } else { - assertThat(query.getGeneratedSql()).endsWith("order by t0.name, t0.id limit 10 offset 3"); + assertThat(query.getGeneratedSql()).endsWith("order by t0.name limit 10 offset 3"); } } diff --git a/src/test/java/io/ebean/TestUnsetLoadedProperties.java b/src/test/java/io/ebean/TestUnsetLoadedProperties.java index 29f720785..5f6b58f97 100644 --- a/src/test/java/io/ebean/TestUnsetLoadedProperties.java +++ b/src/test/java/io/ebean/TestUnsetLoadedProperties.java @@ -1,9 +1,11 @@ package io.ebean; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; import io.ebean.bean.EntityBean; -import org.tests.model.converstation.User; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; +import org.tests.model.converstation.User; import java.util.List; @@ -41,7 +43,6 @@ public class TestUnsetLoadedProperties extends BaseTestCase { List loggedSql = LoggedSqlCollector.stop(); assertThat(loggedSql).hasSize(1); assertThat(loggedSql.get(0)).doesNotContain("email"); - } @Test @@ -95,6 +96,10 @@ public class TestUnsetLoadedProperties extends BaseTestCase { assertThat(beanState.getLoadedProps()).containsExactly("id", "name"); } + /** + * Strange sql server error that needs to be reviewed. + */ + @IgnorePlatform(Platform.SQLSERVER) @Test public void test_markVersionUnset_expect_no_optimistic_locking() { diff --git a/src/test/java/org/tests/query/TestAddOrderByWithFirstRowsMaxRows.java b/src/test/java/org/tests/query/TestAddOrderByWithFirstRowsMaxRows.java index 179a8b1bb..b6a9d0a01 100644 --- a/src/test/java/org/tests/query/TestAddOrderByWithFirstRowsMaxRows.java +++ b/src/test/java/org/tests/query/TestAddOrderByWithFirstRowsMaxRows.java @@ -3,10 +3,10 @@ package org.tests.query; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.PagedList; -import org.tests.model.basic.Order; -import org.tests.model.basic.ResetBasicData; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; +import org.tests.model.basic.Order; +import org.tests.model.basic.ResetBasicData; import java.util.List; @@ -148,7 +148,7 @@ public class TestAddOrderByWithFirstRowsMaxRows extends BaseTestCase { List loggedSql = LoggedSqlCollector.stop(); assertThat(loggedSql).hasSize(1); - assertThat(loggedSql.get(0)).contains("order by t0.order_date, t0.id"); + assertThat(loggedSql.get(0)).contains("order by t0.order_date"); } @Test diff --git a/src/test/java/org/tests/query/TestLimitAlterFetchMany.java b/src/test/java/org/tests/query/TestLimitAlterFetchMany.java index e0b5d4d2d..43bf9b7d2 100644 --- a/src/test/java/org/tests/query/TestLimitAlterFetchMany.java +++ b/src/test/java/org/tests/query/TestLimitAlterFetchMany.java @@ -3,9 +3,9 @@ package org.tests.query; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import org.junit.Test; import java.util.List; @@ -24,7 +24,7 @@ public class TestLimitAlterFetchMany extends BaseTestCase { Query query = Ebean.find(Customer.class) // this will automatically get converted to a // query join ... due to the maxRows - .fetch("contacts").setMaxRows(5); + .fetch("contacts").setMaxRows(5).orderBy("id"); List list = query.findList(); diff --git a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java index 8023476b1..5a9d4dd33 100644 --- a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java +++ b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java @@ -104,6 +104,8 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.setFirstRow(1); query.setMaxRows(2); + query.order().asc("id"); + List list = query.findList(); int rowCount = query.findCount(); @@ -168,11 +170,11 @@ public class TestRawSqlOrmQuery extends BaseTestCase { if (isSqlServer()) { assertThat(query.getGeneratedSql()).contains("top 100 "); - assertThat(query.getGeneratedSql()).contains("order by o.ship_date desc, o.id"); + assertThat(query.getGeneratedSql()).contains("order by o.ship_date desc"); } else if (isOracle()) { assertThat(query.getGeneratedSql()).contains("a where rownum <= 100 )"); } else { - assertThat(query.getGeneratedSql()).contains("order by o.ship_date desc, o.id limit 100"); + assertThat(query.getGeneratedSql()).contains("order by o.ship_date desc limit 100"); } } @@ -197,14 +199,14 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.order("coalesce(shipDate, getdate()) desc"); query.findList(); - assertThat(sqlOf(query)).contains("order by coalesce(o.ship_date, getdate()) desc, o.id"); + assertThat(sqlOf(query)).contains("order by coalesce(o.ship_date, getdate()) desc"); assertThat(sqlOf(query)).contains("select top 100"); } else { query.order("coalesce(shipDate, now()) desc"); query.findList(); - assertThat(query.getGeneratedSql()).contains("order by coalesce(o.ship_date, now()) desc, o.id limit 100"); + assertThat(query.getGeneratedSql()).contains("order by coalesce(o.ship_date, now()) desc limit 100"); } } @@ -226,7 +228,10 @@ public class TestRawSqlOrmQuery extends BaseTestCase { query.order("id desc"); PagedList pagedList = query.findPagedList(); pagedList.getList(); - pagedList.getTotalCount(); + if (!isSqlServer()) { + // sql server doesn't support order by in the count query, I wonder if we can remove it? + pagedList.getTotalCount(); + } if (isSqlServer()) { assertThat(sqlOf(query)).contains("select top 100 "); From e3fac7c622497d987ccd32d83853bda0095f8bff Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:43:14 +1300 Subject: [PATCH 0051/1036] #1269 - Paging queries should not ALWAYS append an order by ID ... but only when the order by is empty --- src/main/java/io/ebeaninternal/api/SpiQuery.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index 426f450bb..2be96bfd9 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -588,6 +588,11 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { */ boolean isRawSql(); + /** + * Return true if the query should have an order by appended automatically. + */ + boolean checkPagingOrderBy(); + /** * Return the Order By clause or null if there is none defined. */ From f8ea5619d079cfccfd7069b6ecbf79bd8d2a9338 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:45:44 +1300 Subject: [PATCH 0052/1036] #1268 - SQL Server fix for "for update" plus Sequences support plus refactor of sequences --- .../java/io/ebean/config/ServerConfig.java | 21 +++ .../config/dbplatform/DatabasePlatform.java | 56 ++++-- .../dbplatform/SequenceBatchIdGenerator.java | 56 ++++++ .../dbplatform/SequenceIdGenerator.java | 177 +++++++----------- .../dbplatform/SequenceStepIdGenerator.java | 38 ++++ .../config/dbplatform/db2/DB2Platform.java | 5 +- .../db2/DB2SequenceIdGenerator.java | 4 +- .../config/dbplatform/h2/H2Platform.java | 6 +- .../dbplatform/h2/H2SequenceIdGenerator.java | 4 +- .../dbplatform/hsqldb/HsqldbPlatform.java | 5 +- .../dbplatform/mysql/MySqlPlatform.java | 13 -- .../dbplatform/oracle/OraclePlatform.java | 5 +- .../oracle/OracleSequenceIdGenerator.java | 4 +- .../dbplatform/postgres/PostgresPlatform.java | 4 +- .../postgres/PostgresSequenceIdGenerator.java | 4 +- .../sqlserver/SqlServerBasicSqlLimiter.java | 2 +- .../sqlserver/SqlServerPlatform.java | 50 ++++- .../sqlserver/SqlServerStepSequence.java | 24 +++ .../ddlgeneration/platform/PlatformDdl.java | 4 +- .../ddlgeneration/platform/SqlServerDdl.java | 4 +- .../server/core/DefaultContainer.java | 2 +- .../server/deploy/BeanDescriptorManager.java | 15 +- .../server/deploy/DbSqlContext.java | 5 + .../deploy/meta/DeployBeanDescriptor.java | 2 +- .../server/query/CQueryBuilder.java | 13 ++ .../server/query/DefaultDbSqlContext.java | 13 +- .../server/query/SqlTreeBuilder.java | 3 +- .../server/query/SqlTreeNodeRoot.java | 1 + .../java/io/ebeaninternal/util/JdbcClose.java | 14 ++ .../config/MatchingNamingConventionTest.java | 9 +- .../io/ebean/config/ServerConfigTest.java | 3 + .../sqlserver/SqlServerStepSequenceTest.java | 55 ++++++ 32 files changed, 439 insertions(+), 182 deletions(-) create mode 100644 src/main/java/io/ebean/config/dbplatform/SequenceBatchIdGenerator.java create mode 100644 src/main/java/io/ebean/config/dbplatform/SequenceStepIdGenerator.java create mode 100644 src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequence.java create mode 100644 src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequenceTest.java diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index a3f9348c9..4b17b276f 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -12,6 +12,7 @@ import io.ebean.cache.ServerCachePlugin; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbType; +import io.ebean.config.dbplatform.IdType; import io.ebean.event.BeanFindController; import io.ebean.event.BeanPersistController; import io.ebean.event.BeanPersistListener; @@ -181,6 +182,11 @@ public class ServerConfig { */ private DatabasePlatform databasePlatform; + /** + * The preferred IdType (to override the default Platform type). + */ + private IdType idType; + /** * For DB's using sequences this is the number of sequence values prefetched. */ @@ -1721,6 +1727,20 @@ public class ServerConfig { this.databasePlatform = databasePlatform; } + /** + * Return the preferred DB platform IdType. + */ + public IdType getIdType() { + return idType; + } + + /** + * Set the preferred DB platform IdType. + */ + public void setIdType(IdType idType) { + this.idType = idType; + } + /** * Return the EncryptKeyManager. */ @@ -2722,6 +2742,7 @@ public class ServerConfig { throw new IllegalArgumentException("Property 'batch.mode' or 'persistBatching' is being set but no longer used. Please change to use 'persistBatchMode'"); } + idType = p.getEnum(IdType.class, "idType", idType); persistBatch = p.getEnum(PersistBatch.class, "persistBatch", persistBatch); persistBatchOnCascade = p.getEnum(PersistBatch.class, "persistBatchOnCascade", persistBatchOnCascade); diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 3b6073c60..190e69d97 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -6,6 +6,8 @@ import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; import io.ebean.config.CustomDbTypeMapping; import io.ebean.config.DbTypeConfig; +import io.ebean.config.ServerConfig; +import io.ebeaninternal.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -98,6 +100,10 @@ public class DatabasePlatform { */ protected DbIdentity dbIdentity = new DbIdentity(); + protected boolean sequenceBatchMode = true; + + protected int sequenceBatchSize = 20; + /** * The history support for this database platform. */ @@ -206,10 +212,19 @@ public class DatabasePlatform { return exceptionTranslator.translate(message, e); } + /** + * Configure the platform given the server configuration. + */ + public void configure(ServerConfig config) { + this.sequenceBatchSize = config.getDatabaseSequenceBatchSize(); + configureIdType(config.getIdType()); + configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); + } + /** * Configure UUID Storage etc based on ServerConfig settings. */ - public void configure(DbTypeConfig config, boolean allQuotedIdentifiers) { + protected void configure(DbTypeConfig config, boolean allQuotedIdentifiers) { this.allQuotedIdentifiers = allQuotedIdentifiers; addGeoTypes(config.getGeometrySRID()); configureIdType(config.getIdType()); @@ -263,6 +278,20 @@ public class DatabasePlatform { return platform.name().toLowerCase(); } + /** + * Return true if we are using Sequence batch mode rather than STEP. + */ + public boolean isSequenceBatchMode() { + return sequenceBatchMode; + } + + /** + * Set to false to not use sequence batch mode but instead STEP mode. + */ + public void setSequenceBatchMode(boolean sequenceBatchMode) { + this.sequenceBatchMode = sequenceBatchMode; + } + /** * Return true if this database platform supports native ILIKE expression. */ @@ -304,10 +333,10 @@ public class DatabasePlatform { * @param be the BackgroundExecutor that can be used to load the sequence if * desired * @param ds the DataSource + * @param stepSize the sequence allocation size as defined by mapping (defaults to 50) * @param seqName the name of the sequence - * @param batchSize the number of sequences that should be loaded */ - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { return null; } @@ -586,6 +615,14 @@ public class DatabasePlatform { return sql; } + /** + * For update hint on the FROM clause (SQL server only). + */ + public String fromForUpdate(Query.ForUpdate forUpdateMode) { + // return null except for sql server + return null; + } + protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) { // silently assume the database does not support the "for update" clause. logger.info("it seems your database does not support the 'for update' clause"); @@ -618,18 +655,7 @@ public class DatabasePlatform { try { return tables.next(); } finally { - close(tables); - } - } - - /** - * Close the resultSet. - */ - protected void close(ResultSet resultSet) { - try { - resultSet.close(); - } catch (SQLException e) { - logger.error("Error closing resultSet", e); + JdbcClose.close(tables); } } diff --git a/src/main/java/io/ebean/config/dbplatform/SequenceBatchIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/SequenceBatchIdGenerator.java new file mode 100644 index 000000000..6444e0d55 --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/SequenceBatchIdGenerator.java @@ -0,0 +1,56 @@ +package io.ebean.config.dbplatform; + +import io.ebean.BackgroundExecutor; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Database sequence based IdGenerator using Sequence Step 1 but batch fetch many sequence values. + */ +public abstract class SequenceBatchIdGenerator extends SequenceIdGenerator { + + /** + * Construct where batchSize is the sequence step size. + * + */ + public SequenceBatchIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { + super(be, ds, seqName, batchSize); + } + + /** + * If allocateSize is large load some sequences in a background thread. + *

+ * For example, when inserting a bean with a cascade on a OneToMany with many + * beans Ebean can call this to ensure . + *

+ */ + @Override + public void preAllocateIds(int requestSize) { + if (allocationSize > 1 && requestSize > allocationSize) { + // only bother if allocateSize is bigger than + // the normal loading batchSize + if (requestSize > 100) { + // max out at 100 for now + requestSize = 100; + } + loadInBackground(requestSize); + } + } + + /** + * Add the next set of Ids as the next value plus all the following numbers up to the step size. + */ + protected List readIds(ResultSet resultSet, int loadSize) throws SQLException { + + List newIds = new ArrayList<>(loadSize); + while (resultSet.next()) { + newIds.add(resultSet.getLong(1)); + } + return newIds; + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java index 3d6da7357..985a545c6 100644 --- a/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java @@ -2,6 +2,7 @@ package io.ebean.config.dbplatform; import io.ebean.BackgroundExecutor; import io.ebean.Transaction; +import io.ebeaninternal.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,13 +13,15 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Database sequence based IdGenerator. */ public abstract class SequenceIdGenerator implements PlatformIdGenerator { - private static final Logger logger = LoggerFactory.getLogger(SequenceIdGenerator.class); + protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ"); /** * Used to synchronise the idList access. @@ -41,18 +44,18 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator { protected final ArrayList idList = new ArrayList<>(50); - protected final int batchSize; + protected final int allocationSize; - protected int currentlyBackgroundLoading; + protected boolean currentlyBackgroundLoading; /** * Construct given a dataSource and sql to return the next sequence value. */ - public SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { + protected SequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int allocationSize) { this.backgroundExecutor = be; this.dataSource = ds; this.seqName = seqName; - this.batchSize = batchSize; + this.allocationSize = allocationSize; } public abstract String getSql(int batchSize); @@ -81,26 +84,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator { *

*/ @Override - public void preAllocateIds(int allocateSize) { - if (batchSize > 1 && allocateSize > batchSize) { - // only bother if allocateSize is bigger than - // the normal loading batchSize - if (allocateSize > 100) { - // max out at 100 for now - allocateSize = 100; - } - loadLargeAllocation(allocateSize); - } - } - - /** - * Called by preAllocateIds when we know that a large number of Id's is going - * to be needed shortly. - */ - protected void loadLargeAllocation(final int allocateSize) { - // preAllocateIds was called with a relatively large batchSize - // so we will just go ahead and load those anyway in background - backgroundExecutor.execute(() -> loadMoreIds(allocateSize, null)); + public void preAllocateIds(int requestSize) { + // do nothing by default } /** @@ -113,80 +98,80 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator { public Object nextId(Transaction t) { synchronized (monitor) { - if (idList.isEmpty()) { - loadMoreIds(batchSize, t); - } - Long nextId = idList.remove(0); - - if (batchSize > 1) { - if (idList.size() <= batchSize / 2) { - loadBatchInBackground(); - } + int size = idList.size(); + if (size > 0) { + maybeLoadMoreInBackground(size); + } else { + loadMore(allocationSize); } - return nextId; + return idList.remove(0); } } - /** - * Load another batch of Id's using a background thread. - */ - protected void loadBatchInBackground() { - - // single threaded processing... - synchronized (backgroundLoadMonitor) { - - if (currentlyBackgroundLoading > 0) { - // skip as already background loading - logger.debug("... skip background sequence load (another load in progress)"); - return; + private void maybeLoadMoreInBackground(int currentSize) { + if (allocationSize > 1) { + if (currentSize <= allocationSize / 2) { + loadInBackground(allocationSize); } - - currentlyBackgroundLoading = batchSize; - - backgroundExecutor.execute(() -> { - loadMoreIds(batchSize, null); - synchronized (backgroundLoadMonitor) { - currentlyBackgroundLoading = 0; - } - }); } } - protected void loadMoreIds(final int numberToLoad, Transaction t) { - - ArrayList newIds = getMoreIds(numberToLoad, t); - - if (logger.isDebugEnabled()) { - logger.debug("... seq:" + seqName + " loaded:" + numberToLoad + " ids:" + newIds); - } - + private void loadMore(int requestSize) { + List newIds = getMoreIds(requestSize); synchronized (monitor) { idList.addAll(newIds); } } + /** + * Load another batch of Id's using a background thread. + */ + protected void loadInBackground(final int requestSize) { + + // single threaded processing... + synchronized (backgroundLoadMonitor) { + if (currentlyBackgroundLoading) { + // skip as already background loading + logger.debug("... skip background sequence load (another load in progress)"); + return; + } + + currentlyBackgroundLoading = true; + + backgroundExecutor.execute(() -> { + loadMore(requestSize); + synchronized (backgroundLoadMonitor) { + currentlyBackgroundLoading = false; + } + }); + } + } + + /** + * Read the resultSet returning the list of Id values. + */ + protected abstract List readIds(ResultSet resultSet, int loadSize) throws SQLException; + /** * Get more Id's by executing a query and reading the Id's returned. */ - protected ArrayList getMoreIds(int loadSize, Transaction t) { + protected List getMoreIds(int requestSize) { - String sql = getSql(loadSize); + String sql = getSql(requestSize); - ArrayList newIds = new ArrayList<>(loadSize); - - boolean useTxnConnection = t != null; - - Connection c = null; - PreparedStatement pstmt = null; - ResultSet rset = null; + Connection connection = null; + PreparedStatement statement = null; + ResultSet resultSet = null; try { - c = useTxnConnection ? t.getConnection() : dataSource.getConnection(); + connection = dataSource.getConnection(); - pstmt = c.prepareStatement(sql); - rset = pstmt.executeQuery(); - while (rset.next()) { - newIds.add(rset.getLong(1)); + statement = connection.prepareStatement(sql); + resultSet = statement.executeQuery(); + + List newIds = readIds(resultSet, requestSize); + if (logger.isTraceEnabled()) { + logger.trace("seq:{} loaded:{} sql:{}", seqName, newIds.size(), sql); } if (newIds.isEmpty()) { throw new PersistenceException("Always expecting more than 1 row from " + sql); @@ -197,46 +182,24 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator { } catch (SQLException e) { if (e.getMessage().contains("Database is already closed")) { String msg = "Error getting SEQ when DB shutting down " + e.getMessage(); - logger.info(msg); + logger.error(msg); System.out.println(msg); - return newIds; + return Collections.emptyList(); } else { throw new PersistenceException("Error getting sequence nextval", e); } } finally { - if (useTxnConnection) { - closeResources(null, pstmt, rset); - } else { - closeResources(c, pstmt, rset); - } + closeResources(connection, statement, resultSet); } } /** * Close the JDBC resources. */ - protected void closeResources(Connection c, PreparedStatement pstmt, ResultSet rset) { - try { - if (rset != null) { - rset.close(); - } - } catch (SQLException e) { - logger.error("Error closing ResultSet", e); - } - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } - try { - if (c != null) { - c.close(); - } - } catch (SQLException e) { - logger.error("Error closing Connection", e); - } + private void closeResources(Connection connection, PreparedStatement statement, ResultSet resultSet) { + JdbcClose.close(resultSet); + JdbcClose.close(statement); + JdbcClose.close(connection); } } diff --git a/src/main/java/io/ebean/config/dbplatform/SequenceStepIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/SequenceStepIdGenerator.java new file mode 100644 index 000000000..3e632e5fa --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/SequenceStepIdGenerator.java @@ -0,0 +1,38 @@ +package io.ebean.config.dbplatform; + +import io.ebean.BackgroundExecutor; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * Database sequence based IdGenerator using Sequence Step (e.g. step 50). + */ +public abstract class SequenceStepIdGenerator extends SequenceIdGenerator { + + /** + * Construct with stepSize (typically 50). + */ + protected SequenceStepIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int stepSize) { + super(be, ds, seqName, stepSize); + } + + /** + * Add the next set of Ids as the next value plus all the following numbers up to the step size. + */ + protected List readIds(ResultSet resultSet, int ignoreRequestSize) throws SQLException { + + List newIds = new ArrayList<>(allocationSize); + if (resultSet.next()) { + long start = resultSet.getLong(1); + for (int i = 0; i < allocationSize; i++) { + newIds.add(start + i); + } + } + return newIds; + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java index c8bcbd7f6..793afee2d 100644 --- a/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/db2/DB2Platform.java @@ -55,10 +55,9 @@ public class DB2Platform extends DatabasePlatform { * sequence values. */ @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, - DataSource ds, String seqName, int batchSize) { + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { - return new DB2SequenceIdGenerator(be, ds, seqName, batchSize); + return new DB2SequenceIdGenerator(be, ds, seqName, sequenceBatchSize); } } diff --git a/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java index 788e4e396..a5170a759 100644 --- a/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/db2/DB2SequenceIdGenerator.java @@ -1,14 +1,14 @@ package io.ebean.config.dbplatform.db2; import io.ebean.BackgroundExecutor; -import io.ebean.config.dbplatform.SequenceIdGenerator; +import io.ebean.config.dbplatform.SequenceBatchIdGenerator; import javax.sql.DataSource; /** * DB2 specific sequence Id Generator. */ -public class DB2SequenceIdGenerator extends SequenceIdGenerator { +public class DB2SequenceIdGenerator extends SequenceBatchIdGenerator { private final String baseSql; private final String unionBaseSql; diff --git a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java index 7c3c78a36..1b093d880 100644 --- a/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/h2/H2Platform.java @@ -46,10 +46,8 @@ public class H2Platform extends DatabasePlatform { * sequence values. */ @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, - String seqName, int batchSize) { - - return new H2SequenceIdGenerator(be, ds, seqName, batchSize); + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { + return new H2SequenceIdGenerator(be, ds, seqName, sequenceBatchSize); } @Override diff --git a/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java index 4dafed231..b4e875511 100644 --- a/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/h2/H2SequenceIdGenerator.java @@ -1,14 +1,14 @@ package io.ebean.config.dbplatform.h2; import io.ebean.BackgroundExecutor; -import io.ebean.config.dbplatform.SequenceIdGenerator; +import io.ebean.config.dbplatform.SequenceBatchIdGenerator; import javax.sql.DataSource; /** * H2 specific sequence Id Generator. */ -public class H2SequenceIdGenerator extends SequenceIdGenerator { +public class H2SequenceIdGenerator extends SequenceBatchIdGenerator { private final String baseSql; private final String unionBaseSql; diff --git a/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java b/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java index 80a3a032e..1450b01f7 100644 --- a/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/hsqldb/HsqldbPlatform.java @@ -31,9 +31,8 @@ public class HsqldbPlatform extends DatabasePlatform { } @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { - - return new H2SequenceIdGenerator(be, ds, seqName, batchSize); + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { + return new H2SequenceIdGenerator(be, ds, seqName, sequenceBatchSize); } } diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java index f004be7d5..f9973c243 100644 --- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java @@ -1,16 +1,13 @@ package io.ebean.config.dbplatform.mysql; -import io.ebean.BackgroundExecutor; import io.ebean.Query; import io.ebean.annotation.Platform; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.config.dbplatform.DbType; import io.ebean.config.dbplatform.IdType; -import io.ebean.config.dbplatform.PlatformIdGenerator; import io.ebean.config.dbplatform.SqlErrorCodes; -import javax.sql.DataSource; import java.sql.Types; /** @@ -64,16 +61,6 @@ public class MySqlPlatform extends DatabasePlatform { dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255)); } - /** - * Return null in case there is a sequence annotation. - */ - @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, - DataSource ds, String seqName, int batchSize) { - - return null; - } - @Override protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) { // NOWAIT and SKIP LOCKED currently not supported with MySQL diff --git a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java index 5f0b1ca3e..636390dfc 100644 --- a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java @@ -70,9 +70,8 @@ public class OraclePlatform extends DatabasePlatform { } @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { - - return new OracleSequenceIdGenerator(be, ds, seqName, batchSize); + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { + return new OracleSequenceIdGenerator(be, ds, seqName, sequenceBatchSize); } @Override diff --git a/src/main/java/io/ebean/config/dbplatform/oracle/OracleSequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/oracle/OracleSequenceIdGenerator.java index b0a7a2f70..32dd7a28e 100644 --- a/src/main/java/io/ebean/config/dbplatform/oracle/OracleSequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/oracle/OracleSequenceIdGenerator.java @@ -1,14 +1,14 @@ package io.ebean.config.dbplatform.oracle; import io.ebean.BackgroundExecutor; -import io.ebean.config.dbplatform.SequenceIdGenerator; +import io.ebean.config.dbplatform.SequenceBatchIdGenerator; import javax.sql.DataSource; /** * Oracle specific sequence Id Generator. */ -public class OracleSequenceIdGenerator extends SequenceIdGenerator { +public class OracleSequenceIdGenerator extends SequenceBatchIdGenerator { private final String baseSql; diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java index 04d1b0384..20d9107d1 100644 --- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java @@ -90,9 +90,9 @@ public class PostgresPlatform extends DatabasePlatform { * Create a Postgres specific sequence IdGenerator. */ @Override - public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, String seqName, int batchSize) { + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { - return new PostgresSequenceIdGenerator(be, ds, seqName, batchSize); + return new PostgresSequenceIdGenerator(be, ds, seqName, sequenceBatchSize); } @Override diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresSequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresSequenceIdGenerator.java index d01a70db5..4550c926d 100644 --- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresSequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresSequenceIdGenerator.java @@ -1,14 +1,14 @@ package io.ebean.config.dbplatform.postgres; import io.ebean.BackgroundExecutor; -import io.ebean.config.dbplatform.SequenceIdGenerator; +import io.ebean.config.dbplatform.SequenceBatchIdGenerator; import javax.sql.DataSource; /** * Postgres specific sequence Id Generator. */ -public class PostgresSequenceIdGenerator extends SequenceIdGenerator { +public class PostgresSequenceIdGenerator extends SequenceBatchIdGenerator { private final String baseSql; diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasicSqlLimiter.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasicSqlLimiter.java index 64494f34d..3ac56f727 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasicSqlLimiter.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasicSqlLimiter.java @@ -13,7 +13,7 @@ public class SqlServerBasicSqlLimiter implements BasicSqlLimiter { StringBuilder sb = new StringBuilder(50 + dbSql.length()); sb.append(dbSql); if (!dbSql.toLowerCase().contains("order by")) { - sb.append(" order by 1 "); + sb.append(" order by 1"); } sb.append(" ").append("offset"); sb.append(" ").append(firstRow).append(" rows"); diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java index f0ed6744a..102a7e0d5 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java @@ -1,13 +1,18 @@ package io.ebean.config.dbplatform.sqlserver; +import io.ebean.BackgroundExecutor; +import io.ebean.Query; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; +import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.config.dbplatform.DbType; import io.ebean.config.dbplatform.IdType; +import io.ebean.config.dbplatform.PlatformIdGenerator; import io.ebean.config.dbplatform.SqlErrorCodes; +import javax.sql.DataSource; import java.sql.Types; /** @@ -18,8 +23,8 @@ public class SqlServerPlatform extends DatabasePlatform { public SqlServerPlatform() { super(); this.platform = Platform.SQLSERVER; - // effectively disable persistBatchOnCascade mode for SQL Server - // due to lack of support for getGeneratedKeys in batch mode + // disable persistBatchOnCascade mode for + // SQL Server unless we are using sequences this.persistBatchOnCascade = PersistBatch.NONE; this.idInExpandedForm = true; this.selectCountWithAlias = true; @@ -29,12 +34,14 @@ public class SqlServerPlatform extends DatabasePlatform { this.dbIdentity.setIdType(IdType.IDENTITY); this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsIdentity(true); + this.dbIdentity.setSupportsSequence(true); + this.sequenceBatchMode = false; this.exceptionTranslator = new SqlErrorCodes() .addAcquireLock("1222") .addDuplicateKey("2601", "2627") - .addDataIntegrity("544", "8114", "8115") + .addDataIntegrity("544", "547", "8114", "8115") .build(); this.openQuote = "["; @@ -67,8 +74,45 @@ public class SqlServerPlatform extends DatabasePlatform { } + @Override + public void configure(ServerConfig config) { + super.configure(config); + if (dbIdentity.getIdType() == IdType.SEQUENCE) { + this.persistBatchOnCascade = PersistBatch.ALL; + } + } + @Override protected void escapeLikeCharacter(char ch, StringBuilder sb) { sb.append('[').append(ch).append(']'); } + + /** + * Create a Postgres specific sequence IdGenerator. + */ + @Override + public PlatformIdGenerator createSequenceIdGenerator(BackgroundExecutor be, DataSource ds, int stepSize, String seqName) { + return new SqlServerStepSequence(be, ds, seqName, stepSize); + } + + /** + * For update is part of the FROM clause on the base table for sql server. + */ + @Override + public String fromForUpdate(Query.ForUpdate forUpdateMode) { + switch (forUpdateMode) { + case SKIPLOCKED: + return "with (updlock,readpast)"; + case NOWAIT: + return "with (updlock,nowait)"; + default: + return "with (updlock)"; + } + } + + @Override + protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) { + // for update are hints on from clause of base table + return sql; + } } diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequence.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequence.java new file mode 100644 index 000000000..d9a53a9f7 --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequence.java @@ -0,0 +1,24 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.BackgroundExecutor; +import io.ebean.config.dbplatform.SequenceStepIdGenerator; + +import javax.sql.DataSource; + +public class SqlServerStepSequence extends SequenceStepIdGenerator { + + private final String nextSql; + + /** + * Construct where batchSize is the sequence step size. + */ + public SqlServerStepSequence(BackgroundExecutor be, DataSource ds, String seqName, int stepSize) { + super(be, ds, seqName, stepSize); + this.nextSql = "select next value for "+seqName; + } + + @Override + public String getSql(int batchSize) { + return nextSql; + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index 55057bddf..66e5e64e0 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -308,9 +308,7 @@ public class PlatformDdl { if (initialValue > 1) { sb.append(" start with ").append(initialValue); } - if (allocationSize > 0 && allocationSize != 50) { - // at this stage ignoring allocationSize 50 as this is the 'default' and - // not consistent with the way Ebean batch fetches sequence values + if (allocationSize > 1) { sb.append(" increment by ").append(allocationSize); } sb.append(";"); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java index 16b541d88..843abad99 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/SqlServerDdl.java @@ -121,9 +121,7 @@ public class SqlServerDdl extends PlatformDdl { } else { sb.append(" start with 1 "); } - if (allocationSize > 0 && allocationSize != 50) { - // at this stage ignoring allocationSize 50 as this is the 'default' and - // not consistent with the way Ebean batch fetches sequence values + if (allocationSize > 1) { sb.append(" increment by ").append(allocationSize); } sb.append(";"); diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java index ff4fd4338..0f72ca48c 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java @@ -270,7 +270,7 @@ public class DefaultContainer implements SpiContainer { config.setDatabasePlatform(platform); } logger.info("DatabasePlatform name:{} platform:{}", config.getName(), platform.getName()); - platform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); + platform.configure(config); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index ed2945ef6..618183220 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -173,8 +173,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private final BackgroundExecutor backgroundExecutor; - private final int dbSequenceBatchSize; - private final EncryptKeyManager encryptKeyManager; private final IdBinderFactory idBinderFactory; @@ -206,7 +204,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap { this.serverName = InternString.intern(serverConfig.getName()); this.cacheManager = config.getCacheManager(); this.docStoreFactory = config.getDocStoreFactory(); - this.dbSequenceBatchSize = serverConfig.getDatabaseSequenceBatchSize(); this.backgroundExecutor = config.getBackgroundExecutor(); this.dataSource = serverConfig.getDataSource(); this.encryptKeyManager = serverConfig.getEncryptKeyManager(); @@ -1391,12 +1388,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap { seqName = namingConvention.getSequenceName(desc.getBaseTable(), primaryKeyColumn); } - // create the sequence based IdGenerator - desc.setIdGenerator(createSequenceIdGenerator(seqName)); + if (databasePlatform.isSequenceBatchMode()) { + // use sequence next step 1 as we are going to batch fetch them instead + desc.setSequenceAllocationSize(1); + } + int stepSize = desc.getSequenceAllocationSize(); + desc.setIdGenerator(createSequenceIdGenerator(seqName, stepSize)); } - private PlatformIdGenerator createSequenceIdGenerator(String seqName) { - return databasePlatform.createSequenceIdGenerator(backgroundExecutor, dataSource, seqName, dbSequenceBatchSize); + private PlatformIdGenerator createSequenceIdGenerator(String seqName, int stepSize) { + return databasePlatform.createSequenceIdGenerator(backgroundExecutor, dataSource, stepSize, seqName); } private void createByteCode(DeployBeanDescriptor deploy) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java index fa1563866..ff5402dbc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java @@ -129,4 +129,9 @@ public interface DbSqlContext { * Start group by clause. */ void startGroupBy(); + + /** + * Append 'for update' lock hints on FROM clause (sql server only). + */ + void appendFromForUpdate(); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 36e14a2e8..83416486a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -107,7 +107,7 @@ public class DeployBeanDescriptor { private int sequenceInitialValue; - private int sequenceAllocationSize; + private int sequenceAllocationSize = 50; /** * Used with Identity columns but no getGeneratedKeys support. diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 6ae7a12a0..c178371ee 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query; +import io.ebean.Query; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; import io.ebean.annotation.Platform; @@ -671,4 +672,16 @@ class CQueryBuilder { boolean isPlatformDistinctOn() { return dbPlatform.isPlatform(Platform.POSTGRES); } + + /** + * Return the 'for update' FROM hint (sql server). + */ + public String fromForUpdate(SpiQuery query) { + Query.ForUpdate mode = query.getForUpdateMode(); + if (mode == null) { + return null; + } else { + return dbPlatform.fromForUpdate(mode); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index cae5da9f0..a2138104b 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -26,6 +26,8 @@ class DefaultDbSqlContext implements DbSqlContext { private final ArrayStack prefixStack = new ArrayStack<>(); + private final String fromForUpdate; + private boolean useColumnAlias; private int columnIndex; @@ -55,7 +57,8 @@ class DefaultDbSqlContext implements DbSqlContext { * Construct for SELECT clause (with column alias settings). */ DefaultDbSqlContext(SqlTreeAlias alias, CQueryBuilder builder, - boolean alwaysUseColumnAlias, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + boolean alwaysUseColumnAlias, CQueryHistorySupport historySupport, + CQueryDraftSupport draftSupport, String fromForUpdate) { this.alias = alias; this.tableAliasPlaceHolder = builder.tableAliasPlaceHolder; @@ -64,6 +67,14 @@ class DefaultDbSqlContext implements DbSqlContext { this.draftSupport = draftSupport; this.historySupport = historySupport; this.historyQuery = (historySupport != null); + this.fromForUpdate = fromForUpdate; + } + + @Override + public void appendFromForUpdate() { + if (fromForUpdate != null) { + append(" ").append(fromForUpdate); + } } @Override diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index d5e0f408c..d5ea84855 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -119,9 +119,10 @@ public final class SqlTreeBuilder { this.alias = new SqlTreeAlias(request.getBaseTableAlias()); this.distinctOnPlatform = builder.isPlatformDistinctOn(); + String fromForUpdate = builder.fromForUpdate(query); CQueryHistorySupport historySupport = builder.getHistorySupport(query); CQueryDraftSupport draftSupport = builder.getDraftSupport(query); - this.ctx = new DefaultDbSqlContext(alias, builder, !subQuery, historySupport, draftSupport); + this.ctx = new DefaultDbSqlContext(alias, builder, !subQuery, historySupport, draftSupport, fromForUpdate); } /** diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java index b956115b6..bb93b25e1 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -68,6 +68,7 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean { ctx.append(desc.getBaseTable(temporalMode)); ctx.append(" ").append(baseTableAlias); + ctx.appendFromForUpdate(); if (includeJoin != null) { String a1 = baseTableAlias; diff --git a/src/main/java/io/ebeaninternal/util/JdbcClose.java b/src/main/java/io/ebeaninternal/util/JdbcClose.java index 647f34709..f74e3dd46 100644 --- a/src/main/java/io/ebeaninternal/util/JdbcClose.java +++ b/src/main/java/io/ebeaninternal/util/JdbcClose.java @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; /** * Utility for closing raw Jdbc resources. @@ -14,6 +15,19 @@ public class JdbcClose { private static final Logger logger = LoggerFactory.getLogger(JdbcClose.class); + /** + * Close the resultSet logging if an error occurs. + */ + public static void close(Statement statement) { + try { + if (statement != null) { + statement.close(); + } + } catch (SQLException e) { + logger.warn("Error closing statement", e); + } + } + /** * Close the resultSet logging if an error occurs. */ diff --git a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java index 8f29e2357..2cca6c06d 100644 --- a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java +++ b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java @@ -16,10 +16,13 @@ public class MatchingNamingConventionTest { } @Test - public void getColumnFromProperty_when_allQuoted() throws Exception { + public void getColumnFromProperty_when_allQuoted() { SqlServerPlatform platform = new SqlServerPlatform(); - platform.configure(new DbTypeConfig(), true); + + ServerConfig config = new ServerConfig(); + config.setAllQuotedIdentifiers(true); + platform.configure(config); NamingConvention nc = new MatchingNamingConvention(); nc.setDatabasePlatform(platform); @@ -29,7 +32,7 @@ public class MatchingNamingConventionTest { } @Test - public void getColumnFromProperty() throws Exception { + public void getColumnFromProperty() { String fkCol = "bridgetab_userId"; String col = namingConvention.getColumnFromProperty(null, fkCol); diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index 860ad9582..0eea08122 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -1,6 +1,7 @@ package io.ebean.config; import io.ebean.annotation.PersistBatch; +import io.ebean.config.dbplatform.IdType; import org.avaje.datasource.DataSourceConfig; import org.junit.Test; @@ -46,6 +47,7 @@ public class ServerConfigTest { props.setProperty("autoReadOnlyDataSource", "true"); props.setProperty("disableL2Cache", "true"); props.setProperty("notifyL2CacheInForeground", "true"); + props.setProperty("idType", "SEQUENCE"); serverConfig.loadFromProperties(props); @@ -54,6 +56,7 @@ public class ServerConfigTest { assertTrue(serverConfig.isDbOffline()); assertTrue(serverConfig.isAutoReadOnlyDataSource()); + assertEquals(IdType.SEQUENCE, serverConfig.getIdType()); assertEquals(PersistBatch.INSERT, serverConfig.getPersistBatch()); assertEquals(PersistBatch.INSERT, serverConfig.getPersistBatchOnCascade()); assertEquals(ServerConfig.DbUuid.BINARY, serverConfig.getDbTypeConfig().getDbUuid()); diff --git a/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequenceTest.java b/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequenceTest.java new file mode 100644 index 000000000..3745ef4fa --- /dev/null +++ b/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServerStepSequenceTest.java @@ -0,0 +1,55 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.BackgroundExecutor; +import io.ebean.BaseTestCase; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SqlServerStepSequenceTest extends BaseTestCase { + + private static final Logger log = LoggerFactory.getLogger(SqlServerStepSequenceTest.class); + + @Ignore + @ForPlatform(Platform.SQLSERVER) + @Test + public void seq() { + + + server().createSqlUpdate("drop sequence if exists sqls_testseq_9876").execute(); + server().createSqlUpdate("create sequence sqls_testseq_9876 start with 1 increment by 50").execute(); + + BackgroundExecutor be = server().getBackgroundExecutor(); + DataSource ds = server().getPluginApi().getDataSource(); + + SqlServerStepSequence s = new SqlServerStepSequence(be, ds, "sqls_testseq_9876", 50); + + Object id = s.nextId(null); + assertThat(id).isEqualTo(1L); + + for (int i = 0; i < 20; i++) { + Object val = s.nextId(null); + log.warn("val: "+val); + } + + log.warn("here"); + + for (int i = 0; i < 20; i++) { + Object val = s.nextId(null); + log.warn("val: "+val); + } + + for (int i = 0; i < 100; i++) { + Object val = s.nextId(null); + log.warn("val: "+val); + } + } + +} From 29bb9d3b487e52c77013d4135c6a0f83a03d9874 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 22 Feb 2018 22:46:17 +1300 Subject: [PATCH 0053/1036] #1268 - SQL Server fix for "for update" plus Sequences support plus refactor of sequences --- src/test/resources/ebean.properties | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index d2e64ef00..233b18ff6 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -15,6 +15,7 @@ ebean.encryptKeyManager=org.tests.basic.encrypt.BasicEncyptKeyManager #ebean.autotune.profiling=true #ebean.autotune.profilingUpdateFrequency=5 +ebean.sqlserver.ddl.createOnly=true ebean.ddl.generate=true ebean.ddl.run=true ebean.packages=org.tests @@ -88,6 +89,10 @@ datasource.h2ebasicver.password= datasource.h2ebasicver.databaseUrl=jdbc:h2:mem:h2ebasicver datasource.h2ebasicver.databaseDriver=org.h2.Driver +datasource.h2ebasicver2.username=sa +datasource.h2ebasicver2.password= +datasource.h2ebasicver2.databaseUrl=jdbc:h2:mem:h2ebasicver +datasource.h2ebasicver2.databaseDriver=org.h2.Driver datasource.sqlite.username= datasource.sqlite.password= @@ -122,9 +127,10 @@ datasource.pg.databaseDriver=org.postgresql.Driver #datasource.pg.capturestacktrace=true datasource.pg.maxStackTraceSize=50 +ebean.sqlserver.idType=SEQUENCE datasource.sqlserver.username=test_ebean datasource.sqlserver.password=SqlS3rv#r -datasource.sqlserver.databaseUrl=jdbc:sqlserver://localhost:1433;databaseName=test_ebean;selectMethod=cursor +datasource.sqlserver.databaseUrl=jdbc:sqlserver://localhost:1433;databaseName=test_ebean datasource.sqlserver.databaseDriver=com.microsoft.sqlserver.jdbc.SQLServerDriver datasource.db2.username=db2admin From 18d944f2287b133da8a7618e76be672bff6daaca Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 10:13:57 +1300 Subject: [PATCH 0054/1036] Test only - copy/add multi-tenant partition tests --- .../multitenant/partition/CurrentTenant.java | 14 ++++ .../multitenant/partition/MtBaseDomain.java | 57 +++++++++++++ .../org/multitenant/partition/MtContent.java | 32 ++++++++ .../org/multitenant/partition/MtTenant.java | 67 ++++++++++++++++ .../multitenant/partition/MtTenantAware.java | 22 +++++ .../partition/MultiTenantPartitionTest.java | 80 +++++++++++++++++++ .../multitenant/partition/UserContext.java | 46 +++++++++++ 7 files changed, 318 insertions(+) create mode 100644 src/test/java/org/multitenant/partition/CurrentTenant.java create mode 100644 src/test/java/org/multitenant/partition/MtBaseDomain.java create mode 100644 src/test/java/org/multitenant/partition/MtContent.java create mode 100644 src/test/java/org/multitenant/partition/MtTenant.java create mode 100644 src/test/java/org/multitenant/partition/MtTenantAware.java create mode 100644 src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java create mode 100644 src/test/java/org/multitenant/partition/UserContext.java diff --git a/src/test/java/org/multitenant/partition/CurrentTenant.java b/src/test/java/org/multitenant/partition/CurrentTenant.java new file mode 100644 index 000000000..7e8b73b9f --- /dev/null +++ b/src/test/java/org/multitenant/partition/CurrentTenant.java @@ -0,0 +1,14 @@ +package org.multitenant.partition; + +import io.ebean.config.CurrentTenantProvider; + +class CurrentTenant implements CurrentTenantProvider { + + /** + * Return the current tenantId from the user context. + */ + @Override + public String currentId() { + return UserContext.get().getTenantId(); + } +} diff --git a/src/test/java/org/multitenant/partition/MtBaseDomain.java b/src/test/java/org/multitenant/partition/MtBaseDomain.java new file mode 100644 index 000000000..41a23d20f --- /dev/null +++ b/src/test/java/org/multitenant/partition/MtBaseDomain.java @@ -0,0 +1,57 @@ +package org.multitenant.partition; + +import io.ebean.annotation.WhenCreated; +import io.ebean.annotation.WhenModified; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.Version; +import java.time.Instant; + +@MappedSuperclass +public abstract class MtBaseDomain { + + @Id + long id; + + @WhenModified + Instant whenModified; + + @WhenCreated + Instant whenCreated; + + @Version + long version; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Instant getWhenModified() { + return whenModified; + } + + public void setWhenModified(Instant whenModified) { + this.whenModified = whenModified; + } + + public Instant getWhenCreated() { + return whenCreated; + } + + public void setWhenCreated(Instant whenCreated) { + this.whenCreated = whenCreated; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/multitenant/partition/MtContent.java b/src/test/java/org/multitenant/partition/MtContent.java new file mode 100644 index 000000000..9489c1342 --- /dev/null +++ b/src/test/java/org/multitenant/partition/MtContent.java @@ -0,0 +1,32 @@ +package org.multitenant.partition; + +import javax.persistence.Entity; + +@Entity +public class MtContent extends MtTenantAware { + + String title; + + String body; + + public MtContent(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + +} diff --git a/src/test/java/org/multitenant/partition/MtTenant.java b/src/test/java/org/multitenant/partition/MtTenant.java new file mode 100644 index 000000000..9c21a14e0 --- /dev/null +++ b/src/test/java/org/multitenant/partition/MtTenant.java @@ -0,0 +1,67 @@ +package org.multitenant.partition; + +import io.ebean.annotation.Length; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class MtTenant { + + @Id + final String id; + + @Length(50) + String name; + + @Length(50) + String email; + + String notes; + + @Version + long version; + + public MtTenant(String id, String name, String email) { + this.id = id; + this.name = name; + this.email = email; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/multitenant/partition/MtTenantAware.java b/src/test/java/org/multitenant/partition/MtTenantAware.java new file mode 100644 index 000000000..ea6337a89 --- /dev/null +++ b/src/test/java/org/multitenant/partition/MtTenantAware.java @@ -0,0 +1,22 @@ +package org.multitenant.partition; + +import io.ebean.annotation.TenantId; + +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; + +@MappedSuperclass +public abstract class MtTenantAware extends MtBaseDomain { + + @TenantId + @ManyToOne(optional = false) + MtTenant tenant; + + public MtTenant getTenant() { + return tenant; + } + + public void setTenant(MtTenant tenant) { + this.tenant = tenant; + } +} diff --git a/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java b/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java new file mode 100644 index 000000000..ff007a938 --- /dev/null +++ b/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java @@ -0,0 +1,80 @@ +package org.multitenant.partition; + +import io.ebean.EbeanServer; +import io.ebean.EbeanServerFactory; +import io.ebean.config.ServerConfig; +import io.ebean.config.TenantMode; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MultiTenantPartitionTest { + + private static String[] names = {"Ace", "Base", "Case", "Dae", "Eva"}; + + static List tenants() { + List tenants = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + tenants.add(new MtTenant("ten_"+i, names[i], names[i]+"@foo.com".toLowerCase())); + } + return tenants; + } + + private static EbeanServer server = init(); + + static { + server.saveAll(tenants()); + } + + @Test + public void start() { + + UserContext.set("rob", "ten_1"); + + LoggedSqlCollector.start(); + MtContent content = new MtContent("first title"); + server.save(content); + + List sql = LoggedSqlCollector.current(); + assertThat(sql.get(0)).contains("insert into mt_content (title, body, when_modified, when_created, version, tenant_id) values (?,?,?,?,?,?)"); + + content.setBody("some body"); + server.save(content); + + sql = LoggedSqlCollector.current(); + assertThat(sql.get(0)).contains("update mt_content set body=?, when_modified=?, version=? where id=? and tenant_id=? and version=?"); + + server.delete(content); + + sql = LoggedSqlCollector.current(); + assertThat(sql.get(0)).contains("delete from mt_content where id=? and tenant_id=? and version=?"); + + LoggedSqlCollector.stop(); + + } + + + private static EbeanServer init() { + System.setProperty("ebean.ignoreExtraDdl", "true"); + + ServerConfig config = new ServerConfig(); + + config.setName("h2multitenant"); + config.loadFromProperties(); + config.setDdlGenerate(true); + config.setDdlRun(true); + config.setRegister(false); + config.setDefaultServer(false); + config.setCurrentTenantProvider(new CurrentTenant()); + config.setTenantMode(TenantMode.PARTITION); + + config.getClasses().add(MtTenant.class); + config.getClasses().add(MtContent.class); + + return EbeanServerFactory.create(config); + } +} diff --git a/src/test/java/org/multitenant/partition/UserContext.java b/src/test/java/org/multitenant/partition/UserContext.java new file mode 100644 index 000000000..60794b674 --- /dev/null +++ b/src/test/java/org/multitenant/partition/UserContext.java @@ -0,0 +1,46 @@ +package org.multitenant.partition; + +public final class UserContext { + + private static final UserContextThreadLocal local = new UserContextThreadLocal(); + + private String userId; + private String tenantId; + + private UserContext(String userId, String tenantId) { + this.userId = userId; + this.tenantId = tenantId; + } + + private UserContext() { + } + + public String getUserId() { + return userId; + } + + public String getTenantId() { + return tenantId; + } + + public static UserContext get() { + return local.get(); + } + + public static void reset() { + local.remove(); + } + + public static void set(String userId, String tenantId) { + local.set(new UserContext(userId, tenantId)); + } + + + private static class UserContextThreadLocal extends ThreadLocal { + + @Override + protected UserContext initialValue() { + return new UserContext(); + } + } +} From 9aee7c892df60af640ea7127ab1e35e44697ff86 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 10:14:27 +1300 Subject: [PATCH 0055/1036] Test only - copy/add multi-tenant partition tests --- src/test/resources/ebean.properties | 6 ++++++ src/test/resources/logback-test.xml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 233b18ff6..22eb59a86 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -68,6 +68,12 @@ datasource.h2.maxStackTraceSize=20 datasource.h2.poolListener=org.tests.basic.MyTestDataSourcePoolListener #datasource.h2.customProperties=IGNORECASE=TRUE;MODE=Oracle; + +datasource.h2multitenant.username=sa +datasource.h2multitenant.password= +datasource.h2multitenant.url=jdbc:h2:mem:h2multitenant +datasource.h2multitenant.driver=org.h2.Driver + datasource.h2autocommit.autoCommit=true datasource.h2autocommit.username=sa datasource.h2autocommit.password= diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index a86b99666..7ab47450e 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -79,7 +79,7 @@ - + From 4a243a76a713f6d5565e8454923972ff6f00816e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 10:26:47 +1300 Subject: [PATCH 0056/1036] #1270 - Multi-tenant - partition mode - Delete by id does not include tenantId value in predicate --- .../server/deploy/BeanDescriptor.java | 7 ++++ .../server/persist/DefaultPersister.java | 19 ++++++++- .../persist/dmlbind/BindableAssocOne.java | 11 ------ .../persist/dmlbind/BindableAssocTenant.java | 20 ++++++++++ .../persist/dmlbind/BindableProperty.java | 11 ------ .../persist/dmlbind/FactoryVersion.java | 9 ++++- .../partition/MultiTenantPartitionTest.java | 39 +++++++++++++++++++ 7 files changed, 92 insertions(+), 24 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocTenant.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 696fa5dbf..9cc43fef5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -3155,6 +3155,13 @@ public class BeanDescriptor implements BeanType { return versionProperty; } + /** + * Return true if this type is tenant aware. + */ + public boolean isMultiTenant() { + return tenant != null; + } + /** * Return the tenant property when multi-tenant partitioning support is used. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index bc6a5cfe8..8459d8e2d 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -578,6 +578,16 @@ public final class DefaultPersister implements Persister { } BeanDescriptor descriptor = beanDescriptorManager.getBeanDescriptor(beanType); + boolean softDelete = !permanent && descriptor.isSoftDelete(); + if (descriptor.isMultiTenant()) { + // convert to a delete by bean + for (Object id : ids) { + EntityBean bean = descriptor.createEntityBean(); + descriptor.convertSetId(id, bean); + deleteRecurse(bean, transaction, permanent); + } + return ids.size(); + } ArrayList idList = new ArrayList<>(ids.size()); for (Object id : ids) { @@ -585,7 +595,6 @@ public final class DefaultPersister implements Persister { idList.add(descriptor.convertId(id)); } - boolean softDelete = !permanent && descriptor.isSoftDelete(); return delete(descriptor, null, idList, transaction, softDelete); } @@ -595,6 +604,14 @@ public final class DefaultPersister implements Persister { @Override public int delete(Class beanType, Object id, Transaction transaction, boolean permanent) { BeanDescriptor descriptor = beanDescriptorManager.getBeanDescriptor(beanType); + if (descriptor.isMultiTenant()) { + // convert to a delete by bean + EntityBean bean = descriptor.createEntityBean(); + descriptor.convertSetId(id, bean); + delete(bean, transaction, permanent); + return 1; + } + id = descriptor.convertId(id); boolean softDelete = !permanent && descriptor.isSoftDelete(); return delete(descriptor, id, null, transaction, softDelete); diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java index 9ccb00aea..bf4339410 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocOne.java @@ -66,15 +66,4 @@ class BindableAssocOne implements Bindable { } } - /** - * Cast to an EntityBean allowing null. - */ - EntityBean castToEntityBean(Object objectValue) { - if (objectValue instanceof EntityBean || objectValue == null) { - return (EntityBean) objectValue; - } else { - throw new IllegalStateException("Bean " + objectValue.getClass() + " is not enhanced?"); - } - } - } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocTenant.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocTenant.java new file mode 100644 index 000000000..eab3678a5 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableAssocTenant.java @@ -0,0 +1,20 @@ +package io.ebeaninternal.server.persist.dmlbind; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; + +import java.sql.SQLException; + +class BindableAssocTenant extends BindableAssocOne { + + BindableAssocTenant(BeanPropertyAssocOne assocOne) { + super(assocOne); + } + + @Override + public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { + + EntityBean assocBean = (EntityBean) assocOne.getValue(bean); + importedId.bind(request, assocBean); + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableProperty.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableProperty.java index bc0840ce2..0d76baf3c 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableProperty.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableProperty.java @@ -54,15 +54,4 @@ public class BindableProperty implements Bindable { request.bind(value, prop); } - /** - * For compound types bind one of the underlying scalar values for a compound type. - */ - public void dmlBindObject(BindableRequest request, Object bean) throws SQLException { - - Object value = null; - if (bean != null) { - value = prop.getValueObject(bean); - } - request.bind(value, prop); - } } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryVersion.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryVersion.java index e52484d81..abb7f1a20 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryVersion.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryVersion.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.persist.dmlbind; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; /** * Creates a Bindable to support version concurrency where clauses. @@ -36,6 +37,12 @@ public class FactoryVersion { public Bindable createTenantId(BeanDescriptor desc) { BeanProperty tenant = desc.getTenantProperty(); - return (tenant == null) ? null : new BindableProperty(tenant); + if (tenant == null) { + return null; + } else if (tenant instanceof BeanPropertyAssocOne) { + return new BindableAssocTenant((BeanPropertyAssocOne) tenant); + } else { + return new BindableProperty(tenant); + } } } diff --git a/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java b/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java index ff007a938..2625266ef 100644 --- a/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java +++ b/src/test/java/org/multitenant/partition/MultiTenantPartitionTest.java @@ -8,6 +8,7 @@ import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -54,7 +55,45 @@ public class MultiTenantPartitionTest { assertThat(sql.get(0)).contains("delete from mt_content where id=? and tenant_id=? and version=?"); LoggedSqlCollector.stop(); + } + @Test + public void deleteById() { + + UserContext.set("fred", "ten_2"); + + MtContent content = new MtContent("first title"); + server.save(content); + + LoggedSqlCollector.start(); + server.delete(MtContent.class, content.getId()); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("delete from mt_content where id=? and tenant_id=?"); + } + + @Test + public void deleteByIds() { + + UserContext.set("fred", "ten_2"); + + MtContent a = newContent("title a"); + MtContent b = newContent("title b"); + + + List ids = Arrays.asList(a.getId(), b.getId()); + + LoggedSqlCollector.start(); + server.deleteAll(MtContent.class, ids); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("delete from mt_content where id=? and tenant_id=?"); + } + + private MtContent newContent(String title) { + MtContent content = new MtContent(title); + server.save(content); + return content; } From 60a3c24cbaa252fc196b2434cc62acf6f20951e9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 10:31:22 +1300 Subject: [PATCH 0057/1036] No Effective change - Tidy pom removing commented out old sqlserver jdbc driver --- pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/pom.xml b/pom.xml index 1a19a7abd..7d67bc788 100644 --- a/pom.xml +++ b/pom.xml @@ -191,13 +191,6 @@ - - - - - - - io.ebean ebean-docker-run From b037be5d3edd1ba802e0bcaddbb2bec25921f4f7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 12:48:06 +1300 Subject: [PATCH 0058/1036] No Effective change - bump agent in pom (with query bean enhancement of interface default methods) --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7d67bc788..6e27f6bdf 100644 --- a/pom.xml +++ b/pom.xml @@ -215,7 +215,7 @@ io.ebean ebean-agent - 11.9.1 + 11.10.1 test @@ -288,7 +288,7 @@ io.ebean ebean-maven-plugin - 11.9.1 + 11.10.1 test From 47d55a2f295197ce8ee1641cd7ba5db132b0cd94 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 12:50:45 +1300 Subject: [PATCH 0059/1036] [maven-release-plugin] prepare release ebean-11.11.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 6e27f6bdf..3fce9bfeb 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.11.1-SNAPSHOT + 11.11.1 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.11.1 From 0e62d0579e75172f6e60783db5601ba9d4c7954a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 12:50:59 +1300 Subject: [PATCH 0060/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3fce9bfeb..5d56073f8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.11.1 + 11.11.2-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.11.1 + HEAD From 40704e2ef76c6b6c6e4729fec41da3479c4d8013 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 13:37:43 +1300 Subject: [PATCH 0061/1036] No Effective change - change test to use assertJ --- .../org/tests/basic/event/TestQueryAdapter.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/test/java/org/tests/basic/event/TestQueryAdapter.java b/src/test/java/org/tests/basic/event/TestQueryAdapter.java index a8c87024d..ab7dbd763 100644 --- a/src/test/java/org/tests/basic/event/TestQueryAdapter.java +++ b/src/test/java/org/tests/basic/event/TestQueryAdapter.java @@ -3,10 +3,11 @@ package org.tests.basic.event; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import org.junit.Test; import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.TOne; -import org.junit.Assert; -import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; public class TestQueryAdapter extends BaseTestCase { @@ -20,16 +21,11 @@ public class TestQueryAdapter extends BaseTestCase { Ebean.save(o); - //Ebean.find(TOne.class, o.getId()); - - Query queryFindId = Ebean.find(TOne.class) - .setId(o.getId()); + Query queryFindId = Ebean.find(TOne.class).setId(o.getId()); TOne one = queryFindId.findOne(); - Assert.assertNotNull(one); - Assert.assertEquals(one.getId(), o.getId()); - String generatedSql = queryFindId.getGeneratedSql(); - Assert.assertTrue(generatedSql.contains(" 1=1")); + assertThat(one.getId()).isEqualTo(o.getId()); + assertThat(sqlOf(queryFindId)).contains(" 1=1"); } } From 8b18e907afd2a3c4430d6b6d8ef4a5902562037a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 14:04:36 +1300 Subject: [PATCH 0062/1036] #1063 - Add Event Listeners capable of being notified for delete by query or update by query Adds QueryType and adds method query.getQueryType() which then can be used in a BeanQueryAdapter --- src/main/java/io/ebean/Query.java | 5 ++++ src/main/java/io/ebean/QueryType.java | 22 ++++++++++++++++ .../server/querydefn/DefaultOrmQuery.java | 14 +++++++++++ .../tests/basic/event/TestQueryAdapter.java | 25 +++++++++++++++++++ .../basic/event/SimpleTOneQueryAdapter.java | 18 ++++++++++--- 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/ebean/QueryType.java diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java index 8d61e223c..d8898ae5d 100644 --- a/src/main/java/io/ebean/Query.java +++ b/src/main/java/io/ebean/Query.java @@ -1485,6 +1485,11 @@ public interface Query { */ Class getBeanType(); + /** + * Return the type of query being executed. + */ + QueryType getQueryType(); + /** * Set true if you want to disable lazy loading. *

diff --git a/src/main/java/io/ebean/QueryType.java b/src/main/java/io/ebean/QueryType.java new file mode 100644 index 000000000..4c167ac7d --- /dev/null +++ b/src/main/java/io/ebean/QueryType.java @@ -0,0 +1,22 @@ +package io.ebean; + +/** + * The type of the query being executed. + */ +public enum QueryType { + + /** + * A find query. + */ + FIND, + + /** + * An update query. + */ + UPDATE, + + /** + * A delete query. + */ + DELETE +} diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index bc14d10d7..a7aef2d50 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -17,6 +17,7 @@ import io.ebean.PersistenceContextScope; import io.ebean.ProfileLocation; import io.ebean.Query; import io.ebean.QueryIterator; +import io.ebean.QueryType; import io.ebean.RawSql; import io.ebean.Version; import io.ebean.bean.CallStack; @@ -914,6 +915,19 @@ public class DefaultOrmQuery implements SpiQuery { this.profilingListener = profilingListener; } + @Override + public QueryType getQueryType() { + if (type != null) { + switch (type) { + case DELETE: + return QueryType.DELETE; + case UPDATE: + return QueryType.UPDATE; + } + } + return QueryType.FIND; + } + @Override public Mode getMode() { return mode; diff --git a/src/test/java/org/tests/basic/event/TestQueryAdapter.java b/src/test/java/org/tests/basic/event/TestQueryAdapter.java index ab7dbd763..4aea4efa9 100644 --- a/src/test/java/org/tests/basic/event/TestQueryAdapter.java +++ b/src/test/java/org/tests/basic/event/TestQueryAdapter.java @@ -3,10 +3,14 @@ package org.tests.basic.event; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import io.ebean.QueryType; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.TOne; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; public class TestQueryAdapter extends BaseTestCase { @@ -27,5 +31,26 @@ public class TestQueryAdapter extends BaseTestCase { assertThat(one.getId()).isEqualTo(o.getId()); assertThat(sqlOf(queryFindId)).contains(" 1=1"); + + Query notUsedQuery = Ebean.find(TOne.class); + assertThat(notUsedQuery.getQueryType()).isEqualTo(QueryType.FIND); + + LoggedSqlCollector.start(); + + Ebean.update(TOne.class) + .set("name", "mod") + .where().idEq(o.getId()) + .update(); + + List sql = LoggedSqlCollector.current(); + assertThat(sql.get(0)).contains(" 2=2"); + + Ebean.find(TOne.class) + .where().idEq(o.getId()) + .delete(); + + sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains(" 3=3"); + } } diff --git a/src/test/java/org/tests/model/basic/event/SimpleTOneQueryAdapter.java b/src/test/java/org/tests/model/basic/event/SimpleTOneQueryAdapter.java index 040fc5cef..6a4ccd346 100644 --- a/src/test/java/org/tests/model/basic/event/SimpleTOneQueryAdapter.java +++ b/src/test/java/org/tests/model/basic/event/SimpleTOneQueryAdapter.java @@ -23,10 +23,20 @@ public class SimpleTOneQueryAdapter implements BeanQueryAdapter { Query query = request.getQuery(); - // can get the type of query Bean, List, RowCount, Id's etc - //Type queryType = query.getType(); - - query.where().raw("1=1"); + switch (query.getQueryType()) { + case DELETE: { + query.where().raw("3=3"); + break; + } + case UPDATE: { + query.where().raw("2=2"); + break; + } + case FIND: { + query.where().raw("1=1"); + break; + } + } } From ff111eaf3369395f2f823634f0a1ce2d1446acf7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 14:34:08 +1300 Subject: [PATCH 0063/1036] #1063 - Add Event Listeners capable of being notified for delete by id Adds BeanDeleteIdRequest and adds a method to BeanPersistController and BeanPersistAdapter --- .../io/ebean/event/BeanDeleteIdRequest.java | 26 +++++++++++++ .../io/ebean/event/BeanPersistAdapter.java | 7 ++++ .../io/ebean/event/BeanPersistController.java | 5 +++ .../deploy/ChainedBeanPersistController.java | 8 ++++ .../server/persist/DefaultPersister.java | 18 +++++++++ .../server/persist/DeleteIdRequest.java | 37 +++++++++++++++++++ .../event/BeanPersistControllerTest.java | 22 +++++++++-- 7 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/ebean/event/BeanDeleteIdRequest.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/DeleteIdRequest.java diff --git a/src/main/java/io/ebean/event/BeanDeleteIdRequest.java b/src/main/java/io/ebean/event/BeanDeleteIdRequest.java new file mode 100644 index 000000000..795886830 --- /dev/null +++ b/src/main/java/io/ebean/event/BeanDeleteIdRequest.java @@ -0,0 +1,26 @@ +package io.ebean.event; + +import io.ebean.EbeanServer; +import io.ebean.Transaction; + +/** + * A request to delete a bean by Id value. + */ +public interface BeanDeleteIdRequest { + + /** + * Return the server processing the request. + */ + EbeanServer getEbeanServer(); + + /** + * Return the Transaction associated with this request. + */ + Transaction getTransaction(); + + /** + * Returns the Id value of the bean being deleted. + */ + Object getId(); + +} diff --git a/src/main/java/io/ebean/event/BeanPersistAdapter.java b/src/main/java/io/ebean/event/BeanPersistAdapter.java index 6e38ce2aa..4b6cf2cc6 100644 --- a/src/main/java/io/ebean/event/BeanPersistAdapter.java +++ b/src/main/java/io/ebean/event/BeanPersistAdapter.java @@ -87,4 +87,11 @@ public abstract class BeanPersistAdapter implements BeanPersistController { public void postSoftDelete(BeanPersistRequest request) { } + /** + * Does nothing by default. + */ + @Override + public void preDelete(BeanDeleteIdRequest request) { + + } } diff --git a/src/main/java/io/ebean/event/BeanPersistController.java b/src/main/java/io/ebean/event/BeanPersistController.java index 6c55cf310..15160cb28 100644 --- a/src/main/java/io/ebean/event/BeanPersistController.java +++ b/src/main/java/io/ebean/event/BeanPersistController.java @@ -92,6 +92,11 @@ public interface BeanPersistController { */ boolean preSoftDelete(BeanPersistRequest request); + /** + * Prior to a delete by id perform some action. + */ + void preDelete(BeanDeleteIdRequest request); + /** * Called after the insert was performed. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/ChainedBeanPersistController.java b/src/main/java/io/ebeaninternal/server/deploy/ChainedBeanPersistController.java index ff6bfe6c1..639a856ad 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ChainedBeanPersistController.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ChainedBeanPersistController.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.deploy; +import io.ebean.event.BeanDeleteIdRequest; import io.ebean.event.BeanPersistController; import io.ebean.event.BeanPersistRequest; @@ -147,6 +148,13 @@ public class ChainedBeanPersistController implements BeanPersistController { return true; } + @Override + public void preDelete(BeanDeleteIdRequest request) { + for (BeanPersistController aChain : chain) { + aChain.preDelete(request); + } + } + @Override public boolean preInsert(BeanPersistRequest request) { for (BeanPersistController aChain : chain) { diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 8459d8e2d..cbf9aba38 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -9,6 +9,7 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; +import io.ebean.event.BeanPersistController; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.SpiUpdate; @@ -718,6 +719,7 @@ public final class DefaultPersister implements Persister { } // use Id's to update L2 cache rather than Bulk table event + notifyDeleteById(descriptor, id, idList, transaction); deleteById.setAutoTableMod(false); if (idList != null) { t.getEvent().addDeleteByIdList(descriptor, idList); @@ -738,6 +740,22 @@ public final class DefaultPersister implements Persister { return rows; } + private void notifyDeleteById(BeanDescriptor descriptor, Object id, List idList, Transaction transaction) { + + BeanPersistController controller = descriptor.getPersistController(); + if (controller != null) { + DeleteIdRequest request = new DeleteIdRequest(server, transaction, id); + if (idList == null) { + controller.preDelete(request); + } else { + for (Object idValue : idList) { + request.setId(idValue); + controller.preDelete(request); + } + } + } + } + /** * We need to create and execute a query to get the foreign key values as * the delete cascades to them (foreign keys). diff --git a/src/main/java/io/ebeaninternal/server/persist/DeleteIdRequest.java b/src/main/java/io/ebeaninternal/server/persist/DeleteIdRequest.java new file mode 100644 index 000000000..0cad9918a --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/DeleteIdRequest.java @@ -0,0 +1,37 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.EbeanServer; +import io.ebean.Transaction; +import io.ebean.event.BeanDeleteIdRequest; +import io.ebeaninternal.api.SpiEbeanServer; + +class DeleteIdRequest implements BeanDeleteIdRequest { + + private final EbeanServer server; + private final Transaction transaction; + private Object id; + + DeleteIdRequest(SpiEbeanServer server, Transaction transaction, Object id) { + this.server = server; + this.transaction = transaction; + } + + void setId(Object id) { + this.id = id; + } + + @Override + public EbeanServer getEbeanServer() { + return server; + } + + @Override + public Transaction getTransaction() { + return transaction; + } + + @Override + public Object getId() { + return id; + } +} diff --git a/src/test/java/io/ebean/event/BeanPersistControllerTest.java b/src/test/java/io/ebean/event/BeanPersistControllerTest.java index 03f7a1170..58d351a1c 100644 --- a/src/test/java/io/ebean/event/BeanPersistControllerTest.java +++ b/src/test/java/io/ebean/event/BeanPersistControllerTest.java @@ -4,19 +4,20 @@ package io.ebean.event; import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; import io.ebean.config.ServerConfig; -import org.tests.model.basic.EBasicVer; import org.junit.Test; +import org.tests.model.basic.EBasicVer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; public class BeanPersistControllerTest { - PersistAdapter continuePersistingAdapter = new PersistAdapter(true); + private PersistAdapter continuePersistingAdapter = new PersistAdapter(true); - PersistAdapter stopPersistingAdapter = new PersistAdapter(false); + private PersistAdapter stopPersistingAdapter = new PersistAdapter(false); @Test public void testInsertUpdateDelete_given_continuePersistingAdapter() { @@ -64,7 +65,17 @@ public class BeanPersistControllerTest { ebeanServer.delete(bean); assertThat(stopPersistingAdapter.methodsCalled).hasSize(1); assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDelete"); + stopPersistingAdapter.methodsCalled.clear(); + ebeanServer.delete(EBasicVer.class, 22); + assertThat(stopPersistingAdapter.methodsCalled).hasSize(1); + assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById"); + stopPersistingAdapter.methodsCalled.clear(); + + ebeanServer.deleteAll(EBasicVer.class, Arrays.asList(22,23,24)); + assertThat(stopPersistingAdapter.methodsCalled).hasSize(3); + assertThat(stopPersistingAdapter.methodsCalled).containsExactly("preDeleteById", "preDeleteById", "preDeleteById"); + stopPersistingAdapter.methodsCalled.clear(); } private EbeanServer getEbeanServer(PersistAdapter persistAdapter) { @@ -136,6 +147,11 @@ public class BeanPersistControllerTest { public void postUpdate(BeanPersistRequest request) { methodsCalled.add("postUpdate"); } + + @Override + public void preDelete(BeanDeleteIdRequest request) { + methodsCalled.add("preDeleteById"); + } } } From 7d0ed261b534fc958df58e34e58bc1fb0d69323f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 16:55:07 +1300 Subject: [PATCH 0064/1036] #1271 - ENH: Add BeanFinder and BeanRepository ... such that there is a read to go base class for DI repository style --- src/main/java/io/ebean/BeanFinder.java | 169 +++++++++++++++++ src/main/java/io/ebean/BeanRepository.java | 178 ++++++++++++++++++ .../tests/repository/CustomerRepository.java | 36 ++++ .../tests/repository/TestBeanRepository.java | 61 ++++++ 4 files changed, 444 insertions(+) create mode 100644 src/main/java/io/ebean/BeanFinder.java create mode 100644 src/main/java/io/ebean/BeanRepository.java create mode 100644 src/test/java/org/tests/repository/CustomerRepository.java create mode 100644 src/test/java/org/tests/repository/TestBeanRepository.java diff --git a/src/main/java/io/ebean/BeanFinder.java b/src/main/java/io/ebean/BeanFinder.java new file mode 100644 index 000000000..0afcc7227 --- /dev/null +++ b/src/main/java/io/ebean/BeanFinder.java @@ -0,0 +1,169 @@ +package io.ebean; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; +import java.util.Optional; + +/** + * Provides finder functionality for use with "Dependency Injection style" use of Ebean. + *

+ * Note that typically users would extend BeanRepository rather than BeanFinder. + *

+ *
{@code
+ *
+ * public class CustomerFinder extends BeanFinder {
+ *
+ *   @Inject
+ *   public CustomerFinder(EbeanServer server) {
+ *     super(Customer.class, server);
+ *   }
+ *
+ *   // ... add customer specific finders
+ * }
+ *
+ * }
+ * + * @param The ID type + * @param The Bean type + */ +public abstract class BeanFinder { + + protected final EbeanServer server; + + protected final Class type; + + /** + * Create with the given bean type and EbeanServer instance. + * + * @param type The bean type + * @param server The EbeanServer instance typically created via Spring factory or equivalent. + */ + protected BeanFinder(Class type, EbeanServer server) { + this.type = type; + this.server = server; + } + + /** + * Return the EbeanServer to use. + */ + public EbeanServer db() { + return server; + } + + /** + * Return the current transaction. + */ + public Transaction currentTransaction() { + return db().currentTransaction(); + } + + /** + * Flush the JDBC batch on the current transaction. + */ + public void flush() { + db().flush(); + } + + /** + * Return typically a different EbeanServer to the default. + *

+ * This is equivalent to {@link Ebean#getServer(String)} + * + * @param server The name of the EbeanServer. If this is null then the default EbeanServer is + * returned. + */ + public EbeanServer db(String server) { + return Ebean.getServer(server); + } + + /** + * Creates an entity reference for this ID. + *

+ * Equivalent to {@link EbeanServer#getReference(Class, Object)} + */ + @Nonnull + public T ref(I id) { + return db().getReference(type, id); + } + + /** + * Retrieves an entity by ID. + *

+ * Equivalent to {@link EbeanServer#find(Class, Object)} + */ + @Nullable + public T findById(I id) { + return db().find(type, id); + } + + /** + * Find an entity by ID returning an Optional. + */ + @Nullable + public Optional findByIdOrEmpty(I id) { + return db().find(type).setId(id).findOneOrEmpty(); + } + + /** + * Delete a bean by Id. + *

+ * Equivalent to {@link EbeanServer#delete(Class, Object)} + */ + public void deleteById(I id) { + db().delete(type, id); + } + + /** + * Retrieves all entities of the given type. + */ + @Nonnull + public List findAll() { + return query().findList(); + } + + /** + * Creates an update query. + * + *

{@code
+   *
+   *  int rows =
+   *      updateQuery()
+   *      .set("status", Customer.Status.ACTIVE)
+   *      .set("updtime", new Timestamp(System.currentTimeMillis()))
+   *      .where()
+   *        .gt("id", 1000)
+   *        .update();
+   *
+   * }
+ * + *

+ * Equivalent to {@link EbeanServer#update(Class)} + */ + protected UpdateQuery updateQuery() { + return db().update(type); + } + + /** + * Creates a query. + *

+ * Equivalent to {@link EbeanServer#find(Class)} + */ + protected Query query() { + return db().find(type); + } + + /** + * Creates a native sql query. + */ + protected Query nativeSql(String nativeSql) { + return db().findNative(type, nativeSql); + } + + /** + * Creates a query using the ORM query language. + */ + protected Query query(String ormQuery) { + return db().createQuery(type, ormQuery); + } +} diff --git a/src/main/java/io/ebean/BeanRepository.java b/src/main/java/io/ebean/BeanRepository.java new file mode 100644 index 000000000..3c588b65c --- /dev/null +++ b/src/main/java/io/ebean/BeanRepository.java @@ -0,0 +1,178 @@ +package io.ebean; + +import io.ebean.bean.EntityBean; + +/** + * Provides finder functionality for use with "Dependency Injection style" use of Ebean. + *

+ *

{@code
+ *
+ * @Repository
+ * public class CustomerRepository extends BeanRepository {
+ *
+ *   @Inject
+ *   public CustomerRepository(EbeanServer server) {
+ *     super(Customer.class, server);
+ *   }
+ *
+ *   // ... add customer specific finders and persist logic
+ *
+ *   public List findByName(String nameStart) {
+ *     return query().where()
+ *             .istartsWith("name", nameStart)
+ *             .findList();
+ *   }
+ *
+ * }
+ * }
+ * + * @param The ID type + * @param The Bean type + */ +public abstract class BeanRepository extends BeanFinder { + + /** + * Create with the given bean type and EbeanServer instance. + *

+ * Typically users would extend BeanRepository rather than BeanFinder. + *

+ *
{@code
+   *
+   *   @Inject
+   *   public CustomerRepository(EbeanServer server) {
+   *     super(Customer.class, server);
+   *   }
+   *
+   * }
+ * + * @param type The bean type + * @param server The EbeanServer instance typically created via Spring factory or equivalent + */ + protected BeanRepository(Class type, EbeanServer server) { + super(type, server); + } + + /** + * Marks the entity bean as dirty. + *

+ * This is used so that when a bean that is otherwise unmodified is updated the version + * property is updated. + *

+ * An unmodified bean that is saved or updated is normally skipped and this marks the bean as + * dirty so that it is not skipped. + *

+ *

{@code
+   *
+   * Customer customer = customerRepository.byId(id);
+   *
+   * // mark the bean as dirty so that a save() or update() will
+   * // increment the version property
+   *
+   * customerRepository.markAsDirty(customer);
+   * customerRepository.save(customer);
+   *
+   * }
+ * + * @see EbeanServer#markAsDirty(Object) + */ + public void markAsDirty(T bean) { + db().markAsDirty(bean); + } + + /** + * Mark the property as unset or 'not loaded'. + *

+ * This would be used to specify a property that we did not wish to include in a stateless update. + *

+ *
{@code
+   *
+   *   // populate an entity bean from JSON or whatever
+   *   Customer customer = ...;
+   *
+   *   // mark the email property as 'unset' so that it is not
+   *   // included in a 'stateless update'
+   *   customerRepository.markPropertyUnset(customer, "email");
+   *
+   *   customerRepository.update(customer);
+   *
+   * }
+ * + * @param propertyName the name of the property on the bean to be marked as 'unset' + */ + public void markPropertyUnset(T bean, String propertyName) { + ((EntityBean) bean)._ebean_getIntercept().setPropertyLoaded(propertyName, false); + } + + /** + * Insert or update this entity depending on its state. + *

+ * Ebean will detect if this is a new bean or a previously fetched bean and perform either an + * insert or an update based on that. + * + * @see EbeanServer#save(Object) + */ + public void save(T bean) { + db().save(bean); + } + + /** + * Update this entity. + * + * @see EbeanServer#update(Object) + */ + public void update(T bean) { + db().update(bean); + } + + /** + * Insert this entity. + * + * @see EbeanServer#insert(Object) + */ + public void insert(T bean) { + db().insert(bean); + } + + /** + * Delete this bean. + *

+ * This will return true if the bean was deleted successfully or JDBC batch is being used. + *

+ *

+ * If there is no current transaction one will be created and committed for + * you automatically. + *

+ *

+ * If the Bean does not have a version property (or loaded version property) and + * the bean does not exist then this returns false indicating that nothing was + * deleted. Note that, if JDBC batch mode is used then this always returns true. + *

+ * + * @see EbeanServer#delete(Object) + */ + public boolean delete(T bean) { + return db().delete(bean); + } + + /** + * Delete a bean permanently without soft delete. + *

+ * This is used when the bean contains a @SoftDelete property and we + * want to perform a hard/permanent delete. + *

+ * + * @see EbeanServer#deletePermanent(Object) + */ + public boolean deletePermanent(T bean) { + return db().deletePermanent(bean); + } + + /** + * Refreshes this entity from the database. + * + * @see EbeanServer#refresh(Object) + */ + public void refresh(T bean) { + db().refresh(bean); + } +} diff --git a/src/test/java/org/tests/repository/CustomerRepository.java b/src/test/java/org/tests/repository/CustomerRepository.java new file mode 100644 index 000000000..31d18ef96 --- /dev/null +++ b/src/test/java/org/tests/repository/CustomerRepository.java @@ -0,0 +1,36 @@ +package org.tests.repository; + +import io.ebean.BeanRepository; +import io.ebean.EbeanServer; +import org.tests.model.basic.Customer; + +import javax.inject.Inject; +import java.util.List; + +public class CustomerRepository extends BeanRepository { + + @Inject + public CustomerRepository(EbeanServer server) { + super(Customer.class, server); + } + + public List findByName(String nameStart) { + return query().where() + .istartsWith("name", nameStart) + .findList(); + } + + public Customer findMatchName(String matchName) { + return nativeSql("select id, name from o_customer where name = ?") + .setParameter(1, matchName) + .findOne(); + } + + public int updateNotes(String blah, String whot) { + + return updateQuery() + .set("smallnote", whot) + .where().eq("name", blah) + .update(); + } +} diff --git a/src/test/java/org/tests/repository/TestBeanRepository.java b/src/test/java/org/tests/repository/TestBeanRepository.java new file mode 100644 index 000000000..cd2f7f666 --- /dev/null +++ b/src/test/java/org/tests/repository/TestBeanRepository.java @@ -0,0 +1,61 @@ +package org.tests.repository; + +import io.ebean.BaseTestCase; +import org.junit.Test; +import org.tests.model.basic.Customer; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestBeanRepository extends BaseTestCase { + + @Test + public void test() { + + CustomerRepository repository = new CustomerRepository(server()); + + Customer customer = new Customer(); + customer.setName("RepoCustomer"); + + repository.save(customer); + + Customer fetchCustomer = repository.findById(customer.getId()); + fetchCustomer.setSmallnote("yeah maybe"); + + repository.update(fetchCustomer); + repository.delete(fetchCustomer); + } + + @Test + public void findByName() { + + CustomerRepository repository = new CustomerRepository(server()); + + Customer blah = new Customer(); + blah.setName("Blah"); + + repository.markAsDirty(blah); + repository.markPropertyUnset(blah, "smallnote"); + repository.save(blah); + + Optional maybe = repository.findByIdOrEmpty(blah.getId()); + assertThat(maybe.isPresent()).isTrue(); + + List names = repository.findByName("bla"); + assertThat(names).hasSize(1); + + Customer matchName = repository.findMatchName("Blah"); + assertThat(matchName).isNotNull(); + + int rows = repository.updateNotes("Blah", "whot"); + assertThat(rows).isEqualTo(1); + + repository.deletePermanent(blah); + + repository.deleteById(1099); + repository.findAll(); + + } +} From 265bda8cf23b3499d6d11c95189696ecbbe0e60b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 17:41:01 +1300 Subject: [PATCH 0065/1036] #1272 - ENH: Add built in support for Joda Period --- .../server/type/DefaultTypeManager.java | 1 + .../server/type/ScalarTypeJodaPeriod.java | 39 +++++++++++++++++ .../server/type/ScalarTypeJodaPeriodTest.java | 43 +++++++++++++++++++ .../org/tests/model/joda/BasicJodaEntity.java | 11 +++++ .../model/joda/TestJodaInsertUpdate.java | 12 +++++- 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriod.java create mode 100644 src/test/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriodTest.java diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index a6dd341d4..369928843 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -875,6 +875,7 @@ public final class DefaultTypeManager implements TypeManager { typeMap.put(DateTime.class, new ScalarTypeJodaDateTime(mode)); typeMap.put(LocalDate.class, new ScalarTypeJodaLocalDate()); typeMap.put(org.joda.time.DateMidnight.class, new ScalarTypeJodaDateMidnight()); + typeMap.put(org.joda.time.Period.class, new ScalarTypeJodaPeriod()); String jodaLocalTimeMode = config.getJodaLocalTimeMode(); if ("normal".equalsIgnoreCase(jodaLocalTimeMode)) { diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriod.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriod.java new file mode 100644 index 000000000..5d3e3ee4e --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriod.java @@ -0,0 +1,39 @@ +package io.ebeaninternal.server.type; + +import org.joda.time.Period; + +/** + * ScalarType for Joda Period stored as DB VARCHAR + */ +public class ScalarTypeJodaPeriod extends ScalarTypeBaseVarchar { + + public ScalarTypeJodaPeriod() { + super(Period.class); + } + + @Override + public int getLength() { + return 50; + } + + @Override + public String formatValue(Period v) { + return v.toString(); + } + + @Override + public Period parse(String value) { + return Period.parse(value); + } + + @Override + public Period convertFromDbString(String dbValue) { + return Period.parse(dbValue); + } + + @Override + public String convertToDbString(Period beanValue) { + return beanValue.toString(); + } + +} diff --git a/src/test/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriodTest.java b/src/test/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriodTest.java new file mode 100644 index 000000000..3a58e9fbf --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/type/ScalarTypeJodaPeriodTest.java @@ -0,0 +1,43 @@ +package io.ebeaninternal.server.type; + +import org.joda.time.Period; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScalarTypeJodaPeriodTest { + + private ScalarTypeJodaPeriod scalarType = new ScalarTypeJodaPeriod(); + + @Test + public void getLength() { + assertThat(scalarType.getLength()).isEqualTo(50); + } + + @Test + public void formatAndParse() { + + Period original = Period.years(1).plusMonths(2).plusDays(4) + .plusHours(12).plusMinutes(19).plusSeconds(20); + + String value = scalarType.formatValue(original); + assertThat(value).isEqualTo("P1Y2M4DT12H19M20S"); + + Period period = scalarType.parse(value); + assertThat(period).isEqualTo(original); + } + + + @Test + public void convertFromDbString() { + + Period original = Period.years(1).plusMonths(2).plusDays(4) + .plusHours(23).plusMinutes(19).plusSeconds(20).plusMillis(987); + + String stringVal = scalarType.convertToDbString(original); + Period period = scalarType.convertFromDbString(stringVal); + + assertThat(period).isEqualTo(original); + } + +} diff --git a/src/test/java/org/tests/model/joda/BasicJodaEntity.java b/src/test/java/org/tests/model/joda/BasicJodaEntity.java index acb025fe0..52e528e27 100644 --- a/src/test/java/org/tests/model/joda/BasicJodaEntity.java +++ b/src/test/java/org/tests/model/joda/BasicJodaEntity.java @@ -4,6 +4,7 @@ import io.ebean.annotation.CreatedTimestamp; import io.ebean.annotation.UpdatedTimestamp; import org.joda.time.DateTime; import org.joda.time.LocalDateTime; +import org.joda.time.Period; import javax.persistence.Entity; import javax.persistence.Id; @@ -23,6 +24,8 @@ public class BasicJodaEntity { @UpdatedTimestamp DateTime updated; + Period period; + @Version LocalDateTime version; @@ -42,6 +45,14 @@ public class BasicJodaEntity { this.name = name; } + public Period getPeriod() { + return period; + } + + public void setPeriod(Period period) { + this.period = period; + } + public LocalDateTime getCreated() { return created; } diff --git a/src/test/java/org/tests/model/joda/TestJodaInsertUpdate.java b/src/test/java/org/tests/model/joda/TestJodaInsertUpdate.java index 7240eca43..df8a79fb5 100644 --- a/src/test/java/org/tests/model/joda/TestJodaInsertUpdate.java +++ b/src/test/java/org/tests/model/joda/TestJodaInsertUpdate.java @@ -4,9 +4,13 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import org.joda.time.DateTime; import org.joda.time.LocalDateTime; +import org.joda.time.Period; import org.junit.Test; -import static org.junit.Assert.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; public class TestJodaInsertUpdate extends BaseTestCase { @@ -27,6 +31,7 @@ public class TestJodaInsertUpdate extends BaseTestCase { Thread.sleep(10); e0.setName("bar"); + e0.setPeriod(Period.years(12).plusDays(1)); Ebean.save(e0); LocalDateTime created1 = e0.getCreated(); @@ -36,5 +41,10 @@ public class TestJodaInsertUpdate extends BaseTestCase { assertSame(created, created1); assertNotSame(updated, updated1); assertNotSame(version, version1); + + + BasicJodaEntity found = Ebean.find(BasicJodaEntity.class, e0.getId()); + + assertThat(found.getPeriod()).isEqualTo(e0.getPeriod()); } } From 75462e7410fd30e7f9384f6ccb19392bb58a7798 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 23 Feb 2018 17:54:02 +1300 Subject: [PATCH 0066/1036] #1272 - ENH: Add built in support for Joda Period and java time Period --- .../server/type/DefaultTypeManager.java | 1 + .../server/type/ScalarTypePeriod.java | 39 +++++++++++++++++ .../server/type/ScalarTypePeriodTest.java | 42 +++++++++++++++++++ .../tests/model/types/SomeNewTypesBean.java | 11 +++++ .../java/org/tests/types/TestNewTypes.java | 19 ++++++--- 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/type/ScalarTypePeriod.java create mode 100644 src/test/java/io/ebeaninternal/server/type/ScalarTypePeriodTest.java diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 369928843..6bdb05661 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -838,6 +838,7 @@ public final class DefaultTypeManager implements TypeManager { if (config.getClassLoadConfig().isJavaTimePresent()) { logger.debug("Registering java.time data types"); + typeMap.put(java.time.Period.class, new ScalarTypePeriod()); typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate()); typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(mode)); typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime(mode)); diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypePeriod.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypePeriod.java new file mode 100644 index 000000000..573ba6e5c --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypePeriod.java @@ -0,0 +1,39 @@ +package io.ebeaninternal.server.type; + +import java.time.Period; + +/** + * ScalarType for Joda Period stored as DB VARCHAR + */ +public class ScalarTypePeriod extends ScalarTypeBaseVarchar { + + public ScalarTypePeriod() { + super(Period.class); + } + + @Override + public int getLength() { + return 20; + } + + @Override + public String formatValue(Period v) { + return v.toString(); + } + + @Override + public Period parse(String value) { + return Period.parse(value); + } + + @Override + public Period convertFromDbString(String dbValue) { + return Period.parse(dbValue); + } + + @Override + public String convertToDbString(Period beanValue) { + return beanValue.toString(); + } + +} diff --git a/src/test/java/io/ebeaninternal/server/type/ScalarTypePeriodTest.java b/src/test/java/io/ebeaninternal/server/type/ScalarTypePeriodTest.java new file mode 100644 index 000000000..858c2d10d --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/type/ScalarTypePeriodTest.java @@ -0,0 +1,42 @@ +package io.ebeaninternal.server.type; + +import org.junit.Test; + +import java.time.Period; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScalarTypePeriodTest { + + private ScalarTypePeriod scalarType = new ScalarTypePeriod(); + + @Test + public void getLength() { + assertThat(scalarType.getLength()).isEqualTo(20); + } + + @Test + public void formatAndParse() { + + Period original = Period.of(1,2, 4); + + String value = scalarType.formatValue(original); + assertThat(value).isEqualTo("P1Y2M4D"); + + Period period = scalarType.parse(value); + assertThat(period).isEqualTo(original); + } + + + @Test + public void convertFromDbString() { + + Period original = Period.of(1, 2, 4); + + String stringVal = scalarType.convertToDbString(original); + Period period = scalarType.convertFromDbString(stringVal); + + assertThat(period).isEqualTo(original); + } + +} diff --git a/src/test/java/org/tests/model/types/SomeNewTypesBean.java b/src/test/java/org/tests/model/types/SomeNewTypesBean.java index 3374615b2..64f0a2220 100644 --- a/src/test/java/org/tests/model/types/SomeNewTypesBean.java +++ b/src/test/java/org/tests/model/types/SomeNewTypesBean.java @@ -11,6 +11,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; import java.time.OffsetDateTime; +import java.time.Period; import java.time.Year; import java.time.YearMonth; import java.time.ZoneId; @@ -54,6 +55,8 @@ public class SomeNewTypesBean { Path path; + Period period; + public Long getId() { return id; } @@ -165,4 +168,12 @@ public class SomeNewTypesBean { public void setPath(Path path) { this.path = path; } + + public Period getPeriod() { + return period; + } + + public void setPeriod(Period period) { + this.period = period; + } } diff --git a/src/test/java/org/tests/types/TestNewTypes.java b/src/test/java/org/tests/types/TestNewTypes.java index a08c03b93..de34a2d71 100644 --- a/src/test/java/org/tests/types/TestNewTypes.java +++ b/src/test/java/org/tests/types/TestNewTypes.java @@ -2,11 +2,10 @@ package org.tests.types; import io.ebean.BaseTestCase; import io.ebean.Ebean; -import org.tests.model.types.SomeNewTypesBean; import org.junit.Test; +import org.tests.model.types.SomeNewTypesBean; import java.io.File; -import java.io.IOException; import java.nio.file.Paths; import java.time.DayOfWeek; import java.time.Instant; @@ -14,20 +13,23 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; import java.time.OffsetDateTime; +import java.time.Period; import java.time.Year; import java.time.YearMonth; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class TestNewTypes extends BaseTestCase { private static final String TEMP_PATH = new File("/tmp").getAbsolutePath(); @Test - public void testInsertUpdate() throws IOException, InterruptedException { + public void testInsertUpdate() throws InterruptedException { SomeNewTypesBean bean = new SomeNewTypesBean(); bean.setLocalDate(LocalDate.now()); bean.setLocalDateTime(LocalDateTime.now()); @@ -41,6 +43,7 @@ public class TestNewTypes extends BaseTestCase { bean.setZoneOffset(ZonedDateTime.now().getOffset()); bean.setYearMonth(YearMonth.of(2014, 9)); bean.setPath(Paths.get(TEMP_PATH)); + bean.setPeriod(Period.of(4,3,2)); Ebean.save(bean); @@ -83,6 +86,9 @@ public class TestNewTypes extends BaseTestCase { list = Ebean.find(SomeNewTypesBean.class).where().eq("path", Paths.get(TEMP_PATH)).findList(); assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList(); + assertTrue(!list.isEmpty()); + SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId()); assertEquals(bean.getZoneId(), fetched.getZoneId()); @@ -95,6 +101,8 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getOffsetDateTime(), fetched.getOffsetDateTime()); assertEquals(bean.getInstant(), fetched.getInstant()); assertEquals(bean.getPath(), fetched.getPath()); + assertEquals(bean.getPeriod(), fetched.getPeriod()); + String asJson = Ebean.json().toJson(fetched); @@ -111,6 +119,7 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getInstant(), toBean.getInstant()); // FIXME: This test fails on Windows with: expected:<\tmp> but was: assertEquals(bean.getPath(), toBean.getPath()); + assertEquals(bean.getPeriod(), toBean.getPeriod()); } @@ -133,6 +142,6 @@ public class TestNewTypes extends BaseTestCase { assertNull(fetched.getOffsetDateTime()); assertNull(fetched.getInstant()); assertNull(fetched.getPath()); - + assertNull(fetched.getPeriod()); } } From 8e9843ab8ae35d7d7a5b14c7cdce43a163f34a63 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Feb 2018 08:35:47 +1300 Subject: [PATCH 0067/1036] #1246 - Support use of application.yml and application-test.yml ... (as alternative to ebean.properties, test-ebean.properties) --- pom.xml | 10 + src/main/java/io/ebean/PrimaryServer.java | 4 +- .../io/ebean/config/PropertiesWrapper.java | 46 +--- .../io/ebean/config/PropertyExpression.java | 178 --------------- .../java/io/ebean/config/PropertyMap.java | 168 --------------- .../io/ebean/config/PropertyMapLoader.java | 163 -------------- .../java/io/ebean/config/ServerConfig.java | 12 +- .../ebean/config/properties/LoadContext.java | 97 +++++++++ .../io/ebean/config/properties/Loader.java | 164 ++++++++++++++ .../config/properties/PropertiesLoader.java | 58 +++++ .../ebean/config/properties/PropertyEval.java | 202 ++++++++++++++++++ .../ebean/config/properties/YamlLoader.java | 54 +++++ .../server/core/DefaultContainer.java | 7 +- .../ebean/config/PropertiesWrapperTest.java | 29 +-- .../java/io/ebean/config/PropertyMapTest.java | 23 -- .../ebean/config/properties/LoaderTest.java | 65 ++++++ .../config/properties/PropertyEvalTest.java | 73 +++++++ .../transaction/TestAutoCommitDataSource.java | 8 +- .../TestExplicitTransactionMode.java | 8 +- .../test-properties/application.properties | 2 + .../resources/test-properties/application.yml | 8 + src/test/resources/test-properties/foo.yml | 17 ++ .../resources/test-properties/one.properties | 3 + test-dummy.properties | 1 + test-dummy.yml | 3 + 25 files changed, 788 insertions(+), 615 deletions(-) delete mode 100644 src/main/java/io/ebean/config/PropertyExpression.java delete mode 100644 src/main/java/io/ebean/config/PropertyMap.java delete mode 100644 src/main/java/io/ebean/config/PropertyMapLoader.java create mode 100644 src/main/java/io/ebean/config/properties/LoadContext.java create mode 100644 src/main/java/io/ebean/config/properties/Loader.java create mode 100644 src/main/java/io/ebean/config/properties/PropertiesLoader.java create mode 100644 src/main/java/io/ebean/config/properties/PropertyEval.java create mode 100644 src/main/java/io/ebean/config/properties/YamlLoader.java delete mode 100644 src/test/java/io/ebean/config/PropertyMapTest.java create mode 100644 src/test/java/io/ebean/config/properties/LoaderTest.java create mode 100644 src/test/java/io/ebean/config/properties/PropertyEvalTest.java create mode 100644 src/test/resources/test-properties/application.properties create mode 100644 src/test/resources/test-properties/application.yml create mode 100644 src/test/resources/test-properties/foo.yml create mode 100644 src/test/resources/test-properties/one.properties create mode 100644 test-dummy.properties create mode 100644 test-dummy.yml diff --git a/pom.xml b/pom.xml index 5d56073f8..b83d0f88f 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,16 @@ provided + + + org.yaml + snakeyaml + 1.19 + provided + + + dbClockDelta + ${dbClockDelta} + diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index a7cbb0644..bdef878cf 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -22,7 +22,23 @@ public abstract class BaseTestCase { protected static Logger logger = LoggerFactory.getLogger(BaseTestCase.class); + /** + * this is the clock delta that may occur between testing machine and db server. + * If the clock delta of DB server is in future, an "asOf" query may not find the + * correct entry. + * + * Note: That some tests may use a Thread.sleep to wait, so that the local system clock + * can catch up. So don't set that to a too high value. + */ + public static final int DB_CLOCK_DELTA; + static { + String s = System.getProperty("dbClockDelta"); + if (s != null && !s.isEmpty()) { + DB_CLOCK_DELTA = Integer.parseInt(s); + } else { + DB_CLOCK_DELTA = 100; + } logger.debug("... preStart"); if (!AgentLoader.loadAgentFromClasspath("ebean-agent", "debug=1")) { logger.info("avaje-ebeanorm-agent not found in classpath - not dynamically loaded"); diff --git a/src/test/java/org/tests/history/TestHistoryInsert.java b/src/test/java/org/tests/history/TestHistoryInsert.java index 2331c26f1..bdbcb873d 100644 --- a/src/test/java/org/tests/history/TestHistoryInsert.java +++ b/src/test/java/org/tests/history/TestHistoryInsert.java @@ -34,7 +34,7 @@ public class TestHistoryInsert extends BaseTestCase { Ebean.save(user); logger.info("-- initial save"); - Thread.sleep(100); + Thread.sleep(DB_CLOCK_DELTA); // wait, so that our system clock can catch up Timestamp afterInsert = new Timestamp(System.currentTimeMillis()); List history = fetchHistory(user); diff --git a/src/test/java/org/tests/model/history/TestHistoryExclude.java b/src/test/java/org/tests/model/history/TestHistoryExclude.java index b7b11bbb3..a8b4c746f 100644 --- a/src/test/java/org/tests/model/history/TestHistoryExclude.java +++ b/src/test/java/org/tests/model/history/TestHistoryExclude.java @@ -44,7 +44,7 @@ public class TestHistoryExclude extends BaseTestCase { prepare(); HeLink linkFound = Ebean.find(HeLink.class) - .asOf(new Timestamp(System.currentTimeMillis())) + .asOf(new Timestamp(System.currentTimeMillis() + DB_CLOCK_DELTA)) .setId(link.getId()) .findOne(); diff --git a/src/test/java/org/tests/model/history/TestHistoryInclude.java b/src/test/java/org/tests/model/history/TestHistoryInclude.java index f556ad7d0..1ba178b70 100644 --- a/src/test/java/org/tests/model/history/TestHistoryInclude.java +++ b/src/test/java/org/tests/model/history/TestHistoryInclude.java @@ -44,7 +44,7 @@ public class TestHistoryInclude extends BaseTestCase { prepare(); HiLink linkFound = Ebean.find(HiLink.class) - .asOf(new Timestamp(System.currentTimeMillis())) + .asOf(new Timestamp(System.currentTimeMillis() + DB_CLOCK_DELTA)) .setId(link.getId()) .findOne(); From 78f8d48e2e8b414cb8d4909168a4a6b41f4663d9 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 26 Feb 2018 23:00:58 +0100 Subject: [PATCH 0086/1036] FIX: more timing issues - mysql does not support resolution in millis (#1288) --- .../java/org/tests/draftable/DocLinkTest.java | 2 +- .../embedded/TestMultipleEmbeddedLoading.java | 3 ++- src/test/java/org/tests/types/TestNewTypes.java | 15 ++++++++------- .../org/tests/update/TestStatelessUpdate.java | 3 ++- .../java/org/tests/update/TestUpdatePartial.java | 3 ++- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/tests/draftable/DocLinkTest.java b/src/test/java/org/tests/draftable/DocLinkTest.java index 98259c101..48b5c6213 100644 --- a/src/test/java/org/tests/draftable/DocLinkTest.java +++ b/src/test/java/org/tests/draftable/DocLinkTest.java @@ -175,7 +175,7 @@ public class DocLinkTest extends BaseTestCase { Link linkLive = server.publish(Link.class, link1.getId(), null); StrictAssertions.assertThat(linkLive.getComment()).isEqualTo(comment); - StrictAssertions.assertThat(linkLive.getWhenPublish()).isEqualTo(when); + StrictAssertions.assertThat(linkLive.getWhenPublish()).isEqualToIgnoringMillis(when); Link draft1b = Ebean.find(Link.class).setId(link1.getId()).asDraft().findOne(); StrictAssertions.assertThat(draft1b.isDirty()).isFalse(); diff --git a/src/test/java/org/tests/query/embedded/TestMultipleEmbeddedLoading.java b/src/test/java/org/tests/query/embedded/TestMultipleEmbeddedLoading.java index e5a158d6f..b6ca2d3c0 100644 --- a/src/test/java/org/tests/query/embedded/TestMultipleEmbeddedLoading.java +++ b/src/test/java/org/tests/query/embedded/TestMultipleEmbeddedLoading.java @@ -13,6 +13,7 @@ import org.junit.Test; import java.util.Date; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -46,7 +47,7 @@ public class TestMultipleEmbeddedLoading extends BaseTestCase { // assert fetched bean populated as expected assertEquals(invoice.getId(), invoice2.getId()); assertEquals(invoice.getState(), invoice2.getState()); - assertEquals(invoice.getInvoiceDate(), invoice2.getInvoiceDate()); + assertThat(invoice2.getInvoiceDate()).isEqualToIgnoringMillis(invoice.getInvoiceDate()); assertEquals("2 Apple St", invoice.getBillAddress().getStreet()); assertEquals("2 Apple St", invoice2.getBillAddress().getStreet()); diff --git a/src/test/java/org/tests/types/TestNewTypes.java b/src/test/java/org/tests/types/TestNewTypes.java index de34a2d71..8248c8028 100644 --- a/src/test/java/org/tests/types/TestNewTypes.java +++ b/src/test/java/org/tests/types/TestNewTypes.java @@ -20,6 +20,7 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -52,7 +53,7 @@ public class TestNewTypes extends BaseTestCase { bean.setMonth(Month.SEPTEMBER); Ebean.save(bean); - Thread.sleep(10); // wait, to ensure that instant < Instant.now() + Thread.sleep(DB_CLOCK_DELTA); // wait, to ensure that instant < Instant.now() List list = Ebean.find(SomeNewTypesBean.class).where().lt("instant", Instant.now()).findList(); assertTrue(!list.isEmpty()); @@ -97,9 +98,9 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getYear(), fetched.getYear()); assertEquals(bean.getYearMonth(), fetched.getYearMonth()); assertEquals(bean.getLocalDate(), fetched.getLocalDate()); - assertEquals(bean.getLocalDateTime(), fetched.getLocalDateTime()); - assertEquals(bean.getOffsetDateTime(), fetched.getOffsetDateTime()); - assertEquals(bean.getInstant(), fetched.getInstant()); + assertThat(fetched.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime()); + assertThat(fetched.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime()); + assertEquals(bean.getInstant().toEpochMilli() / 1000, fetched.getInstant().toEpochMilli() / 1000); assertEquals(bean.getPath(), fetched.getPath()); assertEquals(bean.getPeriod(), fetched.getPeriod()); @@ -114,9 +115,9 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getYear(), toBean.getYear()); assertEquals(bean.getYearMonth(), toBean.getYearMonth()); assertEquals(bean.getLocalDate(), toBean.getLocalDate()); - assertEquals(bean.getLocalDateTime(), toBean.getLocalDateTime()); - assertEquals(bean.getOffsetDateTime(), toBean.getOffsetDateTime()); - assertEquals(bean.getInstant(), toBean.getInstant()); + assertThat(toBean.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime()); + assertThat(toBean.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime()); + assertEquals(bean.getInstant().toEpochMilli() / 1000, toBean.getInstant().toEpochMilli() / 1000); // FIXME: This test fails on Windows with: expected:<\tmp> but was: assertEquals(bean.getPath(), toBean.getPath()); assertEquals(bean.getPeriod(), toBean.getPeriod()); diff --git a/src/test/java/org/tests/update/TestStatelessUpdate.java b/src/test/java/org/tests/update/TestStatelessUpdate.java index 72eb8b8a3..1362893a6 100644 --- a/src/test/java/org/tests/update/TestStatelessUpdate.java +++ b/src/test/java/org/tests/update/TestStatelessUpdate.java @@ -16,6 +16,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -119,7 +120,7 @@ public class TestStatelessUpdate extends BaseTestCase { Customer result = Ebean.find(Customer.class, customer.getId()); // assert - assertEquals(customer.getUpdtime().getTime(), result.getUpdtime().getTime()); + assertThat(result.getUpdtime()).isEqualToIgnoringMillis(customer.getUpdtime()); } /** diff --git a/src/test/java/org/tests/update/TestUpdatePartial.java b/src/test/java/org/tests/update/TestUpdatePartial.java index 722ed9f0a..091e10a1c 100644 --- a/src/test/java/org/tests/update/TestUpdatePartial.java +++ b/src/test/java/org/tests/update/TestUpdatePartial.java @@ -7,6 +7,7 @@ import io.ebean.SqlRow; import org.tests.model.basic.Customer; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; public class TestUpdatePartial extends BaseTestCase { @@ -69,6 +70,6 @@ public class TestUpdatePartial extends BaseTestCase { Customer customerWithoutChanges = Ebean.find(Customer.class, customer.getId()); Ebean.save(customerWithoutChanges); - assertEquals(customer.getUpdtime().getTime(), customerWithoutChanges.getUpdtime().getTime()); + assertThat(customerWithoutChanges.getUpdtime()).isEqualToIgnoringMillis(customer.getUpdtime()); } } From ac9f3408b28fd8a898f756e617377a549ae21d8b Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 26 Feb 2018 23:03:27 +0100 Subject: [PATCH 0087/1036] FIX: reset cache statistics (fixes test cases in eclipse when run in different order) (#1289) --- src/test/java/org/tests/cache/TestQueryCacheInsert.java | 1 + src/test/java/org/tests/readaudit/TestReadAudit.java | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/tests/cache/TestQueryCacheInsert.java b/src/test/java/org/tests/cache/TestQueryCacheInsert.java index dad6caf1f..3a5ca02ea 100644 --- a/src/test/java/org/tests/cache/TestQueryCacheInsert.java +++ b/src/test/java/org/tests/cache/TestQueryCacheInsert.java @@ -45,6 +45,7 @@ public class TestQueryCacheInsert extends BaseTestCase { Ebean.save(doda); ServerCache queryCache = Ebean.getServerCacheManager().getQueryCache(EBasicVer.class); + queryCache.getStatistics(true); Optional found0 = Ebean.find(EBasicVer.class) .where().eq("description", "OddButUniqueSillyExample") diff --git a/src/test/java/org/tests/readaudit/TestReadAudit.java b/src/test/java/org/tests/readaudit/TestReadAudit.java index 22a0257d6..d41e7fd13 100644 --- a/src/test/java/org/tests/readaudit/TestReadAudit.java +++ b/src/test/java/org/tests/readaudit/TestReadAudit.java @@ -83,6 +83,9 @@ public class TestReadAudit extends BaseTestCase { public void test_findById_usingL2Cache() { resetCounters(); + ServerCache beanCache = server.getServerCacheManager().getBeanCache(EBasicChangeLog.class); + beanCache.getStatistics(true); + EBasicChangeLog found = server.find(EBasicChangeLog.class, id1); assertThat(found).isNotNull(); assertThat(readAuditPrepare.count).isEqualTo(1); @@ -91,7 +94,6 @@ public class TestReadAudit extends BaseTestCase { assertThat(readAuditLogger.beans.get(0).getBeanType()).isEqualTo(EBasicChangeLog.class.getName()); assertThat(readAuditLogger.beans.get(0).getId()).isEqualTo(id1); - ServerCache beanCache = server.getServerCacheManager().getBeanCache(EBasicChangeLog.class); ServerCacheStatistics statistics = beanCache.getStatistics(false); assertThat(statistics.getSize()).isEqualTo(1); assertThat(statistics.getHitCount()).isEqualTo(0); @@ -109,6 +111,9 @@ public class TestReadAudit extends BaseTestCase { public void test_findById_usingL2Cache_sharedBean() { resetCounters(); + ServerCache beanCache = server.getServerCacheManager().getBeanCache(Country.class); + beanCache.getStatistics(true); + Country found = server.find(Country.class, "AR"); assertThat(found).isNotNull(); assertThat(readAuditPrepare.count).isEqualTo(1); @@ -117,7 +122,6 @@ public class TestReadAudit extends BaseTestCase { assertThat(readAuditLogger.beans.get(0).getBeanType()).isEqualTo(Country.class.getName()); assertThat(readAuditLogger.beans.get(0).getId()).isEqualTo("AR"); - ServerCache beanCache = server.getServerCacheManager().getBeanCache(Country.class); ServerCacheStatistics statistics = beanCache.getStatistics(false); assertThat(statistics.getSize()).isEqualTo(1); assertThat(statistics.getHitCount()).isEqualTo(0); From bb418456e39e6131e1d19c4b8a09f80099d43fdc Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 26 Feb 2018 23:06:35 +0100 Subject: [PATCH 0088/1036] Misc fixes (#1290) --- .../dbmigration/DbMigrationTest.java | 6 ++++++ .../java/org/tests/delete/TestDeleteByQuery.java | 9 +++++---- .../java/org/tests/history/TestHistoryInsert.java | 8 ++++---- src/test/java/org/tests/query/TestWhereIn.java | 10 ++-------- .../org/tests/rawsql/TestRawSqlNamedParams.java | 15 ++++++++++----- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java index 0bf580245..569f63311 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java @@ -66,6 +66,12 @@ public class DbMigrationTest extends BaseTestCase { "migtest_e_ref", "migtest_e_softdelete", "migtest_e_user", + "migtest_fk_cascade", + "migtest_fk_cascade_one", + "migtest_fk_none", + "migtest_fk_none_via_join", + "migtest_fk_one", + "migtest_fk_set_null", "migtest_mtm_c", "migtest_mtm_m", "migtest_mtm_c_migtest_mtm_m", diff --git a/src/test/java/org/tests/delete/TestDeleteByQuery.java b/src/test/java/org/tests/delete/TestDeleteByQuery.java index 4adeef974..89dd04c72 100644 --- a/src/test/java/org/tests/delete/TestDeleteByQuery.java +++ b/src/test/java/org/tests/delete/TestDeleteByQuery.java @@ -4,6 +4,9 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; import io.ebean.Query; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; + import org.tests.model.basic.Contact; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; @@ -17,13 +20,11 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestDeleteByQuery extends BaseTestCase { @Test + @IgnorePlatform(Platform.MYSQL) + // FIXME: MySql does not the sub query selecting from the delete table public void test() { EbeanServer server = Ebean.getDefaultServer(); - if (server.getName().equals("mysql")) { - // MySql does not the sub query selecting from the delete table - return; - } Query query = server.find(Contact.class).where().eq("group.name", "NahYeahMaybe").query(); diff --git a/src/test/java/org/tests/history/TestHistoryInsert.java b/src/test/java/org/tests/history/TestHistoryInsert.java index bdbcb873d..67a1e93e4 100644 --- a/src/test/java/org/tests/history/TestHistoryInsert.java +++ b/src/test/java/org/tests/history/TestHistoryInsert.java @@ -5,6 +5,9 @@ import io.ebean.Ebean; import io.ebean.SqlQuery; import io.ebean.SqlRow; import io.ebean.Version; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; + import org.tests.model.converstation.User; import org.junit.Test; import org.slf4j.Logger; @@ -20,12 +23,9 @@ public class TestHistoryInsert extends BaseTestCase { private final Logger logger = LoggerFactory.getLogger(TestHistoryInsert.class); @Test + @ForPlatform({Platform.H2, Platform.POSTGRES}) public void test() throws InterruptedException { - if (!isH2() && !isPostgres()) { - return; - } - User user = new User(); user.setName("Jim"); user.setEmail("one@email.com"); diff --git a/src/test/java/org/tests/query/TestWhereIn.java b/src/test/java/org/tests/query/TestWhereIn.java index 9fa85e82a..4be3ecb91 100644 --- a/src/test/java/org/tests/query/TestWhereIn.java +++ b/src/test/java/org/tests/query/TestWhereIn.java @@ -7,7 +7,6 @@ import org.junit.Test; import org.tests.model.basic.Country; import org.tests.model.basic.ResetBasicData; -import static org.assertj.core.api.Assertions.assertThat; public class TestWhereIn extends BaseTestCase { @@ -21,10 +20,7 @@ public class TestWhereIn extends BaseTestCase { .query(); query.findList(); - if (isPostgres()) { - assertThat(sqlOf(query)).contains(" = any("); - } - + platformAssertIn(sqlOf(query), ""); } @@ -38,8 +34,6 @@ public class TestWhereIn extends BaseTestCase { .query(); query.findList(); - if (isPostgres()) { - assertThat(sqlOf(query)).contains(" != all("); - } + platformAssertNotIn(sqlOf(query), ""); } } diff --git a/src/test/java/org/tests/rawsql/TestRawSqlNamedParams.java b/src/test/java/org/tests/rawsql/TestRawSqlNamedParams.java index e123f30f0..62f3f3002 100644 --- a/src/test/java/org/tests/rawsql/TestRawSqlNamedParams.java +++ b/src/test/java/org/tests/rawsql/TestRawSqlNamedParams.java @@ -7,12 +7,16 @@ import io.ebean.Query; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; import io.ebean.Transaction; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; + import org.tests.model.basic.Customer; import org.tests.model.basic.Order; import org.tests.model.basic.ResetBasicData; import org.junit.Assert; import org.junit.Test; +import java.sql.SQLException; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -40,16 +44,17 @@ public class TestRawSqlNamedParams extends BaseTestCase { } @Test - public void testMySqlColonEquals() { - - if (!isMySql()) { - return; - } + @ForPlatform(Platform.MYSQL) + public void testMySqlColonEquals() throws SQLException { ResetBasicData.reset(); Transaction transaction = Ebean.beginTransaction(); + try { + if ("MariaDB connector/J".equals(transaction.getConnection().getMetaData().getDriverName())) { + return; // MariaDb only supports callable statements in the form "? = call function x(?)" + } CallableSql callableSql = Ebean.createCallableSql("set @total = 0"); Ebean.execute(callableSql); From 83cf768369d224d3e6396322f1a832fe3047b3d5 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 26 Feb 2018 23:09:44 +0100 Subject: [PATCH 0089/1036] Append preconfigured database to dbMigration (#1291) --- src/main/java/io/ebean/dbmigration/DbMigration.java | 8 ++++++++ .../io/ebeaninternal/dbmigration/DefaultDbMigration.java | 5 +++++ .../dbmigration/DbMigrationGenerateTest.java | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebean/dbmigration/DbMigration.java b/src/main/java/io/ebean/dbmigration/DbMigration.java index eaa0dee3b..cd9c122a0 100644 --- a/src/main/java/io/ebean/dbmigration/DbMigration.java +++ b/src/main/java/io/ebean/dbmigration/DbMigration.java @@ -102,6 +102,14 @@ public interface DbMigration { */ void addPlatform(Platform platform, String prefix); + /** + * Add an additional databasePlatform to write the migration DDL. + *

+ * Use this when you want to add preconfigured database platforms. + *

+ */ + void addDatabasePlatform(DatabasePlatform databasePlatform, String prefix); + /** * Generate the next migration xml file and associated apply and rollback sql scripts. *

diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index a8d4877c9..9bf36c631 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -183,6 +183,11 @@ public class DefaultDbMigration implements DbMigration { platforms.add(new Pair(getPlatform(platform), prefix)); } + @Override + public void addDatabasePlatform(DatabasePlatform databasePlatform, String prefix) { + platforms.add(new Pair(databasePlatform, prefix)); + } + /** * Generate the next migration xml file and associated apply and rollback sql scripts. *

diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java index 6ea8a19e3..6d16f0d1c 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java @@ -4,6 +4,9 @@ import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; +import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.IdType; +import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; import org.junit.*; import org.slf4j.Logger; @@ -52,7 +55,11 @@ public class DbMigrationGenerateTest { migration.addPlatform(Platform.POSTGRES, "postgres"); migration.addPlatform(Platform.ORACLE, "oracle"); migration.addPlatform(Platform.SQLITE, "sqlite"); - migration.addPlatform(Platform.SQLSERVER, "sqlserver"); + + // we need sequence here, so that migration will work properly + DatabasePlatform sqlServer = new SqlServerPlatform(); + sqlServer.getDbIdentity().setIdType(IdType.SEQUENCE); + migration.addDatabasePlatform(sqlServer, "sqlserver"); ServerConfig config = new ServerConfig(); config.setName("migrationtest"); From e751f991cba1125d1b15948eac9b77e9c5428778 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 11:31:30 +1300 Subject: [PATCH 0090/1036] #1275 - Additional refactor for - Add ServerConfig.setDefaultOrderById() ... Removes the cast on DefaultOrmQuery.prepare() --- src/main/java/io/ebeaninternal/api/SpiQuery.java | 4 ++-- .../ebeaninternal/server/core/OrmQueryRequest.java | 3 +-- .../server/core/SpiOrmQueryRequest.java | 5 +++-- .../server/querydefn/DefaultOrmQuery.java | 8 ++++---- .../server/querydefn/DefaultOrmQueryTest.java | 14 +++++++------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index 869f2ca1c..1134d660f 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -9,10 +9,10 @@ import io.ebean.Query; import io.ebean.bean.CallStack; import io.ebean.bean.ObjectGraphNode; import io.ebean.bean.PersistenceContext; -import io.ebean.event.BeanQueryRequest; import io.ebean.event.readaudit.ReadEvent; import io.ebean.plugin.BeanType; import io.ebeaninternal.server.autotune.ProfilingListener; +import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.TableJoin; @@ -566,7 +566,7 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { * The query plan excludes actual bind values (as they don't effect the query plan). *

*/ - CQueryPlanKey prepare(BeanQueryRequest request); + CQueryPlanKey prepare(SpiOrmQueryRequest request); /** * Calculate a hash based on the bind values used in the query. diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index e63a49d56..7df2185b3 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -12,7 +12,6 @@ import io.ebean.common.BeanList; import io.ebean.common.CopyOnFirstWriteList; import io.ebean.event.BeanFindController; import io.ebean.event.BeanQueryAdapter; -import io.ebean.event.BeanQueryRequest; import io.ebean.text.json.JsonReadOptions; import io.ebeaninternal.api.BeanCacheResult; import io.ebeaninternal.api.CQueryPlanKey; @@ -52,7 +51,7 @@ import java.util.function.Predicate; /** * Wraps the objects involved in executing a Query. */ -public final class OrmQueryRequest extends BeanRequest implements BeanQueryRequest, SpiOrmQueryRequest { +public final class OrmQueryRequest extends BeanRequest implements SpiOrmQueryRequest { private static final Logger log = LoggerFactory.getLogger(OrmQueryRequest.class); diff --git a/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java index 279ddf6c9..32ab198ff 100644 --- a/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.core; import io.ebean.QueryIterator; import io.ebean.Version; +import io.ebean.event.BeanQueryRequest; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeanservice.docstore.api.DocQueryRequest; @@ -15,7 +16,7 @@ import java.util.function.Predicate; /** * Defines the ORM query request api. */ -public interface SpiOrmQueryRequest extends DocQueryRequest { +public interface SpiOrmQueryRequest extends BeanQueryRequest, DocQueryRequest { /** * Return the query. @@ -26,7 +27,7 @@ public interface SpiOrmQueryRequest extends DocQueryRequest { /** * Return the associated BeanDescriptor. */ - BeanDescriptor getBeanDescriptor(); + BeanDescriptor getBeanDescriptor(); /** * This will create a local (readOnly) transaction if no current transaction diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 6a8648e90..103e5d483 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -39,7 +39,7 @@ import io.ebeaninternal.api.SpiNamedParam; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuerySecondary; import io.ebeaninternal.server.autotune.ProfilingListener; -import io.ebeaninternal.server.core.OrmQueryRequest; +import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.TableJoin; @@ -1040,10 +1040,10 @@ public class DefaultOrmQuery implements SpiQuery { * Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key. */ @Override - public CQueryPlanKey prepare(BeanQueryRequest request) { + public CQueryPlanKey prepare(SpiOrmQueryRequest request) { prepareExpressions(request); - prepareForPaging((OrmQueryRequest) request); + prepareForPaging(request); queryPlanKey = createQueryPlanKey(); return queryPlanKey; } @@ -1066,7 +1066,7 @@ public class DefaultOrmQuery implements SpiQuery { * property to ensure unique row ordering for predicable paging but only in * case, this is not a distinct query */ - private void prepareForPaging(OrmQueryRequest request) { + private void prepareForPaging(SpiOrmQueryRequest request) { // add the rawSql statement - if any if (orderByIsEmpty()) { diff --git a/src/test/java/io/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java b/src/test/java/io/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java index 0d3ee55c9..d9e621221 100644 --- a/src/test/java/io/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java +++ b/src/test/java/io/ebeaninternal/server/querydefn/DefaultOrmQueryTest.java @@ -18,7 +18,7 @@ public class DefaultOrmQueryTest extends BaseTestCase { public void when_forUpdate_then_excludeFromBeanCache() { DefaultOrmQuery q1 = (DefaultOrmQuery) Ebean.find(Customer.class) - .setForUpdate(true).where().eq("id", 42).query(); + .forUpdate().where().eq("id", 42).query(); assertThat(q1.getUseBeanCache()).isSameAs(CacheMode.OFF); } @@ -88,13 +88,13 @@ public class DefaultOrmQueryTest extends BaseTestCase { } @Test - public void when_diffFirstMaxRows_then_differentPlan() throws Exception { + public void when_diffFirstMaxRows_then_differentPlan() { - DefaultOrmQuery query1 = (DefaultOrmQuery) Ebean.find(Order.class) + DefaultOrmQuery query1 = (DefaultOrmQuery) Ebean.find(Order.class) .setFirstRow(0) .setMaxRows(31); - DefaultOrmQuery query2 = (DefaultOrmQuery) Ebean.find(Order.class) + DefaultOrmQuery query2 = (DefaultOrmQuery) Ebean.find(Order.class) .setFirstRow(1) .setMaxRows(0); @@ -102,12 +102,12 @@ public class DefaultOrmQueryTest extends BaseTestCase { assertThat(query1.createQueryPlanKey()).isNotEqualTo(query2.createQueryPlanKey()); } - private void prepare(DefaultOrmQuery q1, DefaultOrmQuery q2) { + private void prepare(DefaultOrmQuery q1, DefaultOrmQuery q2) { - OrmQueryRequest r1 = createQueryRequest(SpiQuery.Type.LIST, q1, null); + OrmQueryRequest r1 = createQueryRequest(SpiQuery.Type.LIST, q1, null); q1.prepare(r1); - OrmQueryRequest r2 = createQueryRequest(SpiQuery.Type.LIST, q2, null); + OrmQueryRequest r2 = createQueryRequest(SpiQuery.Type.LIST, q2, null); q2.prepare(r2); } } From a569c7fc960570141fef7835b12e6ef59aa6ed97 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 11:35:10 +1300 Subject: [PATCH 0091/1036] #1275 - Additional refactor of DefaultOrmQuery.prepareForPaging() for - Add ServerConfig.setDefaultOrderById() ... Remove use of SpiOrmQueryRequest request --- .../io/ebeaninternal/server/querydefn/DefaultOrmQuery.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 103e5d483..ded44b52e 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1043,7 +1043,7 @@ public class DefaultOrmQuery implements SpiQuery { public CQueryPlanKey prepare(SpiOrmQueryRequest request) { prepareExpressions(request); - prepareForPaging(request); + prepareForPaging(); queryPlanKey = createQueryPlanKey(); return queryPlanKey; } @@ -1066,17 +1066,16 @@ public class DefaultOrmQuery implements SpiQuery { * property to ensure unique row ordering for predicable paging but only in * case, this is not a distinct query */ - private void prepareForPaging(SpiOrmQueryRequest request) { + private void prepareForPaging() { // add the rawSql statement - if any if (orderByIsEmpty()) { - SpiRawSql rawSql = getRawSql(); if (rawSql != null && rawSql.getSql() != null) { order(rawSql.getSql().getOrderBy()); } } if (checkPagingOrderBy()) { - request.getBeanDescriptor().appendOrderById(this); + beanDescriptor.appendOrderById(this); } } /** From 3dfdd0e2e878d6815e77b9a676501bfdebc06c77 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 26 Feb 2018 23:58:10 +0100 Subject: [PATCH 0092/1036] #1292 - Fix for non-native / number boolean types (MySql, SqlServer, Oracle, Sqlite, SqlAnywhere) removing "default 0" + Fix for DB2 add foreign key update clause --- howto-test.md | 13 +++++----- .../dbplatform/mysql/MySqlPlatform.java | 9 +++++-- .../dbplatform/oracle/OraclePlatform.java | 6 ++++- .../dbplatform/postgres/PostgresPlatform.java | 2 ++ .../sqlanywhere/SqlAnywherePlatform.java | 2 +- .../dbplatform/sqlite/SQLitePlatform.java | 7 ++++-- .../sqlserver/SqlServerPlatform.java | 5 +++- .../ddlgeneration/platform/DB2Ddl.java | 6 +++++ .../ddlgeneration/platform/PlatformDdl.java | 24 ++++++------------ .../config/dbplatform/MySqlPlatformTest.java | 4 +-- .../config/dbplatform/OraclePlatformTest.java | 2 +- .../migrationtest/db2/1.0__initial.sql | 6 ++--- .../dbmigration/migrationtest/db2/1.1.sql | 24 +++++++++--------- .../dbmigration/migrationtest/db2/1.3.sql | 8 +++--- .../dbmigration/migrationtest/h2/1.1.sql | 14 +++++------ .../dbmigration/migrationtest/h2/1.3.sql | 2 +- .../dbmigration/migrationtest/hsqldb/1.1.sql | 14 +++++------ .../dbmigration/migrationtest/hsqldb/1.3.sql | 2 +- .../migrationtest/mysql/1.0__initial.sql | 2 +- .../dbmigration/migrationtest/mysql/1.1.sql | 12 ++++----- .../dbmigration/migrationtest/mysql/1.3.sql | 2 +- .../migrationtest/oracle/1.0__initial.sql | 2 +- .../dbmigration/migrationtest/oracle/1.1.sql | 12 ++++----- .../dbmigration/migrationtest/oracle/1.3.sql | 2 +- .../migrationtest/postgres/1.1.sql | 14 +++++------ .../migrationtest/postgres/1.3.sql | 2 +- .../migrationtest/sqlite/1.0__initial.sql | 2 +- .../dbmigration/migrationtest/sqlite/1.1.sql | 12 ++++----- .../dbmigration/migrationtest/sqlite/1.3.sql | 2 +- .../migrationtest/sqlserver/1.0__initial.sql | 25 +++++++++---------- .../migrationtest/sqlserver/1.1.sql | 12 ++++----- .../migrationtest/sqlserver/1.3.sql | 6 ++--- 32 files changed, 135 insertions(+), 122 deletions(-) diff --git a/howto-test.md b/howto-test.md index 243ed5200..dcb2c727d 100644 --- a/howto-test.md +++ b/howto-test.md @@ -48,7 +48,8 @@ Reqirements run: `mvn clean test -Ddatasource.default=pg` Current status: PASS -Tests run: 1986, Failures: 0, Errors: 0, Skipped: 16 +Tests run: 2166, Failures: 0, Errors: 0, Skipped: 25 + 'mysql' platform @@ -61,8 +62,8 @@ Reqirements run: `mvn clean test -Ddatasource.default=mysql` -Current status: FAIL -Tests run: 1986, Failures: 2, Errors: 4, Skipped: 16 +Current status: PASS +Tests run: 2166, Failures: 0, Errors: 0, Skipped: 33 @@ -76,8 +77,8 @@ Reqires an installed sqlserver - e.g. https://hub.docker.com/r/microsoft/mssql-s run: `mvn clean test -Ddatasource.default=mssql` -Current status: FAIL -Tests run: 1986, Failures: 19, Errors: 43, Skipped: 16 +Current status: PASS +Tests run: 2166, Failures: 0, Errors: 0, Skipped: 39 @@ -107,7 +108,7 @@ Reqires a locally installed DB2 Express-C server. run: `mvn clean test -Ddatasource.default=db2 -Pdb2` Current status: FAIL -Tests run: 1986, Failures: 33, Errors: 26, Skipped: 16 +Tests run: 2166, Failures: 29, Errors: 58, Skipped: 30 'sqlite' platform diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java index bea7ed391..9ee373288 100644 --- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java @@ -35,6 +35,11 @@ public class MySqlPlatform extends DatabasePlatform { this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsIdentity(true); this.dbIdentity.setSupportsSequence(false); + + this.dbDefaultValue.setNow("now(6)"); // must have same precision as TIMESTAMP + this.dbDefaultValue.setFalse("0"); + this.dbDefaultValue.setTrue("1"); + this.exceptionTranslator = new SqlErrorCodes() @@ -52,8 +57,8 @@ public class MySqlPlatform extends DatabasePlatform { this.forwardOnlyHintOnFindIterate = true; this.booleanDbType = Types.BIT; - dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1) default 0")); - dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1) default 0")); + dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1)")); + dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1)")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)")); dbTypeMap.put(DbType.CLOB, new MySqlClob()); dbTypeMap.put(DbType.BLOB, new MySqlBlob()); diff --git a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java index b73f8091a..3eae9a8c6 100644 --- a/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/oracle/OraclePlatform.java @@ -35,6 +35,10 @@ public class OraclePlatform extends DatabasePlatform { 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 ?"; @@ -49,7 +53,7 @@ public class OraclePlatform extends DatabasePlatform { this.closeQuote = "\""; booleanDbType = Types.INTEGER; - dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1) default 0")); + dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("number(1)")); dbTypeMap.put(DbType.INTEGER, new DbPlatformType("number", 10)); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("number", 19)); diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java index 20d9107d1..9a9b584fd 100644 --- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java @@ -39,6 +39,8 @@ public class PostgresPlatform extends DatabasePlatform { this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsSequence(true); + this.dbDefaultValue.setNow("current_timestamp"); + this.exceptionTranslator = new SqlErrorCodes() .addAcquireLock("55P03") diff --git a/src/main/java/io/ebean/config/dbplatform/sqlanywhere/SqlAnywherePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlanywhere/SqlAnywherePlatform.java index 045eeab30..7ca86a219 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlanywhere/SqlAnywherePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlanywhere/SqlAnywherePlatform.java @@ -27,7 +27,7 @@ public class SqlAnywherePlatform extends DatabasePlatform { this.dbIdentity.setSelectLastInsertedIdTemplate("select @@IDENTITY as X"); this.dbIdentity.setSupportsIdentity(true); - dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0")); + dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit")); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19)); dbTypeMap.put(DbType.REAL, new DbPlatformType("float(16)")); dbTypeMap.put(DbType.DOUBLE, new DbPlatformType("float(32)")); diff --git a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java index b4957f6d1..2e15fd007 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlite/SQLitePlatform.java @@ -21,9 +21,12 @@ public class SQLitePlatform extends DatabasePlatform { this.booleanDbType = Types.INTEGER; this.likeClauseRaw = "like ?"; this.likeClauseEscaped = "like ?"; + this.dbDefaultValue.setFalse("0"); + this.dbDefaultValue.setTrue("1"); + this.dbDefaultValue.setNow("CURRENT_TIMESTAMP"); - dbTypeMap.put(DbType.BIT, new DbPlatformType("int default 0")); - dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int default 0")); + dbTypeMap.put(DbType.BIT, new DbPlatformType("int")); + dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("int")); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("integer")); dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("integer")); } diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java index 102a7e0d5..31e1a8525 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java @@ -51,7 +51,10 @@ public class SqlServerPlatform extends DatabasePlatform { this.likeClauseEscaped = "like ? collate Latin1_General_BIN"; booleanDbType = Types.INTEGER; - dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit default 0")); + this.dbDefaultValue.setFalse("0"); + this.dbDefaultValue.setTrue("1"); + this.dbDefaultValue.setNow("SYSUTCDATETIME()"); + dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("bit")); dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false)); dbTypeMap.put(DbType.BIGINT, new DbPlatformType("numeric", 19)); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java index 17a463d60..d3cf92028 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DB2Ddl.java @@ -1,5 +1,6 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; +import io.ebean.annotation.ConstraintMode; import io.ebean.config.dbplatform.DatabasePlatform; /** @@ -27,4 +28,9 @@ public class DB2Ddl extends PlatformDdl { } } + @Override + protected void appendForeignKeyOnUpdate(StringBuilder buffer, ConstraintMode mode) { + // do nothing, no on update clause for db2 + } + } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index db37454c6..512d6efc2 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -213,7 +213,7 @@ public class PlatformDdl { buffer.append(" "); buffer.append(lowerColumnName(column.getName()), 29); buffer.append(platformType); - if (!Boolean.TRUE.equals(column.isPrimaryKey()) && !typeContainsDefault(platformType)) { + if (!Boolean.TRUE.equals(column.isPrimaryKey())) { String defaultValue = convertDefaultValue(column.getDefaultValue()); if (defaultValue != null) { buffer.append(" default ").append(defaultValue); @@ -227,13 +227,6 @@ public class PlatformDdl { // so that the database can potentially provide a nice SQL error } - /** - * Return true if the type definition already contains a default value. - */ - private boolean typeContainsDefault(String platformType) { - return platformType.toLowerCase().contains(" default"); - } - /** * Convert the DB column default literal to platform specific. */ @@ -449,17 +442,14 @@ public class PlatformDdl { .append(" ").append(convertedType); if (!onHistoryTable) { - if (isTrue(column.isNotnull())) { - buffer.append(" not null"); - } if (defaultValue != null) { - if (typeContainsDefault(convertedType)) { - logger.error("Cannot set default value for '" + tableName + "." + column.getName() + "'"); - } else { - buffer.append(" default "); - buffer.append(defaultValue); - } + buffer.append(" default "); + buffer.append(defaultValue); + } + + if (isTrue(column.isNotnull())) { + buffer.append(" not null"); } buffer.endOfStatement(); diff --git a/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java b/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java index 74a789348..ed0fc2bf9 100644 --- a/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java @@ -20,8 +20,8 @@ public class MySqlPlatformTest { assertThat(ddl.convert("json", false)).isEqualTo("longtext"); assertThat(ddl.convert("jsonb", false)).isEqualTo("longtext"); assertThat(ddl.convert("varchar(20)", false)).isEqualTo("varchar(20)"); - assertThat(ddl.convert("boolean", false)).isEqualTo("tinyint(1) default 0"); - assertThat(ddl.convert("bit", false)).isEqualTo("tinyint(1) default 0"); + assertThat(ddl.convert("boolean", false)).isEqualTo("tinyint(1)"); + assertThat(ddl.convert("bit", false)).isEqualTo("tinyint(1)"); } @Test diff --git a/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java b/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java index 4f21ae90c..11da787e2 100644 --- a/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java @@ -27,7 +27,7 @@ public class OraclePlatformTest { assertThat(ddl.convert("varchar(20)", false)).isEqualTo("varchar2(20)"); assertThat(ddl.convert("decimal(10)", false)).isEqualTo("number(10)"); assertThat(ddl.convert("decimal(8,4)", false)).isEqualTo("number(8,4)"); - assertThat(ddl.convert("boolean", false)).isEqualTo("number(1) default 0"); + assertThat(ddl.convert("boolean", false)).isEqualTo("number(1)"); assertThat(ddl.convert("bit", false)).isEqualTo("bit"); assertThat(ddl.convert("tinyint", false)).isEqualTo("number(3)"); assertThat(ddl.convert("binary(16)", false)).isEqualTo("raw(16)"); diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql index ebd35cdcf..2ed9f31ab 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql @@ -81,12 +81,12 @@ create table migtest_e_softdelete ( create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.1.sql b/src/test/resources/dbmigration/migrationtest/db2/1.1.sql index 26650c8ff..2304caa0c 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.1.sql @@ -6,11 +6,11 @@ create table migtest_e_user ( ); alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete restrict on update restrict; -alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; -alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete restrict; +alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; +alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict; update migtest_e_basic set status = 'A' where status is null; alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; @@ -26,16 +26,16 @@ alter table migtest_e_basic alter column some_date set default '2000-01-01T00:00 alter table migtest_e_basic alter column some_date set not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; -alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; +alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict; alter table migtest_e_basic alter column user_id set null; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field boolean not null default true; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field boolean default true not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 boolean not null default true; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 boolean default true not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -50,11 +50,11 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; alter table migtest_e_history2 alter column test_string set not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); -alter table migtest_e_softdelete add column deleted boolean not null default false; +alter table migtest_e_softdelete add column deleted boolean default false not null; create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.3.sql b/src/test/resources/dbmigration/migrationtest/db2/1.3.sql index d8c19fa03..e99cc4048 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.3.sql @@ -6,11 +6,11 @@ create table migtest_e_ref ( ); alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id; alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id; alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null; alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; alter table migtest_e_basic alter column status drop default; alter table migtest_e_basic alter column status set null; @@ -23,7 +23,7 @@ update migtest_e_basic set user_id = 23 where user_id is null; alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; -alter table migtest_e_basic add column old_boolean boolean not null default false; +alter table migtest_e_basic add column old_boolean boolean default false not null; alter table migtest_e_basic add column old_boolean2 boolean; alter table migtest_e_basic add column eref_id integer; @@ -40,6 +40,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index ix_migtest_e_basic_indextest3; drop index ix_migtest_e_basic_indextest6; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.1.sql b/src/test/resources/dbmigration/migrationtest/h2/1.1.sql index 733391e0f..e786f4ecc 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.1.sql @@ -28,14 +28,14 @@ alter table migtest_e_basic alter column some_date set not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; alter table migtest_e_basic alter column user_id set null; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field boolean not null default true; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field boolean default true not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 boolean not null default true; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 boolean default true not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -50,11 +50,11 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; alter table migtest_e_history2 alter column test_string set not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); -alter table migtest_e_softdelete add column deleted boolean not null default false; +alter table migtest_e_softdelete add column deleted boolean default false not null; create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.3.sql b/src/test/resources/dbmigration/migrationtest/h2/1.3.sql index e096649a9..9f3c659df 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.3.sql @@ -23,7 +23,7 @@ update migtest_e_basic set user_id = 23 where user_id is null; alter table migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id; alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; -alter table migtest_e_basic add column old_boolean boolean not null default false; +alter table migtest_e_basic add column old_boolean boolean default false not null; alter table migtest_e_basic add column old_boolean2 boolean; alter table migtest_e_basic add column eref_id integer; diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql index 8fcfa6dbe..3c48db53c 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql @@ -28,14 +28,14 @@ alter table migtest_e_basic alter column some_date set not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; alter table migtest_e_basic alter column user_id set null; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field boolean not null default true; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field boolean default true not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 boolean not null default true; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 boolean default true not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -50,11 +50,11 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; alter table migtest_e_history2 alter column test_string set not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); -alter table migtest_e_softdelete add column deleted boolean not null default false; +alter table migtest_e_softdelete add column deleted boolean default false not null; create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql index 4f2436cbd..d89e67fd1 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql @@ -23,7 +23,7 @@ update migtest_e_basic set user_id = 23 where user_id is null; alter table migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id; alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; -alter table migtest_e_basic add column old_boolean boolean not null default false; +alter table migtest_e_basic add column old_boolean boolean default false not null; alter table migtest_e_basic add column old_boolean2 boolean; alter table migtest_e_basic add column eref_id integer; diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql index 7bfa87ed5..8d5563048 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql @@ -41,7 +41,7 @@ create table migtest_e_basic ( description varchar(127), some_date datetime(6), old_boolean tinyint(1) default 0 not null, - old_boolean2 tinyint(1) default 0, + old_boolean2 tinyint(1), eref_id integer, indextest1 varchar(127), indextest2 varchar(127), diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql index 9025e83c4..3fc961b1a 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql @@ -27,14 +27,14 @@ alter table migtest_e_basic modify some_date datetime(6) not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; alter table migtest_e_basic modify user_id integer; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field tinyint(1) default 0 not null; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field tinyint(1) default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 tinyint(1) default 0 not null; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 tinyint(1) default 1 not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop index uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop index uq_migtest_e_basic_indextest6; @@ -48,7 +48,7 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter test_string set default 'unknown'; alter table migtest_e_history2 modify test_string varchar(255) not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql index 6a4f5c74d..a408ec0f3 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql @@ -21,7 +21,7 @@ alter table migtest_e_basic drop foreign key fk_migtest_e_basic_user_id; alter table migtest_e_basic alter user_id set default 23; alter table migtest_e_basic modify user_id integer not null; alter table migtest_e_basic add column old_boolean tinyint(1) default 0 not null; -alter table migtest_e_basic add column old_boolean2 tinyint(1) default 0; +alter table migtest_e_basic add column old_boolean2 tinyint(1); alter table migtest_e_basic add column eref_id integer; alter table migtest_e_basic drop index uq_migtest_e_basic_name; diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql index d621493ff..fce202026 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql @@ -47,7 +47,7 @@ create table migtest_e_basic ( description varchar2(127), some_date timestamp, old_boolean number(1) default 0 not null, - old_boolean2 number(1) default 0, + old_boolean2 number(1), eref_id number(10), indextest1 varchar2(127), indextest2 varchar2(127), diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql index 99bf46431..6f280989f 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql @@ -29,14 +29,14 @@ alter table migtest_e_basic modify some_date not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); alter table migtest_e_basic modify user_id null; -alter table migtest_e_basic add column new_string_field varchar2(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field number(1) default 0 not null; +alter table migtest_e_basic add column new_string_field varchar2(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field number(1) default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 number(1) default 0 not null; -alter table migtest_e_basic add column progress number(10) not null default 0; +alter table migtest_e_basic add column new_boolean_field2 number(1) default 1 not null; +alter table migtest_e_basic add column progress number(10) default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer number(10) not null default 42; +alter table migtest_e_basic add column new_integer number(10) default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -51,7 +51,7 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 modify test_string default 'unknown'; alter table migtest_e_history2 modify test_string not null; alter table migtest_e_history2 add column test_string2 varchar2(255); -alter table migtest_e_history2 add column test_string3 varchar2(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar2(255) default 'unknown' not null; alter table migtest_e_softdelete add column deleted number(1) default 0 not null; diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql index 60e6bbf6a..f5cc85a85 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql @@ -25,7 +25,7 @@ alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; alter table migtest_e_basic modify user_id default 23; alter table migtest_e_basic modify user_id not null; alter table migtest_e_basic add column old_boolean number(1) default 0 not null; -alter table migtest_e_basic add column old_boolean2 number(1) default 0; +alter table migtest_e_basic add column old_boolean2 number(1); alter table migtest_e_basic add column eref_id number(10); alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql index d26dab182..21b6c7129 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql @@ -31,14 +31,14 @@ alter table migtest_e_basic alter column some_date set not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; alter table migtest_e_basic alter column user_id drop not null; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field boolean not null default true; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field boolean default true not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 boolean not null default true; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 boolean default true not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -55,11 +55,11 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; alter table migtest_e_history2 alter column test_string set not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); -alter table migtest_e_softdelete add column deleted boolean not null default false; +alter table migtest_e_softdelete add column deleted boolean default false not null; create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql index e68509998..a68497900 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql @@ -23,7 +23,7 @@ update migtest_e_basic set user_id = 23 where user_id is null; alter table if exists migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id; alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; -alter table migtest_e_basic add column old_boolean boolean not null default false; +alter table migtest_e_basic add column old_boolean boolean default false not null; alter table migtest_e_basic add column old_boolean2 boolean; alter table migtest_e_basic add column eref_id integer; diff --git a/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql index cf4fd1839..7817850a0 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlite/1.0__initial.sql @@ -43,7 +43,7 @@ create table migtest_e_basic ( description varchar(127), some_date timestamp, old_boolean int default 0 not null, - old_boolean2 int default 0, + old_boolean2 int, eref_id integer, indextest1 varchar(127), indextest2 varchar(127), diff --git a/src/test/resources/dbmigration/migrationtest/sqlite/1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlite/1.1.sql index f1e14b4fb..6bfca30fe 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlite/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlite/1.1.sql @@ -23,14 +23,14 @@ alter table migtest_e_basic alter column some_date set not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic alter column user_id set null; -alter table migtest_e_basic add column new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add column new_boolean_field int default 0 not null; +alter table migtest_e_basic add column new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add column new_boolean_field int default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; -alter table migtest_e_basic add column new_boolean_field2 int default 0 not null; -alter table migtest_e_basic add column progress integer not null default 0; +alter table migtest_e_basic add column new_boolean_field2 int default 1 not null; +alter table migtest_e_basic add column progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add column new_integer integer not null default 42; +alter table migtest_e_basic add column new_integer integer default 42 not null; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; @@ -43,7 +43,7 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 alter column test_string set default 'unknown'; alter table migtest_e_history2 alter column test_string set not null; alter table migtest_e_history2 add column test_string2 varchar(255); -alter table migtest_e_history2 add column test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add column test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_history2_history add column test_string2 varchar(255); alter table migtest_e_history2_history add column test_string3 varchar(255); diff --git a/src/test/resources/dbmigration/migrationtest/sqlite/1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlite/1.3.sql index 262edf014..77f17afb5 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlite/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlite/1.3.sql @@ -22,7 +22,7 @@ alter table migtest_e_basic drop constraint if exists fk_migtest_e_basic_user_id alter table migtest_e_basic alter column user_id set default 23; alter table migtest_e_basic alter column user_id set not null; alter table migtest_e_basic add column old_boolean int default 0 not null; -alter table migtest_e_basic add column old_boolean2 int default 0; +alter table migtest_e_basic add column old_boolean2 int; alter table migtest_e_basic add column eref_id integer; alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql index 70742f488..58a36d80e 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql @@ -5,41 +5,40 @@ create table migtest_fk_cascade ( one_id numeric(19), constraint pk_migtest_fk_cascade primary key (id) ); -create sequence migtest_fk_cascade_seq as bigint start with 1 increment by 50; +create sequence migtest_fk_cascade_seq as bigint start with 1 ; create table migtest_fk_cascade_one ( id numeric(19) not null, constraint pk_migtest_fk_cascade_one primary key (id) ); -create sequence migtest_fk_cascade_one_seq as bigint start with 1 increment by 50; +create sequence migtest_fk_cascade_one_seq as bigint start with 1 ; create table migtest_fk_none ( id numeric(19) not null, one_id numeric(19), constraint pk_migtest_fk_none primary key (id) ); -create sequence migtest_fk_none_seq as bigint start with 1 increment by 50; +create sequence migtest_fk_none_seq as bigint start with 1 ; create table migtest_fk_none_via_join ( id numeric(19) not null, one_id numeric(19), constraint pk_migtest_fk_none_via_join primary key (id) ); -create sequence migtest_fk_none_via_join_seq as bigint start with 1 increment by 50; +create sequence migtest_fk_none_via_join_seq as bigint start with 1 ; create table migtest_fk_one ( id numeric(19) not null, constraint pk_migtest_fk_one primary key (id) ); -create sequence migtest_fk_one_seq as bigint start with 1 increment by 50; - +create sequence migtest_fk_one_seq as bigint start with 1 ; create table migtest_fk_set_null ( id numeric(19) not null, one_id numeric(19), constraint pk_migtest_fk_set_null primary key (id) ); -create sequence migtest_fk_set_null_seq as bigint start with 1 increment by 50; +create sequence migtest_fk_set_null_seq as bigint start with 1 ; create table migtest_e_basic ( id integer not null, @@ -48,7 +47,7 @@ create table migtest_e_basic ( description varchar(127), some_date datetime2, old_boolean bit default 0 not null, - old_boolean2 bit default 0, + old_boolean2 bit, eref_id integer, indextest1 varchar(127), indextest2 varchar(127), @@ -62,34 +61,34 @@ create table migtest_e_basic ( ); create unique nonclustered index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) where indextest2 is not null; create unique nonclustered index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) where indextest6 is not null; -create sequence migtest_e_basic_seq as bigint start with 1 increment by 50; +create sequence migtest_e_basic_seq as bigint start with 1 ; create table migtest_e_history ( id integer not null, test_string varchar(255), constraint pk_migtest_e_history primary key (id) ); -create sequence pk_migtest_e_history_seq as bigint start with 1 increment by 50; +create sequence migtest_e_history_seq as bigint start with 1 ; create table migtest_e_history2 ( id integer not null, test_string varchar(255), constraint pk_migtest_e_history2 primary key (id) ); -create sequence migtest_e_history2_seq as bigint start with 1 increment by 50; +create sequence migtest_e_history2_seq as bigint start with 1 ; create table migtest_e_ref ( id integer not null, constraint pk_migtest_e_ref primary key (id) ); -create sequence migtest_e_ref_seq as bigint start with 1 increment by 50; +create sequence migtest_e_ref_seq as bigint start with 1 ; create table migtest_e_softdelete ( id integer not null, test_string varchar(255), constraint pk_migtest_e_softdelete primary key (id) ); -create sequence migtest_e_softdelete_seq as bigint start with 1 increment by 50; +create sequence migtest_e_softdelete_seq as bigint start with 1 ; create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql index 9bdf6cdc6..b873a0152 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql @@ -4,7 +4,7 @@ create table migtest_e_user ( id integer not null, constraint pk_migtest_e_user primary key (id) ); -create sequence migtest_e_user_seq as bigint start with 1 increment by 50; +create sequence migtest_e_user_seq as bigint start with 1 ; IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id); @@ -29,14 +29,14 @@ alter table migtest_e_basic alter column some_date datetime2 not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); alter table migtest_e_basic alter column user_id integer; -alter table migtest_e_basic add new_string_field varchar(255) not null default 'foo''bar'; -alter table migtest_e_basic add new_boolean_field bit default 0 not null; +alter table migtest_e_basic add new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add new_boolean_field bit default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; alter table migtest_e_basic add new_boolean_field2 bit default 1 not null; -alter table migtest_e_basic add progress integer not null default 0; +alter table migtest_e_basic add progress integer default 0 not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add new_integer integer not null default 42; +alter table migtest_e_basic add new_integer integer default 42 not null; IF (OBJECT_ID('uq_migtest_e_basic_indextest2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest2') drop index uq_migtest_e_basic_indextest2 ON migtest_e_basic; @@ -51,7 +51,7 @@ update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 add default 'unknown' for test_string; alter table migtest_e_history2 alter column test_string varchar(255) not null; alter table migtest_e_history2 add test_string2 varchar(255); -alter table migtest_e_history2 add test_string3 varchar(255) not null default 'unknown'; +alter table migtest_e_history2 add test_string3 varchar(255) default 'unknown' not null; alter table migtest_e_softdelete add deleted bit default 0 not null; diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql index c6add60d1..944c52349 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql @@ -1,10 +1,10 @@ -- Migrationscripts for ebean unittest -- apply changes create table migtest_e_ref ( - id integer identity(1,1) not null, + id integer not null, constraint pk_migtest_e_ref primary key (id) ); -create sequence migtest_e_ref_seq as bigint start with 1 increment by 50; +create sequence migtest_e_ref_seq as bigint start with 1 ; IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; @@ -32,7 +32,7 @@ IF OBJECT_ID('fk_migtest_e_basic_user_id', 'F') IS NOT NULL alter table migtest_ alter table migtest_e_basic add default 23 for user_id; alter table migtest_e_basic alter column user_id integer not null; alter table migtest_e_basic add old_boolean bit default 0 not null; -alter table migtest_e_basic add old_boolean2 bit default 0; +alter table migtest_e_basic add old_boolean2 bit; alter table migtest_e_basic add eref_id integer; IF (OBJECT_ID('uq_migtest_e_basic_name', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; From 06bce35f5ad7d3f530114c85e580e913393ab717 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 12:56:20 +1300 Subject: [PATCH 0093/1036] #1293 - Refactor - move JdbcClose into io.ebean.util ... from io.ebeaninternal.util as it is used in public API (platform code, sequences etc) --- .../config/dbplatform/DatabasePlatform.java | 2 +- .../dbplatform/SequenceIdGenerator.java | 2 +- .../dbplatform/SimpleSequenceIdGenerator.java | 25 +++----------- .../util/JdbcClose.java | 2 +- .../server/core/RelationalQueryRequest.java | 21 ++---------- .../server/persist/ExeCallableSql.java | 17 +++------- .../server/persist/ExeOrmUpdate.java | 13 ++----- .../server/persist/ExeUpdateSql.java | 14 ++------ .../server/persist/dml/InsertHandler.java | 28 +++------------ .../io/ebeaninternal/server/query/CQuery.java | 13 +++---- .../query/CQueryFetchSingleAttribute.java | 11 ++---- .../server/query/CQueryRowCount.java | 5 +-- .../server/query/CQueryUpdate.java | 3 +- .../ebeaninternal/server/query/UtilJdbc.java | 34 ------------------- .../transaction/JtaTransactionManager.java | 2 +- .../transaction/TransactionFactory.java | 2 +- .../transaction/TransactionFactoryBasic.java | 2 +- .../TransactionFactoryBasicWithRead.java | 2 +- .../transaction/TransactionFactoryTenant.java | 2 +- .../TransactionFactoryTenantWithRead.java | 2 +- 20 files changed, 43 insertions(+), 159 deletions(-) rename src/main/java/io/{ebeaninternal => ebean}/util/JdbcClose.java (97%) delete mode 100644 src/main/java/io/ebeaninternal/server/query/UtilJdbc.java diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 2f105e0d6..166a9b5df 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -7,7 +7,7 @@ import io.ebean.annotation.Platform; import io.ebean.config.CustomDbTypeMapping; import io.ebean.config.DbTypeConfig; import io.ebean.config.ServerConfig; -import io.ebeaninternal.util.JdbcClose; // FIXME: should not import ebeaninternal here +import io.ebean.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java index 985a545c6..44f20e643 100644 --- a/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java @@ -2,7 +2,7 @@ package io.ebean.config.dbplatform; import io.ebean.BackgroundExecutor; import io.ebean.Transaction; -import io.ebeaninternal.util.JdbcClose; +import io.ebean.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/ebean/config/dbplatform/SimpleSequenceIdGenerator.java b/src/main/java/io/ebean/config/dbplatform/SimpleSequenceIdGenerator.java index 902579384..95ee33894 100644 --- a/src/main/java/io/ebean/config/dbplatform/SimpleSequenceIdGenerator.java +++ b/src/main/java/io/ebean/config/dbplatform/SimpleSequenceIdGenerator.java @@ -1,6 +1,7 @@ package io.ebean.config.dbplatform; import io.ebean.Transaction; +import io.ebean.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,27 +83,9 @@ public class SimpleSequenceIdGenerator implements PlatformIdGenerator { } private void closeResources(ResultSet rset, PreparedStatement pstmt, Connection c) { - try { - if (rset != null) { - rset.close(); - } - } catch (SQLException e) { - logger.error("Error closing ResultSet", e); - } - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } - try { - if (c != null) { - c.close(); - } - } catch (SQLException e) { - logger.error("Error closing Connection", e); - } + JdbcClose.close(rset); + JdbcClose.close(pstmt); + JdbcClose.close(c); } } diff --git a/src/main/java/io/ebeaninternal/util/JdbcClose.java b/src/main/java/io/ebean/util/JdbcClose.java similarity index 97% rename from src/main/java/io/ebeaninternal/util/JdbcClose.java rename to src/main/java/io/ebean/util/JdbcClose.java index f74e3dd46..92b3f7e28 100644 --- a/src/main/java/io/ebeaninternal/util/JdbcClose.java +++ b/src/main/java/io/ebean/util/JdbcClose.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.util; +package io.ebean.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java index 115c7e93c..9461142f0 100644 --- a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java @@ -4,6 +4,7 @@ import io.ebean.EbeanServer; import io.ebean.SqlQuery; import io.ebean.SqlRow; import io.ebean.Transaction; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiSqlQuery; @@ -14,8 +15,6 @@ import io.ebeaninternal.server.persist.TrimLogSql; import io.ebeaninternal.server.query.DefaultSqlRow; import io.ebeaninternal.server.transaction.TransactionManager; import io.ebeaninternal.server.util.BindParamsParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.PreparedStatement; @@ -32,8 +31,6 @@ import java.util.function.Predicate; */ public final class RelationalQueryRequest { - private static final Logger logger = LoggerFactory.getLogger(RelationalQueryRequest.class); - private final SpiSqlQuery query; private final RelationalQueryEngine queryEngine; @@ -168,20 +165,8 @@ public final class RelationalQueryRequest { * Close the underlying resources. */ public void close() { - try { - if (resultSet != null) { - resultSet.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } - try { - if (pstmt != null) { - pstmt.close(); - } - } catch (SQLException e) { - logger.error(null, e); - } + JdbcClose.close(resultSet); + JdbcClose.close(pstmt); } /** diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java index dde0be020..a1e8daa4e 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java @@ -1,12 +1,11 @@ package io.ebeaninternal.server.persist; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiCallableSql; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.PersistRequestCallableSql; import io.ebeaninternal.server.util.BindParamsParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.sql.CallableStatement; @@ -15,15 +14,13 @@ import java.sql.SQLException; /** * Handles the execution of CallableSql requests. */ -public class ExeCallableSql { - - private static final Logger logger = LoggerFactory.getLogger(ExeCallableSql.class); +class ExeCallableSql { private final Binder binder; private final PstmtFactory pstmtFactory; - public ExeCallableSql(Binder binder) { + ExeCallableSql(Binder binder) { this.binder = binder; this.pstmtFactory = new PstmtFactory(); } @@ -54,12 +51,8 @@ public class ExeCallableSql { throw new PersistenceException(ex); } finally { - if (!batchThisRequest && cstmt != null) { - try { - cstmt.close(); - } catch (SQLException e) { - logger.error(null, e); - } + if (!batchThisRequest) { + JdbcClose.close(cstmt); } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java index 3830096a6..32faa0924 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java @@ -1,13 +1,12 @@ package io.ebeaninternal.server.persist; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.SpiUpdate; import io.ebeaninternal.server.core.PersistRequestOrmUpdate; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.util.BindParamsParser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.sql.PreparedStatement; @@ -18,8 +17,6 @@ import java.sql.SQLException; */ class ExeOrmUpdate { - private static final Logger logger = LoggerFactory.getLogger(ExeOrmUpdate.class); - private final Binder binder; private final PstmtFactory pstmtFactory; @@ -61,12 +58,8 @@ class ExeOrmUpdate { throw new PersistenceException("Error executing: " + request.getOrmUpdate().getGeneratedSql(), ex); } finally { - if (!batchThisRequest && pstmt != null) { - try { - pstmt.close(); - } catch (SQLException e) { - logger.error(null, e); - } + if (!batchThisRequest) { + JdbcClose.close(pstmt); } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java index b8e050783..fd1f0c7d4 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java @@ -1,14 +1,12 @@ package io.ebeaninternal.server.persist; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiSqlUpdate; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.PersistRequestUpdateSql; import io.ebeaninternal.server.core.PersistRequestUpdateSql.SqlType; import io.ebeaninternal.server.util.BindParamsParser; -import io.ebeaninternal.util.JdbcClose; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.sql.PreparedStatement; @@ -20,8 +18,6 @@ import java.sql.SQLException; */ class ExeUpdateSql { - private static final Logger logger = LoggerFactory.getLogger(ExeUpdateSql.class); - private final Binder binder; private final PstmtFactory pstmtFactory; @@ -63,12 +59,8 @@ class ExeUpdateSql { throw new PersistenceException(ex); } finally { - if (!batchThisRequest && pstmt != null) { - try { - pstmt.close(); - } catch (SQLException e) { - logger.error(null, e); - } + if (!batchThisRequest) { + JdbcClose.close(pstmt); } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java index df8b82d5c..ec8cdd7df 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java @@ -1,13 +1,12 @@ package io.ebeaninternal.server.persist.dml; import io.ebean.bean.EntityBean; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.core.PersistRequestBean; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.persist.DmlUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; @@ -21,8 +20,6 @@ import java.sql.SQLException; */ public class InsertHandler extends DmlHandler { - private static final Logger logger = LoggerFactory.getLogger(InsertHandler.class); - /** * The associated InsertMeta data. */ @@ -142,12 +139,7 @@ public class InsertHandler extends DmlHandler { try { setGeneratedKey(rset); } finally { - try { - rset.close(); - } catch (SQLException ex) { - String msg = "Error closing rset for returning generatedKeys?"; - logger.warn(msg, ex); - } + JdbcClose.close(rset); } } @@ -178,20 +170,8 @@ public class InsertHandler extends DmlHandler { rset = stmt.executeQuery(); setGeneratedKey(rset); } finally { - try { - if (rset != null) { - rset.close(); - } - } catch (SQLException ex) { - logger.warn("Error closing ResultSet for fetchGeneratedKeyUsingSelect?", ex); - } - try { - if (stmt != null) { - stmt.close(); - } - } catch (SQLException ex) { - logger.warn("Error closing Statement for fetchGeneratedKeyUsingSelect?", ex); - } + JdbcClose.close(rset); + JdbcClose.close(stmt); } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQuery.java b/src/main/java/io/ebeaninternal/server/query/CQuery.java index 95c3d9767..6ab29d742 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -10,10 +10,11 @@ import io.ebean.bean.NodeUsageListener; import io.ebean.bean.ObjectGraphNode; import io.ebean.bean.PersistenceContext; import io.ebean.event.readaudit.ReadEvent; +import io.ebean.util.JdbcClose; +import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery.Mode; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.server.autotune.ProfilingListener; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.core.SpiOrmQueryRequest; @@ -381,14 +382,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran } catch (SQLException e) { logger.error("Error closing dataReader", e); } - try { - if (pstmt != null) { - pstmt.close(); - pstmt = null; - } - } catch (SQLException e) { - logger.error("Error closing preparedStatement", e); - } + JdbcClose.close(pstmt); + pstmt = null; } /** diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java b/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java index af6420980..8ea69624c 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryFetchSingleAttribute.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiTransaction; @@ -169,14 +170,8 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent { } catch (SQLException e) { logger.error("Error closing DataReader", e); } - try { - if (pstmt != null) { - pstmt.close(); - pstmt = null; - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } + JdbcClose.close(pstmt); + pstmt = null; } @Override diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryRowCount.java b/src/main/java/io/ebeaninternal/server/query/CQueryRowCount.java index efa590883..5ddfe7b02 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryRowCount.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryRowCount.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiTransaction; @@ -141,8 +142,8 @@ class CQueryRowCount implements SpiProfileTransactionEvent { * Close the resources. */ private void close() { - UtilJdbc.close(rset); - UtilJdbc.close(pstmt); + JdbcClose.close(rset); + JdbcClose.close(pstmt); rset = null; pstmt = null; } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryUpdate.java b/src/main/java/io/ebeaninternal/server/query/CQueryUpdate.java index a64738f0a..6331c1cb6 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryUpdate.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryUpdate.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiProfileTransactionEvent; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiTransaction; @@ -127,7 +128,7 @@ class CQueryUpdate implements SpiProfileTransactionEvent { * Close the resources. */ private void close() { - UtilJdbc.close(pstmt); + JdbcClose.close(pstmt); pstmt = null; } diff --git a/src/main/java/io/ebeaninternal/server/query/UtilJdbc.java b/src/main/java/io/ebeaninternal/server/query/UtilJdbc.java deleted file mode 100644 index 56cec9d40..000000000 --- a/src/main/java/io/ebeaninternal/server/query/UtilJdbc.java +++ /dev/null @@ -1,34 +0,0 @@ -package io.ebeaninternal.server.query; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -public class UtilJdbc { - - private static final Logger logger = LoggerFactory.getLogger(UtilJdbc.class); - - public static void close(ResultSet resultSet) { - try { - if (resultSet != null) { - resultSet.close(); - } - } catch (SQLException e) { - logger.error("Error closing ResultSet", e); - } - } - - public static void close(PreparedStatement statement) { - try { - if (statement != null) { - statement.close(); - } - } catch (SQLException e) { - logger.error("Error closing PreparedStatement", e); - } - } - -} diff --git a/src/main/java/io/ebeaninternal/server/transaction/JtaTransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/JtaTransactionManager.java index 1a0c0043c..1933b10c6 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/JtaTransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/JtaTransactionManager.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.transaction; import io.ebean.config.ExternalTransactionManager; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +19,6 @@ import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.UserTransaction; -import io.ebeaninternal.util.JdbcClose; /** * Hook into external JTA transaction manager. diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java index a1593736d..c30a430ba 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactory.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.transaction; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.util.JdbcClose; import org.slf4j.Logger; import javax.persistence.PersistenceException; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java index 3b552bf27..88959e921 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasic.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.transaction; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.util.JdbcClose; import javax.persistence.PersistenceException; import javax.sql.DataSource; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasicWithRead.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasicWithRead.java index 19926ffea..dbab9e870 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasicWithRead.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryBasicWithRead.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.transaction; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.util.JdbcClose; import javax.persistence.PersistenceException; import javax.sql.DataSource; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java index c1fa5f670..fdb76e23e 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenant.java @@ -1,8 +1,8 @@ package io.ebeaninternal.server.transaction; import io.ebean.config.CurrentTenantProvider; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.util.JdbcClose; import javax.persistence.PersistenceException; import java.sql.Connection; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenantWithRead.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenantWithRead.java index 94f83d5fd..77bec4413 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenantWithRead.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionFactoryTenantWithRead.java @@ -1,8 +1,8 @@ package io.ebeaninternal.server.transaction; import io.ebean.config.CurrentTenantProvider; +import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.util.JdbcClose; import javax.persistence.PersistenceException; import java.sql.Connection; From 45a023f0e4af21fb746e9b2e9af62cb8f754ce00 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 14:25:44 +1300 Subject: [PATCH 0094/1036] #1282 - Not supported for @DbArray mapping when using kotlin var instead of val --- .../server/type/DefaultTypeManager.java | 24 ++++--- .../server/type/TypeReflectHelper.java | 39 +++++++++++- .../server/type/TypeReflectHelperTest.java | 62 ++++++++++++++++++- 3 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 6bdb05661..e0f2c6ac5 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -266,7 +266,7 @@ public final class DefaultTypeManager implements TypeManager { * can have many classes if it uses method overrides and we need to register all * the variations/classes for the enum. */ - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) @Override public void addEnumType(ScalarType scalarType, Class enumClass) { @@ -339,7 +339,7 @@ public final class DefaultTypeManager implements TypeManager { Type valueType = getValueType(genericType); if (type.equals(List.class)) { if (arrayTypeListFactory != null) { - if(isEnumType(valueType)) { + if (isEnumType(valueType)) { return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING)); } return arrayTypeListFactory.typeFor(valueType); @@ -348,7 +348,7 @@ public final class DefaultTypeManager implements TypeManager { return new ScalarTypeJsonList.Varchar(getDocType(valueType)); } else if (type.equals(Set.class)) { if (arrayTypeSetFactory != null) { - if(isEnumType(valueType)) { + if (isEnumType(valueType)) { return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING)); } return arrayTypeSetFactory.typeFor(valueType); @@ -359,13 +359,12 @@ public final class DefaultTypeManager implements TypeManager { throw new IllegalStateException("Type [" + type + "] not supported for @DbArray"); } - @SuppressWarnings("unchecked") private Class> asEnumClass(Type valueType) { - return (Class>)valueType; + return TypeReflectHelper.asEnumClass(valueType); } private boolean isEnumType(Type valueType) { - return valueType instanceof Class && ((Class)valueType).isEnum(); + return TypeReflectHelper.isEnumType(valueType); } @Override @@ -430,14 +429,13 @@ public final class DefaultTypeManager implements TypeManager { /** * Return true if value parameter type of the map is Object. */ - private boolean isValueTypeSimple(Type genericType) { - Type[] typeArgs = ((ParameterizedType) genericType).getActualTypeArguments(); - return String.class.equals(typeArgs[0]) || Long.class.equals(typeArgs[0]); + private boolean isValueTypeSimple(Type collectionType) { + Type typeArg = TypeReflectHelper.getValueType(collectionType); + return String.class.equals(typeArg) || Long.class.equals(typeArg); } - private Type getValueType(Type genericType) { - Type[] typeArgs = ((ParameterizedType) genericType).getActualTypeArguments(); - return typeArgs[0]; + private Type getValueType(Type collectionType) { + return TypeReflectHelper.getValueType(collectionType); } /** @@ -593,7 +591,7 @@ public final class DefaultTypeManager implements TypeManager { ScalarTypeEnum scalarType = (ScalarTypeEnum) getScalarType(enumType); if (scalarType != null && !scalarType.isOverrideBy(type)) { if (type != null && !scalarType.isCompatible(type)) { - throw new IllegalStateException("Error mapping Enum type:"+enumType+" It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)"); + throw new IllegalStateException("Error mapping Enum type:" + enumType + " It is mapped using 2 different modes when only one is supported (ORDINAL, STRING or an Ebean mapping)"); } return scalarType; } diff --git a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java index a69dcd75d..392c0829b 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; public class TypeReflectHelper { @@ -9,14 +10,48 @@ public class TypeReflectHelper { return TypeResolver.resolveRawArgs(matchRawType, cls); } - public static Class getClass(Type type) { + /** + * Return the enum class for this type taking into account wildcard type. + */ + @SuppressWarnings("unchecked") + public static Class> asEnumClass(Type valueType) { + Class enumClass = getClass(valueType); + return (Class>) enumClass; + } + + /** + * Return true if the type is an enum. + */ + public static boolean isEnumType(Type valueType) { + try { + return getClass(valueType).isEnum(); + } catch (ClassCastException | IllegalArgumentException e) { + return false; + } + } + + /** + * Return the value type of a collection type (list, set, map values). + */ + public static Type getValueType(Type collectionType) { + Type[] typeArgs = ((ParameterizedType) collectionType).getActualTypeArguments(); + return typeArgs[0]; + } + + private static Class getClass(Type type) { while (true) { if (type instanceof ParameterizedType) { type = ((ParameterizedType) type).getRawType(); continue; } - + if (type instanceof WildcardType) { + Type[] upperBounds = ((WildcardType) type).getUpperBounds(); + if (upperBounds != null && upperBounds.length == 1) { + return getClass(upperBounds[0]); + } + throw new IllegalArgumentException("Don't know how to determine Class from Type [" + type + "]"); + } return (Class) type; } } diff --git a/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java index fe815617d..8ba6d612f 100644 --- a/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java +++ b/src/test/java/io/ebeaninternal/server/type/TypeReflectHelperTest.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.type; import io.ebean.config.ScalarTypeConverter; import org.junit.Test; +import org.tests.model.basic.Order; import org.tests.model.ivo.Money; import org.tests.model.ivo.Oid; import org.tests.model.ivo.SysTime; @@ -10,8 +11,13 @@ import org.tests.model.ivo.converter.OidTypeConverter; import org.tests.model.ivo.converter.SysTimeConverter; import javax.persistence.AttributeConverter; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.math.BigDecimal; import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -57,13 +63,63 @@ public class TypeReflectHelperTest { assertThat(params[1]).isEqualTo(byte[].class); } - static class RichText { + @Test + public void isEnumType_wildCard() throws NoSuchFieldException { + + Field wildOrderStatus = Some.class.getDeclaredField("wildOrderStatus"); + assertThat(TypeReflectHelper.isEnumType(getValueType(wildOrderStatus.getGenericType()))).isTrue(); + + Class aClass = TypeReflectHelper.asEnumClass(getValueType(wildOrderStatus.getGenericType())); + assertThat(aClass).isEqualTo(Order.Status.class); + } + + + @Test + public void isEnumType_simpleType() throws NoSuchFieldException { + + Field orderStatus = Some.class.getDeclaredField("orderStatus"); + + assertThat(TypeReflectHelper.isEnumType(getValueType(orderStatus.getGenericType()))).isTrue(); + + Class aClass = TypeReflectHelper.asEnumClass(getValueType(orderStatus.getGenericType())); + assertThat(aClass).isEqualTo(Order.Status.class); + } + + @Test + public void getValueType_simpleType() throws NoSuchFieldException { + + Field orderStatus = Some.class.getDeclaredField("orderStatus"); + + Type expected = getValueType(orderStatus.getGenericType()); + assertThat(TypeReflectHelper.getValueType(orderStatus.getGenericType())).isEqualTo(expected); + } + + @Test + public void getValueType_wildcardType() throws NoSuchFieldException { + + Field orderStatus = Some.class.getDeclaredField("wildOrderStatus"); + + Type expected = getValueType(orderStatus.getGenericType()); + assertThat(TypeReflectHelper.getValueType(orderStatus.getGenericType())).isEqualTo(expected); + } + + private Type getValueType(Type genericType) { + return ((ParameterizedType) genericType).getActualTypeArguments()[0]; + } + + private static class Some { + + List wildOrderStatus = new ArrayList<>(); + List orderStatus = new ArrayList<>(); + } + + private static class RichText { } - static class RichTextConverter extends Direct {} + private static class RichTextConverter extends Direct {} - static class Direct implements ScalarTypeConverter { + private static class Direct implements ScalarTypeConverter { @Override public M getNullValue() { From 68a470a086e6531f24acda2fd17db2e3ff1cf120 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 15:00:13 +1300 Subject: [PATCH 0095/1036] Test change only - No effective change, remove noop ServerConfig.loadTestProperties() --- .../io/ebean/EbeanServerFactory_MultiTenancy_Test.java | 10 ++++++---- src/test/java/io/ebean/config/ServerConfigTest.java | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/io/ebean/EbeanServerFactory_MultiTenancy_Test.java b/src/test/java/io/ebean/EbeanServerFactory_MultiTenancy_Test.java index 8d1669e56..a12db5bbb 100644 --- a/src/test/java/io/ebean/EbeanServerFactory_MultiTenancy_Test.java +++ b/src/test/java/io/ebean/EbeanServerFactory_MultiTenancy_Test.java @@ -1,6 +1,11 @@ package io.ebean; -import io.ebean.config.*; +import io.ebean.config.CurrentTenantProvider; +import io.ebean.config.ServerConfig; +import io.ebean.config.TenantCatalogProvider; +import io.ebean.config.TenantDataSourceProvider; +import io.ebean.config.TenantMode; +import io.ebean.config.TenantSchemaProvider; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import org.junit.Test; @@ -27,7 +32,6 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase { ServerConfig config = new ServerConfig(); config.setName("multiTenantDb"); config.loadFromProperties(); - config.loadTestProperties(); config.setRegister(false); config.setDefaultServer(false); @@ -62,7 +66,6 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase { ServerConfig config = new ServerConfig(); config.setName("h2"); config.loadFromProperties(); - config.loadTestProperties(); config.setRegister(false); config.setDefaultServer(false); @@ -92,7 +95,6 @@ public class EbeanServerFactory_MultiTenancy_Test extends BaseTestCase { ServerConfig config = new ServerConfig(); config.setName("h2"); config.loadFromProperties(); - config.loadTestProperties(); config.setRegister(false); config.setDefaultServer(false); diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index 0eea08122..fcf62fee5 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -83,8 +83,6 @@ public class ServerConfigTest { assertFalse(serverConfig.isDisableL2Cache()); assertFalse(serverConfig.isNotifyL2CacheInForeground()); - serverConfig.loadTestProperties(); - assertEquals(PersistBatch.ALL, serverConfig.getPersistBatch()); assertEquals(PersistBatch.ALL, serverConfig.getPersistBatchOnCascade()); } From c8e199177c31419b985d31fd9dc00cff1e1dc5d8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 15:31:26 +1300 Subject: [PATCH 0096/1036] #1294 - NPE when delete cascade from bean with SoftDelete to imported OneToOne without SoftDelete --- .../server/deploy/BeanPropertyAssoc.java | 7 ++ .../server/persist/DefaultPersister.java | 20 +++--- .../tests/model/softdelete/ESoftDelOneA.java | 71 +++++++++++++++++++ .../tests/model/softdelete/ESoftDelOneB.java | 57 +++++++++++++++ .../softdelete/TestSoftDeleteOtoCascade.java | 38 ++++++++++ 5 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 src/test/java/org/tests/model/softdelete/ESoftDelOneA.java create mode 100644 src/test/java/org/tests/model/softdelete/ESoftDelOneB.java create mode 100644 src/test/java/org/tests/softdelete/TestSoftDeleteOtoCascade.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java index 499276dce..656f5d0bc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java @@ -186,6 +186,13 @@ public abstract class BeanPropertyAssoc extends BeanProperty { return targetDescriptor; } + /** + * Return true if the target side has soft delete. + */ + public boolean isTargetSoftDelete() { + return targetDescriptor.isSoftDelete(); + } + /** * Return true if REFRESH should cascade. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 7343a8ac5..a825c1653 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -1080,7 +1080,7 @@ public final class DefaultPersister implements Persister { DeleteUnloadedForeignKeys unloaded = null; for (BeanPropertyAssocOne prop : expOnes) { // for soft delete check cascade type also supports soft delete - if (!softDelete || prop.getTargetDescriptor().isSoftDelete()) { + if (!softDelete || prop.isTargetSoftDelete()) { if (request.isLoadedProperty(prop)) { Object detailBean = prop.getValue(parentBean); if (detailBean != null) { @@ -1113,7 +1113,7 @@ public final class DefaultPersister implements Persister { if (ModifyListenMode.REMOVALS == many.getModifyListenMode()) { // PrivateOwned ... // if soft delete then check target also supports soft delete - if (!softDelete || many.getTargetDescriptor().isSoftDelete()) { + if (!softDelete || many.isTargetSoftDelete()) { Object details = many.getValue(parentBean); if (details instanceof BeanCollection) { Set modifyRemovals = ((BeanCollection) details).getModifyRemovals(); @@ -1257,14 +1257,18 @@ public final class DefaultPersister implements Persister { */ private void deleteAssocOne(PersistRequestBean request) { + boolean softDelete = request.isSoftDelete(); + BeanPropertyAssocOne[] ones = request.getBeanDescriptor().propertiesOneImportedDelete(); for (BeanPropertyAssocOne prop : ones) { - if (request.isLoadedProperty(prop)) { - Object detailBean = prop.getValue(request.getEntityBean()); - if (detailBean != null) { - EntityBean detail = (EntityBean) detailBean; - if (prop.hasId(detail)) { - deleteRecurse(detail, request.getTransaction(), request.isSoftDelete()); + if (!softDelete || prop.isTargetSoftDelete()) { + if (request.isLoadedProperty(prop)) { + Object detailBean = prop.getValue(request.getEntityBean()); + if (detailBean != null) { + EntityBean detail = (EntityBean) detailBean; + if (prop.hasId(detail)) { + deleteRecurse(detail, request.getTransaction(), request.isSoftDelete()); + } } } } diff --git a/src/test/java/org/tests/model/softdelete/ESoftDelOneA.java b/src/test/java/org/tests/model/softdelete/ESoftDelOneA.java new file mode 100644 index 000000000..3ecd9b044 --- /dev/null +++ b/src/test/java/org/tests/model/softdelete/ESoftDelOneA.java @@ -0,0 +1,71 @@ +package org.tests.model.softdelete; + +import io.ebean.annotation.SoftDelete; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class ESoftDelOneA { + + @Id + long id; + + String name; + + @OneToOne(cascade = CascadeType.ALL) + ESoftDelOneB oneb; + + @SoftDelete + boolean deleted; + + @Version + long version; + + public ESoftDelOneA(String name) { + this.name = name; + } + + 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 ESoftDelOneB getOneb() { + return oneb; + } + + public void setOneb(ESoftDelOneB oneb) { + this.oneb = oneb; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/softdelete/ESoftDelOneB.java b/src/test/java/org/tests/model/softdelete/ESoftDelOneB.java new file mode 100644 index 000000000..b89192b31 --- /dev/null +++ b/src/test/java/org/tests/model/softdelete/ESoftDelOneB.java @@ -0,0 +1,57 @@ +package org.tests.model.softdelete; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class ESoftDelOneB { + + @Id + long id; + + String name; + + @OneToOne(mappedBy = "oneb") + ESoftDelOneA onea; + + @Version + long version; + + public ESoftDelOneB(String name) { + this.name = name; + } + + 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 ESoftDelOneA getOnea() { + return onea; + } + + public void setOnea(ESoftDelOneA onea) { + this.onea = onea; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/softdelete/TestSoftDeleteOtoCascade.java b/src/test/java/org/tests/softdelete/TestSoftDeleteOtoCascade.java new file mode 100644 index 000000000..bad534614 --- /dev/null +++ b/src/test/java/org/tests/softdelete/TestSoftDeleteOtoCascade.java @@ -0,0 +1,38 @@ +package org.tests.softdelete; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; +import org.tests.model.softdelete.ESoftDelOneA; +import org.tests.model.softdelete.ESoftDelOneB; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestSoftDeleteOtoCascade extends BaseTestCase { + + @Test + public void test() { + + ESoftDelOneA a = new ESoftDelOneA("a1"); + ESoftDelOneB b = new ESoftDelOneB("b1"); + + a.setOneb(b); + b.setOnea(a); + + Ebean.save(a); + + LoggedSqlCollector.start(); + + // delete doesn't cascade to ESoftDelOneB as this is a + // soft delete and ESoftDelOneB doesn't have soft delete flag + Ebean.delete(a); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update esoft_del_one_a set deleted=?, version=? where id=? and version=?"); + + } +} From 57b0190cd2c92f906de95c990ea7506cd1c0d668 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Feb 2018 18:28:03 +1300 Subject: [PATCH 0097/1036] #1283 - ENH: Support simplified test configuration (with docker setup typically via application-test.yml) --- pom.xml | 3 +-- src/main/java/io/ebean/config/AutoConfigure.java | 15 +++++++++++++++ src/main/java/io/ebean/config/ServerConfig.java | 12 ++++++++++++ .../ebean/config/properties/PropertiesLoader.java | 11 +++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/ebean/config/AutoConfigure.java diff --git a/pom.xml b/pom.xml index 7da7e58fa..e391767ed 100644 --- a/pom.xml +++ b/pom.xml @@ -84,13 +84,12 @@ org.yaml snakeyaml 1.19 - provided diff --git a/src/main/java/io/ebeaninternal/server/grammer/EqlParser.java b/src/main/java/io/ebeaninternal/server/grammer/EqlParser.java index f4e8a184d..b65b8ada5 100644 --- a/src/main/java/io/ebeaninternal/server/grammer/EqlParser.java +++ b/src/main/java/io/ebeaninternal/server/grammer/EqlParser.java @@ -3,8 +3,8 @@ package io.ebeaninternal.server.grammer; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.grammer.antlr.EQLLexer; import io.ebeaninternal.server.grammer.antlr.EQLParser; -import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; @@ -22,7 +22,7 @@ public class EqlParser { */ public static void parse(String raw, SpiQuery query) { - EQLLexer lexer = new EQLLexer(new ANTLRInputStream(raw)); + EQLLexer lexer = new EQLLexer(CharStreams.fromString(raw)); CommonTokenStream tokens = new CommonTokenStream(lexer); EQLParser parser = new EQLParser(tokens); parser.addErrorListener(errorListener); diff --git a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLBaseListener.java b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLBaseListener.java index 639967cb0..e368fb917 100644 --- a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLBaseListener.java +++ b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLBaseListener.java @@ -1,4 +1,4 @@ -// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.6 +// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.7 package io.ebeaninternal.server.grammer.antlr; import org.antlr.v4.runtime.ParserRuleContext; diff --git a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLLexer.java b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLLexer.java index 040ef83e1..b0c5076a4 100644 --- a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLLexer.java +++ b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLLexer.java @@ -1,9 +1,8 @@ -// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.6 +// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.7 package io.ebeaninternal.server.grammer.antlr; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.Lexer; -import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.RuntimeMetaData; import org.antlr.v4.runtime.Vocabulary; import org.antlr.v4.runtime.VocabularyImpl; @@ -16,7 +15,7 @@ import org.antlr.v4.runtime.dfa.DFA; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class EQLLexer extends Lexer { static { - RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION); + RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; @@ -33,6 +32,10 @@ public class EQLLexer extends Lexer { T__52 = 53, T__53 = 54, T__54 = 55, T__55 = 56, T__56 = 57, INPUT_VARIABLE = 58, PATH_VARIABLE = 59, BOOLEAN_LITERAL = 60, NUMBER_LITERAL = 61, DOUBLE = 62, INT = 63, ZERO = 64, STRING_LITERAL = 65, WS = 66; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + public static String[] modeNames = { "DEFAULT_MODE" }; @@ -104,12 +107,6 @@ public class EQLLexer extends Lexer { } - @Override - public void recover(RecognitionException e) { - throw new RuntimeException("Error in grammer - " + e.getMessage()); - } - - public EQLLexer(CharStream input) { super(input); _interp = new LexerATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache); @@ -130,6 +127,11 @@ public class EQLLexer extends Lexer { return _serializedATN; } + @Override + public String[] getChannelNames() { + return channelNames; + } + @Override public String[] getModeNames() { return modeNames; @@ -141,7 +143,7 @@ public class EQLLexer extends Lexer { } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2D\u0200\b\1\4\2\t" + + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2D\u0200\b\1\4\2\t" + "\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13" + "\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22" + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31" + @@ -177,22 +179,22 @@ public class EQLLexer extends Lexer { ";\37= ?!A\"C#E$G%I&K\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67" + "m8o9q:s;u{?}@\177A\u0081B\u0083C\u0085D\3\2\t\5\2C\\aac|\6\2\62;" + "C\\aac|\7\2\60\60\62;C\\aac|\3\2\62;\3\2\63;\3\2))\5\2\13\f\17\17\"\"" + - "\u020b\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2" + - "\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27\3" + - "\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2" + - "\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2" + - "/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2\2" + - "\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2" + - "G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3" + - "\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2\2" + - "\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2" + - "m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3" + - "\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3\2" + - "\2\2\2\u0085\3\2\2\2\3\u0087\3\2\2\2\5\u008e\3\2\2\2\7\u0090\3\2\2\2\t" + - "\u0092\3\2\2\2\13\u009b\3\2\2\2\r\u00a1\3\2\2\2\17\u00a7\3\2\2\2\21\u00aa" + - "\3\2\2\2\23\u00ac\3\2\2\2\25\u00b2\3\2\2\2\27\u00b8\3\2\2\2\31\u00bd\3" + - "\2\2\2\33\u00c1\3\2\2\2\35\u00c6\3\2\2\2\37\u00cc\3\2\2\2!\u00d3\3\2\2" + - "\2#\u00d9\3\2\2\2%\u00db\3\2\2\2\'\u00e1\3\2\2\2)\u00e6\3\2\2\2+\u00e9" + + "\2\u020b\2\3\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2" + + "\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25\3\2\2\2\2\27" + + "\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2" + + "\2\2#\3\2\2\2\2%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2" + + "\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3\2\2\2\29\3\2" + + "\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2" + + "\2G\3\2\2\2\2I\3\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S" + + "\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2\2\2\2_\3\2" + + "\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\2i\3\2\2\2\2k\3\2\2\2" + + "\2m\3\2\2\2\2o\3\2\2\2\2q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y" + + "\3\2\2\2\2{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2\2\u0083\3" + + "\2\2\2\2\u0085\3\2\2\2\3\u0087\3\2\2\2\5\u008e\3\2\2\2\7\u0090\3\2\2\2" + + "\t\u0092\3\2\2\2\13\u009b\3\2\2\2\r\u00a1\3\2\2\2\17\u00a7\3\2\2\2\21" + + "\u00aa\3\2\2\2\23\u00ac\3\2\2\2\25\u00b2\3\2\2\2\27\u00b8\3\2\2\2\31\u00bd" + + "\3\2\2\2\33\u00c1\3\2\2\2\35\u00c6\3\2\2\2\37\u00cc\3\2\2\2!\u00d3\3\2" + + "\2\2#\u00d9\3\2\2\2%\u00db\3\2\2\2\'\u00e1\3\2\2\2)\u00e6\3\2\2\2+\u00e9" + "\3\2\2\2-\u00ed\3\2\2\2/\u00f1\3\2\2\2\61\u00f4\3\2\2\2\63\u00fc\3\2\2" + "\2\65\u00ff\3\2\2\2\67\u0104\3\2\2\29\u010b\3\2\2\2;\u0115\3\2\2\2=\u011d" + "\3\2\2\2?\u0123\3\2\2\2A\u012b\3\2\2\2C\u0136\3\2\2\2E\u013f\3\2\2\2G" + diff --git a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLListener.java b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLListener.java index 7d8e0738b..6fddb3633 100644 --- a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLListener.java +++ b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLListener.java @@ -1,4 +1,4 @@ -// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.6 +// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.7 package io.ebeaninternal.server.grammer.antlr; import org.antlr.v4.runtime.tree.ParseTreeListener; diff --git a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLParser.java b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLParser.java index 57b0a573c..151146b94 100644 --- a/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLParser.java +++ b/src/main/java/io/ebeaninternal/server/grammer/antlr/EQLParser.java @@ -1,4 +1,4 @@ -// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.6 +// Generated from /home/rob/github/ebean/src/test/resources/EQL.g4 by ANTLR 4.7 package io.ebeaninternal.server.grammer.antlr; import org.antlr.v4.runtime.NoViableAltException; @@ -23,7 +23,7 @@ import java.util.List; @SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast"}) public class EQLParser extends Parser { static { - RuntimeMetaData.checkVersion("4.6", RuntimeMetaData.VERSION); + RuntimeMetaData.checkVersion("4.7", RuntimeMetaData.VERSION); } protected static final DFA[] _decisionToDFA; @@ -142,18 +142,16 @@ public class EQLParser extends Parser { return _ATN; } - -// @Override -// public void reportError(RecognitionException e) { -// throw new RuntimeException("Error in grammer - " + e.getMessage()); -// } - public EQLParser(TokenStream input) { super(input); _interp = new ParserATNSimulator(this, _ATN, _decisionToDFA, _sharedContextCache); } public static class Select_statementContext extends ParserRuleContext { + public TerminalNode EOF() { + return getToken(EQLParser.EOF, 0); + } + public Select_clauseContext select_clause() { return getRuleContext(Select_clauseContext.class, 0); } @@ -259,6 +257,8 @@ public class EQLParser extends Parser { } } + setState(98); + match(EOF); } } catch (RecognitionException re) { _localctx.exception = re; @@ -306,23 +306,23 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(98); - match(T__0); setState(100); + match(T__0); + setState(102); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__3) { { - setState(99); + setState(101); distinct(); } } - setState(102); - match(T__1); - setState(103); - fetch_property_group(); setState(104); + match(T__1); + setState(105); + fetch_property_group(); + setState(106); match(T__2); } } catch (RecognitionException re) { @@ -362,7 +362,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(106); + setState(108); match(T__3); } } catch (RecognitionException re) { @@ -406,7 +406,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(108); + setState(110); fetch_path(); } } catch (RecognitionException re) { @@ -450,9 +450,9 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(110); + setState(112); match(T__4); - setState(111); + setState(113); conditional_expression(); } } catch (RecognitionException re) { @@ -501,25 +501,25 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(113); - match(T__5); - setState(114); - match(T__6); setState(115); + match(T__5); + setState(116); + match(T__6); + setState(117); orderby_property(); - setState(120); + setState(122); _errHandler.sync(this); _la = _input.LA(1); while (_la == T__7) { { { - setState(116); + setState(118); match(T__7); - setState(117); + setState(119); orderby_property(); } } - setState(122); + setState(124); _errHandler.sync(this); _la = _input.LA(1); } @@ -574,24 +574,24 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(123); - match(PATH_VARIABLE); setState(125); + match(PATH_VARIABLE); + setState(127); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__11 || _la == T__12) { { - setState(124); + setState(126); asc_desc(); } } - setState(128); + setState(130); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__8) { { - setState(127); + setState(129); nulls_firstlast(); } } @@ -632,24 +632,24 @@ public class EQLParser extends Parser { Nulls_firstlastContext _localctx = new Nulls_firstlastContext(_ctx, getState()); enterRule(_localctx, 14, RULE_nulls_firstlast); try { - setState(134); + setState(136); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 9, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(130); + setState(132); match(T__8); - setState(131); + setState(133); match(T__9); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(132); + setState(134); match(T__8); - setState(133); + setState(135); match(T__10); } break; @@ -692,7 +692,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(136); + setState(138); _la = _input.LA(1); if (!(_la == T__11 || _la == T__12)) { _errHandler.recoverInline(this); @@ -748,16 +748,16 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(138); + setState(140); match(T__13); - setState(139); - match(NUMBER_LITERAL); setState(141); + match(NUMBER_LITERAL); + setState(143); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__14) { { - setState(140); + setState(142); offset_clause(); } } @@ -804,9 +804,9 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(143); + setState(145); match(T__14); - setState(144); + setState(146); match(NUMBER_LITERAL); } } catch (RecognitionException re) { @@ -859,26 +859,26 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(146); - match(T__15); setState(148); + match(T__15); + setState(150); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__17 || _la == T__18) { { - setState(147); + setState(149); fetch_option(); } } - setState(150); - match(PATH_VARIABLE); setState(152); + match(PATH_VARIABLE); + setState(154); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__1) { { - setState(151); + setState(153); fetch_property_set(); } } @@ -925,11 +925,11 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(154); - match(T__1); - setState(155); - fetch_property_group(); setState(156); + match(T__1); + setState(157); + fetch_property_group(); + setState(158); match(T__2); } } catch (RecognitionException re) { @@ -978,21 +978,21 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(158); + setState(160); fetch_property(); - setState(163); + setState(165); _errHandler.sync(this); _la = _input.LA(1); while (_la == T__7) { { { - setState(159); + setState(161); match(T__7); - setState(160); + setState(162); fetch_property(); } } - setState(165); + setState(167); _errHandler.sync(this); _la = _input.LA(1); } @@ -1044,27 +1044,27 @@ public class EQLParser extends Parser { Fetch_propertyContext _localctx = new Fetch_propertyContext(_ctx, getState()); enterRule(_localctx, 28, RULE_fetch_property); try { - setState(169); + setState(171); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 14, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(166); + setState(168); match(PATH_VARIABLE); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(167); + setState(169); fetch_query_hint(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(168); + setState(170); fetch_lazy_hint(); } break; @@ -1110,9 +1110,9 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(171); + setState(173); match(T__16); - setState(172); + setState(174); fetch_query_option(); } } catch (RecognitionException re) { @@ -1156,9 +1156,9 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(174); + setState(176); match(T__16); - setState(175); + setState(177); fetch_lazy_option(); } } catch (RecognitionException re) { @@ -1204,20 +1204,20 @@ public class EQLParser extends Parser { Fetch_optionContext _localctx = new Fetch_optionContext(_ctx, getState()); enterRule(_localctx, 34, RULE_fetch_option); try { - setState(179); + setState(181); _errHandler.sync(this); switch (_input.LA(1)) { case T__17: enterOuterAlt(_localctx, 1); { - setState(177); + setState(179); fetch_query_option(); } break; case T__18: enterOuterAlt(_localctx, 2); { - setState(178); + setState(180); fetch_lazy_option(); } break; @@ -1266,14 +1266,14 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(181); - match(T__17); setState(183); + match(T__17); + setState(185); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__1) { { - setState(182); + setState(184); fetch_batch_size(); } } @@ -1321,14 +1321,14 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(185); - match(T__18); setState(187); + match(T__18); + setState(189); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__1) { { - setState(186); + setState(188); fetch_batch_size(); } } @@ -1375,11 +1375,11 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(189); - match(T__1); - setState(190); - match(NUMBER_LITERAL); setState(191); + match(T__1); + setState(192); + match(NUMBER_LITERAL); + setState(193); match(T__2); } } catch (RecognitionException re) { @@ -1428,21 +1428,21 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(193); + setState(195); conditional_term(); - setState(198); + setState(200); _errHandler.sync(this); _la = _input.LA(1); while (_la == T__19) { { { - setState(194); + setState(196); match(T__19); - setState(195); + setState(197); conditional_term(); } } - setState(200); + setState(202); _errHandler.sync(this); _la = _input.LA(1); } @@ -1493,21 +1493,21 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(201); + setState(203); conditional_factor(); - setState(206); + setState(208); _errHandler.sync(this); _la = _input.LA(1); while (_la == T__20) { { { - setState(202); + setState(204); match(T__20); - setState(203); + setState(205); conditional_factor(); } } - setState(208); + setState(210); _errHandler.sync(this); _la = _input.LA(1); } @@ -1554,17 +1554,17 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(210); + setState(212); _errHandler.sync(this); _la = _input.LA(1); if (_la == T__21) { { - setState(209); + setState(211); match(T__21); } } - setState(212); + setState(214); conditional_primary(); } } catch (RecognitionException re) { @@ -1610,24 +1610,24 @@ public class EQLParser extends Parser { Conditional_primaryContext _localctx = new Conditional_primaryContext(_ctx, getState()); enterRule(_localctx, 48, RULE_conditional_primary); try { - setState(219); + setState(221); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 21, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(214); + setState(216); any_expression(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(215); - match(T__1); - setState(216); - conditional_expression(); setState(217); + match(T__1); + setState(218); + conditional_expression(); + setState(219); match(T__2); } break; @@ -1707,80 +1707,80 @@ public class EQLParser extends Parser { Any_expressionContext _localctx = new Any_expressionContext(_ctx, getState()); enterRule(_localctx, 50, RULE_any_expression); try { - setState(234); + setState(236); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 22, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(221); + setState(223); comparison_expression(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(222); + setState(224); like_expression(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(223); + setState(225); between_expression(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(224); + setState(226); propertyBetween_expression(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(225); + setState(227); in_expression(); } break; case 6: enterOuterAlt(_localctx, 6); { - setState(226); + setState(228); isNull_expression(); } break; case 7: enterOuterAlt(_localctx, 7); { - setState(227); + setState(229); isNotNull_expression(); } break; case 8: enterOuterAlt(_localctx, 8); { - setState(228); + setState(230); isEmpty_expression(); } break; case 9: enterOuterAlt(_localctx, 9); { - setState(229); + setState(231); isNotEmpty_expression(); } break; case 10: enterOuterAlt(_localctx, 10); { - setState(230); - match(T__1); - setState(231); - any_expression(); setState(232); + match(T__1); + setState(233); + any_expression(); + setState(234); match(T__2); } break; @@ -1830,11 +1830,11 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(236); - match(PATH_VARIABLE); - setState(237); - match(T__22); setState(238); + match(PATH_VARIABLE); + setState(239); + match(T__22); + setState(240); in_value(); } } catch (RecognitionException re) { @@ -1885,40 +1885,40 @@ public class EQLParser extends Parser { enterRule(_localctx, 54, RULE_in_value); int _la; try { - setState(252); + setState(254); _errHandler.sync(this); switch (_input.LA(1)) { case INPUT_VARIABLE: enterOuterAlt(_localctx, 1); { - setState(240); + setState(242); match(INPUT_VARIABLE); } break; case T__1: enterOuterAlt(_localctx, 2); { - setState(241); + setState(243); match(T__1); - setState(242); + setState(244); value_expression(); - setState(247); + setState(249); _errHandler.sync(this); _la = _input.LA(1); while (_la == T__7) { { { - setState(243); + setState(245); match(T__7); - setState(244); + setState(246); value_expression(); } } - setState(249); + setState(251); _errHandler.sync(this); _la = _input.LA(1); } - setState(250); + setState(252); match(T__2); } break; @@ -1974,16 +1974,16 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(254); - match(PATH_VARIABLE); - setState(255); - match(T__23); setState(256); - value_expression(); + match(PATH_VARIABLE); setState(257); - match(T__20); + match(T__23); setState(258); value_expression(); + setState(259); + match(T__20); + setState(260); + value_expression(); } } catch (RecognitionException re) { _localctx.exception = re; @@ -2034,16 +2034,16 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(260); - value_expression(); - setState(261); - match(T__23); setState(262); - match(PATH_VARIABLE); + value_expression(); setState(263); - match(T__20); + match(T__23); setState(264); match(PATH_VARIABLE); + setState(265); + match(T__20); + setState(266); + match(PATH_VARIABLE); } } catch (RecognitionException re) { _localctx.exception = re; @@ -2084,26 +2084,26 @@ public class EQLParser extends Parser { IsNull_expressionContext _localctx = new IsNull_expressionContext(_ctx, getState()); enterRule(_localctx, 60, RULE_isNull_expression); try { - setState(271); + setState(273); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 25, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(266); - match(PATH_VARIABLE); - setState(267); - match(T__24); setState(268); + match(PATH_VARIABLE); + setState(269); + match(T__24); + setState(270); match(T__25); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(269); + setState(271); match(PATH_VARIABLE); - setState(270); + setState(272); match(T__26); } break; @@ -2147,37 +2147,37 @@ public class EQLParser extends Parser { IsNotNull_expressionContext _localctx = new IsNotNull_expressionContext(_ctx, getState()); enterRule(_localctx, 62, RULE_isNotNull_expression); try { - setState(281); + setState(283); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 26, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(273); - match(PATH_VARIABLE); - setState(274); - match(T__24); setState(275); - match(T__21); + match(PATH_VARIABLE); setState(276); + match(T__24); + setState(277); + match(T__21); + setState(278); match(T__25); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(277); + setState(279); match(PATH_VARIABLE); - setState(278); + setState(280); match(T__27); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(279); + setState(281); match(PATH_VARIABLE); - setState(280); + setState(282); match(T__28); } break; @@ -2221,26 +2221,26 @@ public class EQLParser extends Parser { IsEmpty_expressionContext _localctx = new IsEmpty_expressionContext(_ctx, getState()); enterRule(_localctx, 64, RULE_isEmpty_expression); try { - setState(288); + setState(290); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 27, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(283); - match(PATH_VARIABLE); - setState(284); - match(T__24); setState(285); + match(PATH_VARIABLE); + setState(286); + match(T__24); + setState(287); match(T__29); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(286); + setState(288); match(PATH_VARIABLE); - setState(287); + setState(289); match(T__30); } break; @@ -2284,37 +2284,37 @@ public class EQLParser extends Parser { IsNotEmpty_expressionContext _localctx = new IsNotEmpty_expressionContext(_ctx, getState()); enterRule(_localctx, 66, RULE_isNotEmpty_expression); try { - setState(298); + setState(300); _errHandler.sync(this); switch (getInterpreter().adaptivePredict(_input, 28, _ctx)) { case 1: enterOuterAlt(_localctx, 1); { - setState(290); - match(PATH_VARIABLE); - setState(291); - match(T__24); setState(292); - match(T__21); + match(PATH_VARIABLE); setState(293); + match(T__24); + setState(294); + match(T__21); + setState(295); match(T__29); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(294); + setState(296); match(PATH_VARIABLE); - setState(295); + setState(297); match(T__31); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(296); + setState(298); match(PATH_VARIABLE); - setState(297); + setState(299); match(T__32); } break; @@ -2368,11 +2368,11 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(300); - match(PATH_VARIABLE); - setState(301); - like_op(); setState(302); + match(PATH_VARIABLE); + setState(303); + like_op(); + setState(304); value_expression(); } } catch (RecognitionException re) { @@ -2413,7 +2413,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(304); + setState(306); _la = _input.LA(1); if (!((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__33) | (1L << T__34) | (1L << T__35) | (1L << T__36) | (1L << T__37) | (1L << T__38) | (1L << T__39) | (1L << T__40))) != 0))) { _errHandler.recoverInline(this); @@ -2470,17 +2470,17 @@ public class EQLParser extends Parser { Comparison_expressionContext _localctx = new Comparison_expressionContext(_ctx, getState()); enterRule(_localctx, 72, RULE_comparison_expression); try { - setState(314); + setState(316); _errHandler.sync(this); switch (_input.LA(1)) { case PATH_VARIABLE: enterOuterAlt(_localctx, 1); { - setState(306); - match(PATH_VARIABLE); - setState(307); - comparison_operator(); setState(308); + match(PATH_VARIABLE); + setState(309); + comparison_operator(); + setState(310); value_expression(); } break; @@ -2490,11 +2490,11 @@ public class EQLParser extends Parser { case STRING_LITERAL: enterOuterAlt(_localctx, 2); { - setState(310); - value_expression(); - setState(311); - comparison_operator(); setState(312); + value_expression(); + setState(313); + comparison_operator(); + setState(314); match(PATH_VARIABLE); } break; @@ -2539,7 +2539,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(316); + setState(318); _la = _input.LA(1); if (!((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << T__41) | (1L << T__42) | (1L << T__43) | (1L << T__44) | (1L << T__45) | (1L << T__46) | (1L << T__47) | (1L << T__48) | (1L << T__49) | (1L << T__50) | (1L << T__51) | (1L << T__52) | (1L << T__53) | (1L << T__54) | (1L << T__55) | (1L << T__56))) != 0))) { _errHandler.recoverInline(this); @@ -2592,7 +2592,7 @@ public class EQLParser extends Parser { Value_expressionContext _localctx = new Value_expressionContext(_ctx, getState()); enterRule(_localctx, 76, RULE_value_expression); try { - setState(320); + setState(322); _errHandler.sync(this); switch (_input.LA(1)) { case BOOLEAN_LITERAL: @@ -2600,14 +2600,14 @@ public class EQLParser extends Parser { case STRING_LITERAL: enterOuterAlt(_localctx, 1); { - setState(318); + setState(320); literal(); } break; case INPUT_VARIABLE: enterOuterAlt(_localctx, 2); { - setState(319); + setState(321); match(INPUT_VARIABLE); } break; @@ -2664,7 +2664,7 @@ public class EQLParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(322); + setState(324); _la = _input.LA(1); if (!(((((_la - 60)) & ~0x3f) == 0 && ((1L << (_la - 60)) & ((1L << (BOOLEAN_LITERAL - 60)) | (1L << (NUMBER_LITERAL - 60)) | (1L << (STRING_LITERAL - 60)))) != 0))) { _errHandler.recoverInline(this); @@ -2685,114 +2685,115 @@ public class EQLParser extends Parser { } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3D\u0147\4\2\t\2\4" + + "\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3D\u0149\4\2\t\2\4" + "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t" + "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22" + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31" + "\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!" + "\t!\4\"\t\"\4#\t#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\3\2\5\2T\n\2\3" + - "\2\7\2W\n\2\f\2\16\2Z\13\2\3\2\5\2]\n\2\3\2\5\2`\n\2\3\2\5\2c\n\2\3\3" + - "\3\3\5\3g\n\3\3\3\3\3\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\6\3\7\3\7\3\7" + - "\3\7\3\7\7\7y\n\7\f\7\16\7|\13\7\3\b\3\b\5\b\u0080\n\b\3\b\5\b\u0083\n" + - "\b\3\t\3\t\3\t\3\t\5\t\u0089\n\t\3\n\3\n\3\13\3\13\3\13\5\13\u0090\n\13" + - "\3\f\3\f\3\f\3\r\3\r\5\r\u0097\n\r\3\r\3\r\5\r\u009b\n\r\3\16\3\16\3\16" + - "\3\16\3\17\3\17\3\17\7\17\u00a4\n\17\f\17\16\17\u00a7\13\17\3\20\3\20" + - "\3\20\5\20\u00ac\n\20\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\5\23\u00b6" + - "\n\23\3\24\3\24\5\24\u00ba\n\24\3\25\3\25\5\25\u00be\n\25\3\26\3\26\3" + - "\26\3\26\3\27\3\27\3\27\7\27\u00c7\n\27\f\27\16\27\u00ca\13\27\3\30\3" + - "\30\3\30\7\30\u00cf\n\30\f\30\16\30\u00d2\13\30\3\31\5\31\u00d5\n\31\3" + - "\31\3\31\3\32\3\32\3\32\3\32\3\32\5\32\u00de\n\32\3\33\3\33\3\33\3\33" + - "\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\5\33\u00ed\n\33\3\34\3\34" + - "\3\34\3\34\3\35\3\35\3\35\3\35\3\35\7\35\u00f8\n\35\f\35\16\35\u00fb\13" + - "\35\3\35\3\35\5\35\u00ff\n\35\3\36\3\36\3\36\3\36\3\36\3\36\3\37\3\37" + - "\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \5 \u0112\n \3!\3!\3!\3!\3!\3!\3!\3" + - "!\5!\u011c\n!\3\"\3\"\3\"\3\"\3\"\5\"\u0123\n\"\3#\3#\3#\3#\3#\3#\3#\3" + - "#\5#\u012d\n#\3$\3$\3$\3$\3%\3%\3&\3&\3&\3&\3&\3&\3&\3&\5&\u013d\n&\3" + - "\'\3\'\3(\3(\5(\u0143\n(\3)\3)\3)\2\2*\2\4\6\b\n\f\16\20\22\24\26\30\32" + - "\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNP\2\6\3\2\16\17\3\2$+\3\2,;\4\2" + - ">?CC\u0148\2S\3\2\2\2\4d\3\2\2\2\6l\3\2\2\2\bn\3\2\2\2\np\3\2\2\2\fs\3" + - "\2\2\2\16}\3\2\2\2\20\u0088\3\2\2\2\22\u008a\3\2\2\2\24\u008c\3\2\2\2" + - "\26\u0091\3\2\2\2\30\u0094\3\2\2\2\32\u009c\3\2\2\2\34\u00a0\3\2\2\2\36" + - "\u00ab\3\2\2\2 \u00ad\3\2\2\2\"\u00b0\3\2\2\2$\u00b5\3\2\2\2&\u00b7\3" + - "\2\2\2(\u00bb\3\2\2\2*\u00bf\3\2\2\2,\u00c3\3\2\2\2.\u00cb\3\2\2\2\60" + - "\u00d4\3\2\2\2\62\u00dd\3\2\2\2\64\u00ec\3\2\2\2\66\u00ee\3\2\2\28\u00fe" + - "\3\2\2\2:\u0100\3\2\2\2<\u0106\3\2\2\2>\u0111\3\2\2\2@\u011b\3\2\2\2B" + - "\u0122\3\2\2\2D\u012c\3\2\2\2F\u012e\3\2\2\2H\u0132\3\2\2\2J\u013c\3\2" + - "\2\2L\u013e\3\2\2\2N\u0142\3\2\2\2P\u0144\3\2\2\2RT\5\4\3\2SR\3\2\2\2" + - "ST\3\2\2\2TX\3\2\2\2UW\5\b\5\2VU\3\2\2\2WZ\3\2\2\2XV\3\2\2\2XY\3\2\2\2" + - "Y\\\3\2\2\2ZX\3\2\2\2[]\5\n\6\2\\[\3\2\2\2\\]\3\2\2\2]_\3\2\2\2^`\5\f" + - "\7\2_^\3\2\2\2_`\3\2\2\2`b\3\2\2\2ac\5\24\13\2ba\3\2\2\2bc\3\2\2\2c\3" + - "\3\2\2\2df\7\3\2\2eg\5\6\4\2fe\3\2\2\2fg\3\2\2\2gh\3\2\2\2hi\7\4\2\2i" + - "j\5\34\17\2jk\7\5\2\2k\5\3\2\2\2lm\7\6\2\2m\7\3\2\2\2no\5\30\r\2o\t\3" + - "\2\2\2pq\7\7\2\2qr\5,\27\2r\13\3\2\2\2st\7\b\2\2tu\7\t\2\2uz\5\16\b\2" + - "vw\7\n\2\2wy\5\16\b\2xv\3\2\2\2y|\3\2\2\2zx\3\2\2\2z{\3\2\2\2{\r\3\2\2" + - "\2|z\3\2\2\2}\177\7=\2\2~\u0080\5\22\n\2\177~\3\2\2\2\177\u0080\3\2\2" + - "\2\u0080\u0082\3\2\2\2\u0081\u0083\5\20\t\2\u0082\u0081\3\2\2\2\u0082" + - "\u0083\3\2\2\2\u0083\17\3\2\2\2\u0084\u0085\7\13\2\2\u0085\u0089\7\f\2" + - "\2\u0086\u0087\7\13\2\2\u0087\u0089\7\r\2\2\u0088\u0084\3\2\2\2\u0088" + - "\u0086\3\2\2\2\u0089\21\3\2\2\2\u008a\u008b\t\2\2\2\u008b\23\3\2\2\2\u008c" + - "\u008d\7\20\2\2\u008d\u008f\7?\2\2\u008e\u0090\5\26\f\2\u008f\u008e\3" + - "\2\2\2\u008f\u0090\3\2\2\2\u0090\25\3\2\2\2\u0091\u0092\7\21\2\2\u0092" + - "\u0093\7?\2\2\u0093\27\3\2\2\2\u0094\u0096\7\22\2\2\u0095\u0097\5$\23" + - "\2\u0096\u0095\3\2\2\2\u0096\u0097\3\2\2\2\u0097\u0098\3\2\2\2\u0098\u009a" + - "\7=\2\2\u0099\u009b\5\32\16\2\u009a\u0099\3\2\2\2\u009a\u009b\3\2\2\2" + - "\u009b\31\3\2\2\2\u009c\u009d\7\4\2\2\u009d\u009e\5\34\17\2\u009e\u009f" + - "\7\5\2\2\u009f\33\3\2\2\2\u00a0\u00a5\5\36\20\2\u00a1\u00a2\7\n\2\2\u00a2" + - "\u00a4\5\36\20\2\u00a3\u00a1\3\2\2\2\u00a4\u00a7\3\2\2\2\u00a5\u00a3\3" + - "\2\2\2\u00a5\u00a6\3\2\2\2\u00a6\35\3\2\2\2\u00a7\u00a5\3\2\2\2\u00a8" + - "\u00ac\7=\2\2\u00a9\u00ac\5 \21\2\u00aa\u00ac\5\"\22\2\u00ab\u00a8\3\2" + - "\2\2\u00ab\u00a9\3\2\2\2\u00ab\u00aa\3\2\2\2\u00ac\37\3\2\2\2\u00ad\u00ae" + - "\7\23\2\2\u00ae\u00af\5&\24\2\u00af!\3\2\2\2\u00b0\u00b1\7\23\2\2\u00b1" + - "\u00b2\5(\25\2\u00b2#\3\2\2\2\u00b3\u00b6\5&\24\2\u00b4\u00b6\5(\25\2" + - "\u00b5\u00b3\3\2\2\2\u00b5\u00b4\3\2\2\2\u00b6%\3\2\2\2\u00b7\u00b9\7" + - "\24\2\2\u00b8\u00ba\5*\26\2\u00b9\u00b8\3\2\2\2\u00b9\u00ba\3\2\2\2\u00ba" + - "\'\3\2\2\2\u00bb\u00bd\7\25\2\2\u00bc\u00be\5*\26\2\u00bd\u00bc\3\2\2" + - "\2\u00bd\u00be\3\2\2\2\u00be)\3\2\2\2\u00bf\u00c0\7\4\2\2\u00c0\u00c1" + - "\7?\2\2\u00c1\u00c2\7\5\2\2\u00c2+\3\2\2\2\u00c3\u00c8\5.\30\2\u00c4\u00c5" + - "\7\26\2\2\u00c5\u00c7\5.\30\2\u00c6\u00c4\3\2\2\2\u00c7\u00ca\3\2\2\2" + - "\u00c8\u00c6\3\2\2\2\u00c8\u00c9\3\2\2\2\u00c9-\3\2\2\2\u00ca\u00c8\3" + - "\2\2\2\u00cb\u00d0\5\60\31\2\u00cc\u00cd\7\27\2\2\u00cd\u00cf\5\60\31" + - "\2\u00ce\u00cc\3\2\2\2\u00cf\u00d2\3\2\2\2\u00d0\u00ce\3\2\2\2\u00d0\u00d1" + - "\3\2\2\2\u00d1/\3\2\2\2\u00d2\u00d0\3\2\2\2\u00d3\u00d5\7\30\2\2\u00d4" + - "\u00d3\3\2\2\2\u00d4\u00d5\3\2\2\2\u00d5\u00d6\3\2\2\2\u00d6\u00d7\5\62" + - "\32\2\u00d7\61\3\2\2\2\u00d8\u00de\5\64\33\2\u00d9\u00da\7\4\2\2\u00da" + - "\u00db\5,\27\2\u00db\u00dc\7\5\2\2\u00dc\u00de\3\2\2\2\u00dd\u00d8\3\2" + - "\2\2\u00dd\u00d9\3\2\2\2\u00de\63\3\2\2\2\u00df\u00ed\5J&\2\u00e0\u00ed" + - "\5F$\2\u00e1\u00ed\5:\36\2\u00e2\u00ed\5<\37\2\u00e3\u00ed\5\66\34\2\u00e4" + - "\u00ed\5> \2\u00e5\u00ed\5@!\2\u00e6\u00ed\5B\"\2\u00e7\u00ed\5D#\2\u00e8" + - "\u00e9\7\4\2\2\u00e9\u00ea\5\64\33\2\u00ea\u00eb\7\5\2\2\u00eb\u00ed\3" + - "\2\2\2\u00ec\u00df\3\2\2\2\u00ec\u00e0\3\2\2\2\u00ec\u00e1\3\2\2\2\u00ec" + - "\u00e2\3\2\2\2\u00ec\u00e3\3\2\2\2\u00ec\u00e4\3\2\2\2\u00ec\u00e5\3\2" + - "\2\2\u00ec\u00e6\3\2\2\2\u00ec\u00e7\3\2\2\2\u00ec\u00e8\3\2\2\2\u00ed" + - "\65\3\2\2\2\u00ee\u00ef\7=\2\2\u00ef\u00f0\7\31\2\2\u00f0\u00f1\58\35" + - "\2\u00f1\67\3\2\2\2\u00f2\u00ff\7<\2\2\u00f3\u00f4\7\4\2\2\u00f4\u00f9" + - "\5N(\2\u00f5\u00f6\7\n\2\2\u00f6\u00f8\5N(\2\u00f7\u00f5\3\2\2\2\u00f8" + - "\u00fb\3\2\2\2\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2\2\u00fa\u00fc\3\2" + - "\2\2\u00fb\u00f9\3\2\2\2\u00fc\u00fd\7\5\2\2\u00fd\u00ff\3\2\2\2\u00fe" + - "\u00f2\3\2\2\2\u00fe\u00f3\3\2\2\2\u00ff9\3\2\2\2\u0100\u0101\7=\2\2\u0101" + - "\u0102\7\32\2\2\u0102\u0103\5N(\2\u0103\u0104\7\27\2\2\u0104\u0105\5N" + - "(\2\u0105;\3\2\2\2\u0106\u0107\5N(\2\u0107\u0108\7\32\2\2\u0108\u0109" + - "\7=\2\2\u0109\u010a\7\27\2\2\u010a\u010b\7=\2\2\u010b=\3\2\2\2\u010c\u010d" + - "\7=\2\2\u010d\u010e\7\33\2\2\u010e\u0112\7\34\2\2\u010f\u0110\7=\2\2\u0110" + - "\u0112\7\35\2\2\u0111\u010c\3\2\2\2\u0111\u010f\3\2\2\2\u0112?\3\2\2\2" + - "\u0113\u0114\7=\2\2\u0114\u0115\7\33\2\2\u0115\u0116\7\30\2\2\u0116\u011c" + - "\7\34\2\2\u0117\u0118\7=\2\2\u0118\u011c\7\36\2\2\u0119\u011a\7=\2\2\u011a" + - "\u011c\7\37\2\2\u011b\u0113\3\2\2\2\u011b\u0117\3\2\2\2\u011b\u0119\3" + - "\2\2\2\u011cA\3\2\2\2\u011d\u011e\7=\2\2\u011e\u011f\7\33\2\2\u011f\u0123" + - "\7 \2\2\u0120\u0121\7=\2\2\u0121\u0123\7!\2\2\u0122\u011d\3\2\2\2\u0122" + - "\u0120\3\2\2\2\u0123C\3\2\2\2\u0124\u0125\7=\2\2\u0125\u0126\7\33\2\2" + - "\u0126\u0127\7\30\2\2\u0127\u012d\7 \2\2\u0128\u0129\7=\2\2\u0129\u012d" + - "\7\"\2\2\u012a\u012b\7=\2\2\u012b\u012d\7#\2\2\u012c\u0124\3\2\2\2\u012c" + - "\u0128\3\2\2\2\u012c\u012a\3\2\2\2\u012dE\3\2\2\2\u012e\u012f\7=\2\2\u012f" + - "\u0130\5H%\2\u0130\u0131\5N(\2\u0131G\3\2\2\2\u0132\u0133\t\3\2\2\u0133" + - "I\3\2\2\2\u0134\u0135\7=\2\2\u0135\u0136\5L\'\2\u0136\u0137\5N(\2\u0137" + - "\u013d\3\2\2\2\u0138\u0139\5N(\2\u0139\u013a\5L\'\2\u013a\u013b\7=\2\2" + - "\u013b\u013d\3\2\2\2\u013c\u0134\3\2\2\2\u013c\u0138\3\2\2\2\u013dK\3" + - "\2\2\2\u013e\u013f\t\4\2\2\u013fM\3\2\2\2\u0140\u0143\5P)\2\u0141\u0143" + - "\7<\2\2\u0142\u0140\3\2\2\2\u0142\u0141\3\2\2\2\u0143O\3\2\2\2\u0144\u0145" + - "\t\5\2\2\u0145Q\3\2\2\2!SX\\_bfz\177\u0082\u0088\u008f\u0096\u009a\u00a5" + - "\u00ab\u00b5\u00b9\u00bd\u00c8\u00d0\u00d4\u00dd\u00ec\u00f9\u00fe\u0111" + - "\u011b\u0122\u012c\u013c\u0142"; + "\2\7\2W\n\2\f\2\16\2Z\13\2\3\2\5\2]\n\2\3\2\5\2`\n\2\3\2\5\2c\n\2\3\2" + + "\3\2\3\3\3\3\5\3i\n\3\3\3\3\3\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6\3\6\3\7" + + "\3\7\3\7\3\7\3\7\7\7{\n\7\f\7\16\7~\13\7\3\b\3\b\5\b\u0082\n\b\3\b\5\b" + + "\u0085\n\b\3\t\3\t\3\t\3\t\5\t\u008b\n\t\3\n\3\n\3\13\3\13\3\13\5\13\u0092" + + "\n\13\3\f\3\f\3\f\3\r\3\r\5\r\u0099\n\r\3\r\3\r\5\r\u009d\n\r\3\16\3\16" + + "\3\16\3\16\3\17\3\17\3\17\7\17\u00a6\n\17\f\17\16\17\u00a9\13\17\3\20" + + "\3\20\3\20\5\20\u00ae\n\20\3\21\3\21\3\21\3\22\3\22\3\22\3\23\3\23\5\23" + + "\u00b8\n\23\3\24\3\24\5\24\u00bc\n\24\3\25\3\25\5\25\u00c0\n\25\3\26\3" + + "\26\3\26\3\26\3\27\3\27\3\27\7\27\u00c9\n\27\f\27\16\27\u00cc\13\27\3" + + "\30\3\30\3\30\7\30\u00d1\n\30\f\30\16\30\u00d4\13\30\3\31\5\31\u00d7\n" + + "\31\3\31\3\31\3\32\3\32\3\32\3\32\3\32\5\32\u00e0\n\32\3\33\3\33\3\33" + + "\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\5\33\u00ef\n\33\3\34" + + "\3\34\3\34\3\34\3\35\3\35\3\35\3\35\3\35\7\35\u00fa\n\35\f\35\16\35\u00fd" + + "\13\35\3\35\3\35\5\35\u0101\n\35\3\36\3\36\3\36\3\36\3\36\3\36\3\37\3" + + "\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \5 \u0114\n \3!\3!\3!\3!\3!\3!\3" + + "!\3!\5!\u011e\n!\3\"\3\"\3\"\3\"\3\"\5\"\u0125\n\"\3#\3#\3#\3#\3#\3#\3" + + "#\3#\5#\u012f\n#\3$\3$\3$\3$\3%\3%\3&\3&\3&\3&\3&\3&\3&\3&\5&\u013f\n" + + "&\3\'\3\'\3(\3(\5(\u0145\n(\3)\3)\3)\2\2*\2\4\6\b\n\f\16\20\22\24\26\30" + + "\32\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJLNP\2\6\3\2\16\17\3\2$+\3\2,;" + + "\4\2>?CC\2\u014a\2S\3\2\2\2\4f\3\2\2\2\6n\3\2\2\2\bp\3\2\2\2\nr\3\2\2" + + "\2\fu\3\2\2\2\16\177\3\2\2\2\20\u008a\3\2\2\2\22\u008c\3\2\2\2\24\u008e" + + "\3\2\2\2\26\u0093\3\2\2\2\30\u0096\3\2\2\2\32\u009e\3\2\2\2\34\u00a2\3" + + "\2\2\2\36\u00ad\3\2\2\2 \u00af\3\2\2\2\"\u00b2\3\2\2\2$\u00b7\3\2\2\2" + + "&\u00b9\3\2\2\2(\u00bd\3\2\2\2*\u00c1\3\2\2\2,\u00c5\3\2\2\2.\u00cd\3" + + "\2\2\2\60\u00d6\3\2\2\2\62\u00df\3\2\2\2\64\u00ee\3\2\2\2\66\u00f0\3\2" + + "\2\28\u0100\3\2\2\2:\u0102\3\2\2\2<\u0108\3\2\2\2>\u0113\3\2\2\2@\u011d" + + "\3\2\2\2B\u0124\3\2\2\2D\u012e\3\2\2\2F\u0130\3\2\2\2H\u0134\3\2\2\2J" + + "\u013e\3\2\2\2L\u0140\3\2\2\2N\u0144\3\2\2\2P\u0146\3\2\2\2RT\5\4\3\2" + + "SR\3\2\2\2ST\3\2\2\2TX\3\2\2\2UW\5\b\5\2VU\3\2\2\2WZ\3\2\2\2XV\3\2\2\2" + + "XY\3\2\2\2Y\\\3\2\2\2ZX\3\2\2\2[]\5\n\6\2\\[\3\2\2\2\\]\3\2\2\2]_\3\2" + + "\2\2^`\5\f\7\2_^\3\2\2\2_`\3\2\2\2`b\3\2\2\2ac\5\24\13\2ba\3\2\2\2bc\3" + + "\2\2\2cd\3\2\2\2de\7\2\2\3e\3\3\2\2\2fh\7\3\2\2gi\5\6\4\2hg\3\2\2\2hi" + + "\3\2\2\2ij\3\2\2\2jk\7\4\2\2kl\5\34\17\2lm\7\5\2\2m\5\3\2\2\2no\7\6\2" + + "\2o\7\3\2\2\2pq\5\30\r\2q\t\3\2\2\2rs\7\7\2\2st\5,\27\2t\13\3\2\2\2uv" + + "\7\b\2\2vw\7\t\2\2w|\5\16\b\2xy\7\n\2\2y{\5\16\b\2zx\3\2\2\2{~\3\2\2\2" + + "|z\3\2\2\2|}\3\2\2\2}\r\3\2\2\2~|\3\2\2\2\177\u0081\7=\2\2\u0080\u0082" + + "\5\22\n\2\u0081\u0080\3\2\2\2\u0081\u0082\3\2\2\2\u0082\u0084\3\2\2\2" + + "\u0083\u0085\5\20\t\2\u0084\u0083\3\2\2\2\u0084\u0085\3\2\2\2\u0085\17" + + "\3\2\2\2\u0086\u0087\7\13\2\2\u0087\u008b\7\f\2\2\u0088\u0089\7\13\2\2" + + "\u0089\u008b\7\r\2\2\u008a\u0086\3\2\2\2\u008a\u0088\3\2\2\2\u008b\21" + + "\3\2\2\2\u008c\u008d\t\2\2\2\u008d\23\3\2\2\2\u008e\u008f\7\20\2\2\u008f" + + "\u0091\7?\2\2\u0090\u0092\5\26\f\2\u0091\u0090\3\2\2\2\u0091\u0092\3\2" + + "\2\2\u0092\25\3\2\2\2\u0093\u0094\7\21\2\2\u0094\u0095\7?\2\2\u0095\27" + + "\3\2\2\2\u0096\u0098\7\22\2\2\u0097\u0099\5$\23\2\u0098\u0097\3\2\2\2" + + "\u0098\u0099\3\2\2\2\u0099\u009a\3\2\2\2\u009a\u009c\7=\2\2\u009b\u009d" + + "\5\32\16\2\u009c\u009b\3\2\2\2\u009c\u009d\3\2\2\2\u009d\31\3\2\2\2\u009e" + + "\u009f\7\4\2\2\u009f\u00a0\5\34\17\2\u00a0\u00a1\7\5\2\2\u00a1\33\3\2" + + "\2\2\u00a2\u00a7\5\36\20\2\u00a3\u00a4\7\n\2\2\u00a4\u00a6\5\36\20\2\u00a5" + + "\u00a3\3\2\2\2\u00a6\u00a9\3\2\2\2\u00a7\u00a5\3\2\2\2\u00a7\u00a8\3\2" + + "\2\2\u00a8\35\3\2\2\2\u00a9\u00a7\3\2\2\2\u00aa\u00ae\7=\2\2\u00ab\u00ae" + + "\5 \21\2\u00ac\u00ae\5\"\22\2\u00ad\u00aa\3\2\2\2\u00ad\u00ab\3\2\2\2" + + "\u00ad\u00ac\3\2\2\2\u00ae\37\3\2\2\2\u00af\u00b0\7\23\2\2\u00b0\u00b1" + + "\5&\24\2\u00b1!\3\2\2\2\u00b2\u00b3\7\23\2\2\u00b3\u00b4\5(\25\2\u00b4" + + "#\3\2\2\2\u00b5\u00b8\5&\24\2\u00b6\u00b8\5(\25\2\u00b7\u00b5\3\2\2\2" + + "\u00b7\u00b6\3\2\2\2\u00b8%\3\2\2\2\u00b9\u00bb\7\24\2\2\u00ba\u00bc\5" + + "*\26\2\u00bb\u00ba\3\2\2\2\u00bb\u00bc\3\2\2\2\u00bc\'\3\2\2\2\u00bd\u00bf" + + "\7\25\2\2\u00be\u00c0\5*\26\2\u00bf\u00be\3\2\2\2\u00bf\u00c0\3\2\2\2" + + "\u00c0)\3\2\2\2\u00c1\u00c2\7\4\2\2\u00c2\u00c3\7?\2\2\u00c3\u00c4\7\5" + + "\2\2\u00c4+\3\2\2\2\u00c5\u00ca\5.\30\2\u00c6\u00c7\7\26\2\2\u00c7\u00c9" + + "\5.\30\2\u00c8\u00c6\3\2\2\2\u00c9\u00cc\3\2\2\2\u00ca\u00c8\3\2\2\2\u00ca" + + "\u00cb\3\2\2\2\u00cb-\3\2\2\2\u00cc\u00ca\3\2\2\2\u00cd\u00d2\5\60\31" + + "\2\u00ce\u00cf\7\27\2\2\u00cf\u00d1\5\60\31\2\u00d0\u00ce\3\2\2\2\u00d1" + + "\u00d4\3\2\2\2\u00d2\u00d0\3\2\2\2\u00d2\u00d3\3\2\2\2\u00d3/\3\2\2\2" + + "\u00d4\u00d2\3\2\2\2\u00d5\u00d7\7\30\2\2\u00d6\u00d5\3\2\2\2\u00d6\u00d7" + + "\3\2\2\2\u00d7\u00d8\3\2\2\2\u00d8\u00d9\5\62\32\2\u00d9\61\3\2\2\2\u00da" + + "\u00e0\5\64\33\2\u00db\u00dc\7\4\2\2\u00dc\u00dd\5,\27\2\u00dd\u00de\7" + + "\5\2\2\u00de\u00e0\3\2\2\2\u00df\u00da\3\2\2\2\u00df\u00db\3\2\2\2\u00e0" + + "\63\3\2\2\2\u00e1\u00ef\5J&\2\u00e2\u00ef\5F$\2\u00e3\u00ef\5:\36\2\u00e4" + + "\u00ef\5<\37\2\u00e5\u00ef\5\66\34\2\u00e6\u00ef\5> \2\u00e7\u00ef\5@" + + "!\2\u00e8\u00ef\5B\"\2\u00e9\u00ef\5D#\2\u00ea\u00eb\7\4\2\2\u00eb\u00ec" + + "\5\64\33\2\u00ec\u00ed\7\5\2\2\u00ed\u00ef\3\2\2\2\u00ee\u00e1\3\2\2\2" + + "\u00ee\u00e2\3\2\2\2\u00ee\u00e3\3\2\2\2\u00ee\u00e4\3\2\2\2\u00ee\u00e5" + + "\3\2\2\2\u00ee\u00e6\3\2\2\2\u00ee\u00e7\3\2\2\2\u00ee\u00e8\3\2\2\2\u00ee" + + "\u00e9\3\2\2\2\u00ee\u00ea\3\2\2\2\u00ef\65\3\2\2\2\u00f0\u00f1\7=\2\2" + + "\u00f1\u00f2\7\31\2\2\u00f2\u00f3\58\35\2\u00f3\67\3\2\2\2\u00f4\u0101" + + "\7<\2\2\u00f5\u00f6\7\4\2\2\u00f6\u00fb\5N(\2\u00f7\u00f8\7\n\2\2\u00f8" + + "\u00fa\5N(\2\u00f9\u00f7\3\2\2\2\u00fa\u00fd\3\2\2\2\u00fb\u00f9\3\2\2" + + "\2\u00fb\u00fc\3\2\2\2\u00fc\u00fe\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fe\u00ff" + + "\7\5\2\2\u00ff\u0101\3\2\2\2\u0100\u00f4\3\2\2\2\u0100\u00f5\3\2\2\2\u0101" + + "9\3\2\2\2\u0102\u0103\7=\2\2\u0103\u0104\7\32\2\2\u0104\u0105\5N(\2\u0105" + + "\u0106\7\27\2\2\u0106\u0107\5N(\2\u0107;\3\2\2\2\u0108\u0109\5N(\2\u0109" + + "\u010a\7\32\2\2\u010a\u010b\7=\2\2\u010b\u010c\7\27\2\2\u010c\u010d\7" + + "=\2\2\u010d=\3\2\2\2\u010e\u010f\7=\2\2\u010f\u0110\7\33\2\2\u0110\u0114" + + "\7\34\2\2\u0111\u0112\7=\2\2\u0112\u0114\7\35\2\2\u0113\u010e\3\2\2\2" + + "\u0113\u0111\3\2\2\2\u0114?\3\2\2\2\u0115\u0116\7=\2\2\u0116\u0117\7\33" + + "\2\2\u0117\u0118\7\30\2\2\u0118\u011e\7\34\2\2\u0119\u011a\7=\2\2\u011a" + + "\u011e\7\36\2\2\u011b\u011c\7=\2\2\u011c\u011e\7\37\2\2\u011d\u0115\3" + + "\2\2\2\u011d\u0119\3\2\2\2\u011d\u011b\3\2\2\2\u011eA\3\2\2\2\u011f\u0120" + + "\7=\2\2\u0120\u0121\7\33\2\2\u0121\u0125\7 \2\2\u0122\u0123\7=\2\2\u0123" + + "\u0125\7!\2\2\u0124\u011f\3\2\2\2\u0124\u0122\3\2\2\2\u0125C\3\2\2\2\u0126" + + "\u0127\7=\2\2\u0127\u0128\7\33\2\2\u0128\u0129\7\30\2\2\u0129\u012f\7" + + " \2\2\u012a\u012b\7=\2\2\u012b\u012f\7\"\2\2\u012c\u012d\7=\2\2\u012d" + + "\u012f\7#\2\2\u012e\u0126\3\2\2\2\u012e\u012a\3\2\2\2\u012e\u012c\3\2" + + "\2\2\u012fE\3\2\2\2\u0130\u0131\7=\2\2\u0131\u0132\5H%\2\u0132\u0133\5" + + "N(\2\u0133G\3\2\2\2\u0134\u0135\t\3\2\2\u0135I\3\2\2\2\u0136\u0137\7=" + + "\2\2\u0137\u0138\5L\'\2\u0138\u0139\5N(\2\u0139\u013f\3\2\2\2\u013a\u013b" + + "\5N(\2\u013b\u013c\5L\'\2\u013c\u013d\7=\2\2\u013d\u013f\3\2\2\2\u013e" + + "\u0136\3\2\2\2\u013e\u013a\3\2\2\2\u013fK\3\2\2\2\u0140\u0141\t\4\2\2" + + "\u0141M\3\2\2\2\u0142\u0145\5P)\2\u0143\u0145\7<\2\2\u0144\u0142\3\2\2" + + "\2\u0144\u0143\3\2\2\2\u0145O\3\2\2\2\u0146\u0147\t\5\2\2\u0147Q\3\2\2" + + "\2!SX\\_bh|\u0081\u0084\u008a\u0091\u0098\u009c\u00a7\u00ad\u00b7\u00bb" + + "\u00bf\u00ca\u00d2\u00d6\u00df\u00ee\u00fb\u0100\u0113\u011d\u0124\u012e" + + "\u013e\u0144"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); diff --git a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java index d4c569262..0f09a79a1 100644 --- a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java +++ b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java @@ -17,12 +17,12 @@ public class EqlParserTest extends BaseTestCase { @Test(expected = IllegalArgumentException.class) - public void illegal_syntax() throws Exception { + public void illegal_syntax() { parse("find Article where name = :p0"); } @Test - public void where_eq() throws Exception { + public void where_eq() { Query query = parse("where name eq 'Rob'"); query.findList(); @@ -31,7 +31,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_eq_reverse() throws Exception { + public void where_eq_reverse() { Query query = parse("where 'Rob' eq name"); query.findList(); @@ -40,7 +40,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_gt_reverse() throws Exception { + public void where_gt_reverse() { Query query = parse("where 'Rob' > name"); query.findList(); @@ -48,7 +48,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_gte_reverse() throws Exception { + public void where_gte_reverse() { Query query = parse("where 'Rob' >= name"); query.findList(); @@ -56,7 +56,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_lt_reverse() throws Exception { + public void where_lt_reverse() { Query query = parse("where 'Rob' < name"); query.findList(); @@ -64,7 +64,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_lte_reverse() throws Exception { + public void where_lte_reverse() { Query query = parse("where 'Rob' <= name"); query.findList(); @@ -72,7 +72,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_ieq() throws Exception { + public void where_ieq() { Query query = parse("where name ieq 'Rob'"); query.findList(); @@ -81,7 +81,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_ieq_reverse() throws Exception { + public void where_ieq_reverse() { Query query = parse("where 'Rob' ieq name"); query.findList(); @@ -89,7 +89,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_eq2() throws Exception { + public void where_eq2() { Query query = parse("where name = 'Rob'"); query.findList(); @@ -98,7 +98,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_namedParam() throws Exception { + public void where_namedParam() { Query query = parse("where name eq :name"); query.setParameter("name", "Rob"); @@ -117,7 +117,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_namedParam_startsWith() throws Exception { + public void where_namedParam_startsWith() { Query query = parse("where name startsWith :name"); query.setParameter("name", "Rob"); @@ -127,7 +127,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_or1() throws Exception { + public void where_or1() { Query query = parse("where name = 'Rob' or (status = 'NEW' and smallnote is null)"); query.findList(); @@ -136,7 +136,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_or2() throws Exception { + public void where_or2() { Query query = parse("where (name = 'Rob' or status = 'NEW') and smallnote is null"); query.findList(); @@ -145,7 +145,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void test_simplifyExpressions() throws Exception { + public void test_simplifyExpressions() { Query query = parse("where not (name = 'Rob' and status = 'NEW')"); query.findList(); @@ -162,7 +162,7 @@ public class EqlParserTest extends BaseTestCase { @Test - public void where_in() throws Exception { + public void where_in() { Query query = parse("where name in ('Rob','Jim')"); query.findList(); @@ -171,7 +171,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_in_when_namedParams() throws Exception { + public void where_in_when_namedParams() { Query query = parse("where name in (:one, :two)"); query.setParameter("one", "Foo"); @@ -182,7 +182,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_in_when_namedParams_withWhitespace() throws Exception { + public void where_in_when_namedParams_withWhitespace() { Query query = parse("where name in (:one, :two)"); query.setParameter("one", "Foo"); @@ -193,7 +193,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_in_when_namedParams_withNoWhitespace() throws Exception { + public void where_in_when_namedParams_withNoWhitespace() { Query query = parse("where name in (:one,:two)"); query.setParameter("one", "Foo"); @@ -204,7 +204,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_in_when_namedParamAsList() throws Exception { + public void where_in_when_namedParamAsList() { Query query = parse("where name in (:names)"); query.setParameter("names", Arrays.asList("Baz", "Maz", "Jim")); @@ -214,7 +214,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_between() throws Exception { + public void where_between() { Query query = parse("where name between 'As' and 'B'"); query.findList(); @@ -223,7 +223,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_between_withNamedParams() throws Exception { + public void where_between_withNamedParams() { Query query = parse("where name between :one and :two"); query.setParameter("one", "a"); @@ -234,7 +234,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_betweenProperty() throws Exception { + public void where_betweenProperty() { Query query = parse("where 'x' between name and smallnote"); query.findList(); @@ -243,7 +243,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void where_betweenProperty_withNamed() throws Exception { + public void where_betweenProperty_withNamed() { Query query = parse("where :some between name and smallnote"); query.setParameter("some", "A"); @@ -253,7 +253,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_basic() throws Exception { + public void fetch_basic() { Query query = parse("fetch billingAddress"); query.findList(); @@ -262,7 +262,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_withProperty() throws Exception { + public void fetch_withProperty() { Query query = parse("fetch billingAddress (city)"); query.findList(); @@ -271,7 +271,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_withProperty_noWhitespace() throws Exception { + public void fetch_withProperty_noWhitespace() { Query query = parse("fetch billingAddress(city)"); query.findList(); @@ -280,7 +280,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_basic_multiple() throws Exception { + public void fetch_basic_multiple() { Query query = parse("fetch billingAddress fetch shippingAddress"); query.findList(); @@ -290,7 +290,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_basic_multiple_withProperties() throws Exception { + public void fetch_basic_multiple_withProperties() { Query query = parse("fetch billingAddress (city) fetch shippingAddress (city)"); query.findList(); @@ -299,7 +299,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_lazy() throws Exception { + public void fetch_lazy() { Query query = parse("fetch lazy billingAddress"); query.findList(); @@ -308,7 +308,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_lazy50() throws Exception { + public void fetch_lazy50() { Query query = parse("fetch lazy(50) billingAddress"); query.findList(); @@ -317,7 +317,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_query50() throws Exception { + public void fetch_query50() { ResetBasicData.reset(); Query query = parse("fetch query(50) billingAddress"); @@ -327,7 +327,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_query50_asHint() throws Exception { + public void fetch_query50_asHint() { ResetBasicData.reset(); Query query = parse("fetch billingAddress (+query(50),city)"); @@ -337,7 +337,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void fetch_lazy50_asHint() throws Exception { + public void fetch_lazy50_asHint() { ResetBasicData.reset(); Query query = parse("fetch billingAddress (+lazy(50),city) order by id"); @@ -350,7 +350,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void select() throws Exception { + public void select() { ResetBasicData.reset(); @@ -360,7 +360,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void selectDistinct() throws Exception { + public void selectDistinct() { ResetBasicData.reset(); @@ -371,7 +371,7 @@ public class EqlParserTest extends BaseTestCase { @Test - public void limit() throws Exception { + public void limit() { ResetBasicData.reset(); @@ -383,7 +383,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void limitOffset() throws Exception { + public void limitOffset() { ResetBasicData.reset(); @@ -395,7 +395,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void orderBy() throws Exception { + public void orderBy() { ResetBasicData.reset(); @@ -407,7 +407,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void orderBy_desc() throws Exception { + public void orderBy_desc() { ResetBasicData.reset(); @@ -419,7 +419,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void orderBy_nullsLast() throws Exception { + public void orderBy_nullsLast() { if (!isPlatformOrderNullsSupport()) { return; @@ -435,7 +435,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void orderBy_nullsFirst() throws Exception { + public void orderBy_nullsFirst() { if (!isPlatformOrderNullsSupport()) { return; @@ -450,7 +450,7 @@ public class EqlParserTest extends BaseTestCase { } @Test - public void orderBy_multiple() throws Exception { + public void orderBy_multiple() { if (!isPlatformOrderNullsSupport()) { return; diff --git a/src/test/resources/EQL.g4 b/src/test/resources/EQL.g4 index da25a2851..4e021172b 100644 --- a/src/test/resources/EQL.g4 +++ b/src/test/resources/EQL.g4 @@ -1,21 +1,7 @@ grammar EQL; -@parser::members { - @Override - public void reportError(RecognitionException e) { - throw new RuntimeException("Error in grammer - " + e.getMessage()); - } -} - -@lexer::members { - @Override - public void reportError(RecognitionException e) { - throw new RuntimeException("Error in grammer - " + e.getMessage()); - } -} - select_statement - : select_clause? fetch_clause* where_clause? orderby_clause? limit_clause? + : select_clause? fetch_clause* where_clause? orderby_clause? limit_clause? EOF ; select_clause From 7e56a147be3008c84e78d7bf41d7c5f987a3b315 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 5 Mar 2018 07:29:40 +0100 Subject: [PATCH 0135/1036] FIX: ReadOnlyDatasource must also be configured (#1323) --- src/main/java/io/ebean/config/ServerConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index b0b341fb8..0c6edcc64 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -2724,6 +2724,7 @@ public class ServerConfig { */ protected void loadDataSourceSettings(PropertiesWrapper p) { dataSourceConfig.loadSettings(p.properties, name); + readOnlyDataSourceConfig.loadSettings(p.properties, name); } /** From 5a3e386b7c699548d9dd7a91ce0225da7edeacfc Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 5 Mar 2018 19:59:40 +1300 Subject: [PATCH 0136/1036] No effective change - add test for selecting only some @Aggregation properties --- .../query/aggregation/TestAggregationCount.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 778db90ef..abd586eb9 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -111,6 +111,18 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql).contains(" order by sum(u1.units), t0.name"); } + @Test + public void testSelectSome() { + + Query query0 = Ebean.find(TEventOne.class) + .select("name, count, totalUnits"); + + query0.findList(); + String sql = sqlOf(query0, 5); + assertThat(sql).contains("select t0.id, t0.name, count(u1.id), sum(u1.units) from tevent_one t0"); + assertThat(sql).contains("group by t0.id, t0.name"); + } + @Test public void testSelectOnly() { From ec2c3b13d485b7294fe8753aaa1360e7a2f6e89b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 01:08:42 +1300 Subject: [PATCH 0137/1036] No effective change - add test for deploy parser --- .../deploy/DeployPropertyParserTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index 1d6a9cafa..9c7369a46 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; import org.junit.Test; +import org.tests.model.basic.Address; import org.tests.model.basic.Customer; import static org.assertj.core.api.Assertions.assertThat; @@ -11,6 +12,8 @@ public class DeployPropertyParserTest extends BaseTestCase { private final BeanDescriptor descriptor = getBeanDescriptor(Customer.class); + private final BeanDescriptor
addressBeanDescriptor = getBeanDescriptor(Address.class); + @Test public void from_prefix_expect_unchanged() { assertThat(parser().parse("(select x from status join status)")).isEqualTo("(select x from status join status)"); @@ -31,6 +34,21 @@ public class DeployPropertyParserTest extends BaseTestCase { assertThat(parser().parse("max(billingAddress.country.name)")).isEqualTo("max(${billingAddress.country}name)"); } + @Test + public void simpleMax() { + assertThat(parser().parse("max(name)")).isEqualTo("max(${}name)"); + } + + @Test + public void combined() { + assertThat(parser().parse("sum(status * name)")).isEqualTo("sum(${}status * ${}name)"); + } + + @Test + public void combined_withAtColumn() { + assertThat(adddressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')"); + } + @Test public void unknown_path() { assertThat(parser().parse(" foo ")).isEqualTo(" foo "); @@ -39,5 +57,9 @@ public class DeployPropertyParserTest extends BaseTestCase { private DeployPropertyParser parser() { return descriptor.createDeployPropertyParser(); } + + private DeployPropertyParser adddressParser() { + return addressBeanDescriptor.createDeployPropertyParser(); + } } From 3ca4efc818cd3a3331bf606f7bd8f1a29447e76a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 12:58:43 +1300 Subject: [PATCH 0138/1036] #1331 - ENH: Support Aggregation formula with findSingleAttribute() ... max, min, avg, count and count(distinct ..) --- .../server/deploy/BeanDescriptor.java | 42 ++++ .../server/deploy/BeanDescriptorManager.java | 12 +- .../server/deploy/BeanDescriptorMap.java | 6 + .../server/deploy/BeanProperty.java | 8 +- .../server/deploy/DbSqlContext.java | 5 + .../server/deploy/DeployParser.java | 15 +- .../deploy/DeployPropertyParserMap.java | 2 +- .../server/deploy/DetermineAggPath.java | 4 + .../DynamicPropertyAggregationFormula.java | 52 +++++ .../server/deploy/DynamicPropertyBase.java | 70 ++++++ .../server/deploy/FormulaPropertyPath.java | 89 ++++++++ .../deploy/meta/DeployBeanDescriptor.java | 55 ++++- .../deploy/meta/DeployBeanProperty.java | 24 +- .../server/query/DefaultDbSqlContext.java | 12 +- .../server/query/SqlBeanLoad.java | 17 ++ .../server/query/SqlTreeBuilder.java | 4 +- .../server/query/SqlTreeNodeBean.java | 23 +- .../server/query/SqlTreeProperties.java | 27 ++- .../server/query/SqlTreeProperty.java | 76 +++++++ .../deploy/FormulaPropertyPathTest.java | 35 +++ .../org/tests/model/tevent/TEventOne.java | 26 ++- .../aggregation/TestAggregationCount.java | 215 +++++++++++++++++- .../query/other/TestQuerySingleAttribute.java | 15 ++ 23 files changed, 783 insertions(+), 51 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java create mode 100644 src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java create mode 100644 src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 36330994a..2552d2600 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -62,11 +62,13 @@ import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.DmlUtil; import io.ebeaninternal.server.query.CQueryPlan; import io.ebeaninternal.server.query.CQueryPlanStatsCollector; +import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.DataBind; +import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.util.SortByClause; import io.ebeaninternal.util.SortByClauseParser; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; @@ -112,6 +114,8 @@ public class BeanDescriptor implements BeanType { private final ConcurrentHashMap> comparatorCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap dynamicProperty = new ConcurrentHashMap<>(); + private final Map namedRawSql; private final Map namedQuery; @@ -1055,6 +1059,13 @@ public class BeanDescriptor implements BeanType { return owner.getEncryptKey(tableName, columnName); } + /** + * Return the Scalar type for the given JDBC type. + */ + public ScalarType getScalarType(int jdbcType) { + return owner.getScalarType(jdbcType); + } + /** * Return true if this bean type has a default select clause that is not * simply select all properties. @@ -2437,6 +2448,37 @@ public class BeanDescriptor implements BeanType { return null; } + /** + * Return a 'dynamic property' used to read a formula. + */ + private SqlTreeProperty findSqlTreeFormula(String formulaExpression) { + + return dynamicProperty.computeIfAbsent(formulaExpression, (formula) -> { + FormulaPropertyPath propertyFormula = new FormulaPropertyPath(formula); + if (!propertyFormula.isFormula()) { + throw new IllegalStateException("unable to parse formula [" + formula + "} on bean type " + fullName); + } + String baseName = propertyFormula.basePropertyName(); + BeanProperty base = _findBeanProperty(baseName); + if (base == null) { + throw new IllegalStateException("unable to find property [" + baseName + "] from formula [" + formula + "} on bean type " + fullName); + } + return propertyFormula.formulaProperty(base); + }); + } + + /** + * Return a property that is part of the SQL tree. + * + * The property can be a dynamic formula or a well known bean property. + */ + public SqlTreeProperty findSqlTreeProperty(String propName) { + if (propName.indexOf('(') > -1) { + return findSqlTreeFormula(propName); + } + return _findBeanProperty(propName); + } + /** * Find a BeanProperty including searching the inheritance hierarchy. *

diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 618183220..9d8c6fbe6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -52,7 +52,9 @@ import io.ebeaninternal.server.properties.BeanPropertiesReader; import io.ebeaninternal.server.properties.BeanPropertyAccess; import io.ebeaninternal.server.properties.EnhanceBeanPropertyAccess; import io.ebeaninternal.server.query.CQueryPlan; +import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.server.type.ScalarTypeInteger; +import io.ebeaninternal.server.type.TypeManager; import io.ebeaninternal.xmlmapping.XmlMappingReader; import io.ebeaninternal.xmlmapping.model.XmAliasMapping; import io.ebeaninternal.xmlmapping.model.XmColumnMapping; @@ -139,6 +141,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private final MultiValueBind multiValueBind; + private final TypeManager typeManager; + private int entityBeanCount; private final boolean updateChangesOnly; @@ -222,6 +226,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { this.dbIdentity = config.getDatabasePlatform().getDbIdentity(); this.deplyInherit = config.getDeployInherit(); this.deployUtil = config.getDeployUtil(); + this.typeManager = deployUtil.getTypeManager(); this.beanManagerFactory = new BeanManagerFactory(config.getDatabasePlatform()); @@ -260,6 +265,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } + @Override + public ScalarType getScalarType(int jdbcType) { + return typeManager.getScalarType(jdbcType); + } + /** * Return the AsOfViewSuffix based on the DbHistorySupport. */ @@ -1463,7 +1473,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { prop.setGetter(beanPropertyAccess.getGetter(propertyIndex)); prop.setSetter(beanPropertyAccess.getSetter(propertyIndex)); if (prop.isAggregation()) { - prop.setAggregationPrefix(DetermineAggPath.manyPath(prop.getAggregation(), desc)); + prop.setAggregationPrefix(DetermineAggPath.manyPath(prop.getRawAggregation(), desc)); } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java index 2cb357a2e..9d8387565 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java @@ -6,6 +6,7 @@ import io.ebean.config.ServerConfig; import io.ebeaninternal.server.cache.SpiCacheManager; import io.ebeaninternal.server.deploy.id.IdBinder; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.type.ScalarType; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; /** @@ -60,4 +61,9 @@ public interface BeanDescriptorMap { * Create a doc store specific adapter for this bean type. */ DocStoreBeanAdapter createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor deploy); + + /** + * Return the scalarType for the given JDBC type. + */ + ScalarType getScalarType(int jdbcType); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 05e69add2..85f66e177 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -24,6 +24,7 @@ import io.ebeaninternal.server.properties.BeanPropertyGetter; import io.ebeaninternal.server.properties.BeanPropertySetter; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; +import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.DataBind; @@ -55,7 +56,7 @@ import java.util.Set; * Description of a property of a bean. Includes its deployment information such * as database column mapping information. */ -public class BeanProperty implements ElPropertyValue, Property { +public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty { private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class); @@ -321,7 +322,7 @@ public class BeanProperty implements ElPropertyValue, Property { this.dbColumn = tableAliasIntern(descriptor, deploy.getDbColumn(), false, null); this.dbComment = deploy.getDbComment(); - this.aggregation = deploy.getAggregation(); + this.aggregation = deploy.parseAggregation(); this.sqlFormulaJoin = InternString.intern(deploy.getSqlFormulaJoin()); this.sqlFormulaSelect = InternString.intern(deploy.getSqlFormulaSelect()); this.formula = sqlFormulaSelect != null; @@ -575,8 +576,7 @@ public class BeanProperty implements ElPropertyValue, Property { public void appendSelect(DbSqlContext ctx, boolean subQuery) { if (aggregation != null) { - ctx.appendRawColumn(aggregation); - + ctx.appendFormulaSelect(aggregation); } else if (formula) { ctx.appendFormulaSelect(sqlFormulaSelect); diff --git a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java index ff5402dbc..5b7e335f0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java @@ -64,6 +64,11 @@ public interface DbSqlContext { */ void appendColumn(String column); + /** + * Parse and add formula with standard table alias replacement. + */ + void appendParseSelect(String parseSelect); + /** * Append a Sql Formula select. This converts the "${ta}" keyword to the * current table alias. diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index ff693b1ec..9d01766fa 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -27,6 +27,8 @@ public abstract class DeployParser { */ protected static final char PERIOD = '.'; + protected static final char OPEN_BRACKET = '('; + protected boolean encrypted; protected String source; @@ -43,6 +45,8 @@ public abstract class DeployParser { protected char wordTerminator; + private StringBuilder wordBuffer; + protected abstract String convertWord(); public abstract String getDeployWord(String expression); @@ -77,7 +81,9 @@ public abstract class DeployParser { priorWord = deployWord; } if (pos < sourceLength) { - sb.append(wordTerminator); + if (wordTerminator != OPEN_BRACKET) { + sb.append(wordTerminator); + } if (wordTerminator == SINGLE_QUOTE) { readLiteral(); } @@ -97,7 +103,7 @@ public abstract class DeployParser { return false; } - StringBuilder wordBuffer = new StringBuilder(); + wordBuffer = new StringBuilder(); wordBuffer.append(source.charAt(pos)); while (++pos < sourceLength) { char ch = source.charAt(pos); @@ -172,6 +178,11 @@ public abstract class DeployParser { * return true if the char is a letter, digit or underscore. */ private boolean isWordPart(char ch) { + if (ch == OPEN_BRACKET) { + // include in the 'word' such that "count(" formula doesn't clash with property "count" + wordBuffer.append(ch); + return false; + } return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD; } diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java index 415ffd9d0..fc8aaadab 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParserMap.java @@ -7,7 +7,7 @@ import java.util.Set; /** * Converts logical property names to database columns using a Map. */ -public final class DeployPropertyParserMap extends DeployParser { +public class DeployPropertyParserMap extends DeployParser { private final Map map; diff --git a/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java b/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java index 83608456b..fff0a1438 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DetermineAggPath.java @@ -12,6 +12,10 @@ class DetermineAggPath { */ static String manyPath(String aggregation, DeployBeanDescriptor desc) { DetermineAggPath.Path path = paths(aggregation); + if (path.length() == 1) { + // a top level aggregation (so here we need to exclude Id property) + return null; + } return path.getManyPath(0, desc); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java new file mode 100644 index 000000000..e7f55721e --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java @@ -0,0 +1,52 @@ +package io.ebeaninternal.server.deploy; + +import io.ebeaninternal.server.query.SqlBeanLoad; +import io.ebeaninternal.server.type.ScalarType; + +import javax.persistence.PersistenceException; + +/** + * Dynamic property based on aggregation (max, min, avg, count). + */ +class DynamicPropertyAggregationFormula extends DynamicPropertyBase { + + private final String parsedAggregation; + + private final BeanProperty asTarget; + + DynamicPropertyAggregationFormula(String name, ScalarType scalarType, String parsedAggregation, BeanProperty asTarget) { + super(name, name, null, scalarType); + this.parsedAggregation = parsedAggregation; + this.asTarget = asTarget; + } + + @Override + public String toString() { + return "DynamicPropertyFormula[" + parsedAggregation + "]"; + } + + @Override + public boolean isAggregation() { + return true; + } + + @Override + public void load(SqlBeanLoad sqlBeanLoad) { + + try { + Object value = scalarType.read(sqlBeanLoad.ctx().getDataReader()); + if (asTarget != null) { + sqlBeanLoad.load(asTarget, value); + } + + } catch (Exception e) { + throw new PersistenceException("Error loading on " + fullName, e); + } + } + + @Override + public void appendSelect(DbSqlContext ctx, boolean subQuery) { + ctx.appendParseSelect(parsedAggregation); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java new file mode 100644 index 000000000..e0fae9d19 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java @@ -0,0 +1,70 @@ +package io.ebeaninternal.server.deploy; + +import io.ebeaninternal.server.query.SqlJoinType; +import io.ebeaninternal.server.query.SqlTreeProperty; +import io.ebeaninternal.server.type.ScalarType; + +import java.util.List; + +/** + * Abstract base for dynamic properties. + */ +abstract class DynamicPropertyBase implements SqlTreeProperty { + + final String name; + final String fullName; + final String elPrefix; + final ScalarType scalarType; + + public DynamicPropertyBase(String name, String fullName, String elPrefix, ScalarType scalarType) { + this.name = name; + this.fullName = fullName; + this.elPrefix = elPrefix; + this.scalarType = scalarType; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getFullBeanName() { + return fullName; + } + + @Override + public boolean isId() { + return false; + } + + @Override + public boolean isEmbedded() { + return false; + } + + @Override + public String getElPrefix() { + return elPrefix; + } + + @Override + public ScalarType getScalarType() { + return scalarType; + } + + @Override + public void buildRawSqlSelectChain(String prefix, List selectChain) { + // do nothing, only for RawSql + } + + @Override + public void loadIgnore(DbReadContext ctx) { + scalarType.loadIgnore(ctx.getDataReader()); + } + + @Override + public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { + // do not add to from usually + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java new file mode 100644 index 000000000..bb350f536 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -0,0 +1,89 @@ +package io.ebeaninternal.server.deploy; + +import io.ebeaninternal.server.query.SqlTreeProperty; +import io.ebeaninternal.server.type.ScalarType; + +import java.sql.Types; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +class FormulaPropertyPath { + + private static final Pattern pattern = Pattern.compile("(max|min|avg|count)\\((.*)\\)"); + + private static final String DISTINCT_ = "distinct "; + + private final String aggType; + + private final String baseName; + + private boolean countDistinct; + + FormulaPropertyPath(String propName) { + + Matcher matcher = pattern.matcher(propName); + if (matcher.find()) { + aggType = matcher.group(1); + baseName = trimDistinct(matcher.group(2)); + + } else { + aggType = null; + baseName = null; + } + } + + private String trimDistinct(String propertyName) { + if (propertyName.startsWith(DISTINCT_)){ + countDistinct = true; + return propertyName.substring(DISTINCT_.length()); + } else { + return propertyName; + } + } + + boolean isFormula() { + return aggType != null; + } + + String aggType() { + return aggType; + } + + String basePropertyName() { + return baseName; + } + + /** + * Create a bean property dynamically for the formula in the select clause. + */ + SqlTreeProperty formulaProperty(BeanProperty base) { + + String parsedAggregation = buildFormula(base); + String name = logicalName(); + + ScalarType scalarType = base.getScalarType(); + if (isCount()) { + // count maps to Long / BIGINT + scalarType = base.getBeanDescriptor().getScalarType(Types.BIGINT); + } + + return new DynamicPropertyAggregationFormula(name, scalarType, parsedAggregation, null); + } + + private String buildFormula(BeanProperty base) { + if (countDistinct) { + return "count(distinct ${}"+base.getDbColumn()+")"; + } else { + return aggType+"(${}"+base.getDbColumn()+")"; + } + } + + private boolean isCount() { + return aggType.equals("count"); + } + + private String logicalName() { + return aggType+Character.toUpperCase(baseName.charAt(0))+baseName.substring(1); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index cfd837967..1df0d8ffd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -25,6 +25,7 @@ import io.ebeaninternal.server.deploy.ChainedBeanPersistListener; import io.ebeaninternal.server.deploy.ChainedBeanPostConstructListener; import io.ebeaninternal.server.deploy.ChainedBeanPostLoad; import io.ebeaninternal.server.deploy.ChainedBeanQueryAdapter; +import io.ebeaninternal.server.deploy.DeployPropertyParserMap; import io.ebeaninternal.server.deploy.IndexDefinition; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; @@ -849,18 +850,18 @@ public class DeployBeanDescriptor { this.idGeneratorName = PlatformIdGenerator.AUTO_UUID; switch (serverConfig.getUuidVersion()) { - case VERSION1: - this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile()); - break; + case VERSION1: + this.idGenerator = UuidV1IdGenerator.getInstance(serverConfig.getUuidStateFile()); + break; - case VERSION1RND: - this.idGenerator = UuidV1RndIdGenerator.INSTANCE; - break; + case VERSION1RND: + this.idGenerator = UuidV1RndIdGenerator.INSTANCE; + break; - case VERSION4: - default: - this.idGenerator = UuidV4IdGenerator.INSTANCE; - break; + case VERSION4: + default: + this.idGenerator = UuidV4IdGenerator.INSTANCE; + break; } } @@ -1168,4 +1169,38 @@ public class DeployBeanDescriptor { } namedRawSql.put(name, rawSql); } + + /** + * Parse the aggregation formula into expressions with table alias placeholders. + */ + public String parse(String aggregation) { + return new Parser(this).parse(aggregation); + } + + /** + * Parser for top level properties into EL expressions (table alias placeholders). + */ + private static class Parser extends DeployPropertyParserMap { + + private final DeployBeanDescriptor descriptor; + + Parser(DeployBeanDescriptor descriptor) { + super(null); + this.descriptor = descriptor; + } + + public String getDeployWord(String expression) { + return descriptor.getDeployWord(expression); + } + } + + private String getDeployWord(String expression) { + if (expression.charAt(expression.length() - 1) == '(') { + return null; + } + // use 'current' table alias - refer BeanProperty appendSelect() for aggregation + DeployBeanProperty property = propMap.get(expression); + return (property == null) ? null : "${ta}." + property.getDbColumn(); + } + } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 5e2cfa517..a363fdbdd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -175,6 +175,7 @@ public class DeployBeanProperty { private String aggregationPrefix; private String aggregation; + private String aggregationParsed; private String sqlFormulaSelect; private String sqlFormulaJoin; @@ -615,10 +616,23 @@ public class DeployBeanProperty { return aggregation != null; } - public String getAggregation() { + /** + * Get the raw/logical aggregation formula. + */ + public String getRawAggregation() { return aggregation; } + /** + * Get the parsed aggregation formula with table alias placeholders. + */ + public String parseAggregation() { + if (aggregation != null) { + aggregationParsed = desc.parse(aggregation); + } + return aggregationParsed; + } + public void setAggregation(String aggregation) { this.aggregation = aggregation; this.dbRead = true; @@ -629,9 +643,9 @@ public class DeployBeanProperty { /** * Set the path to the aggregation. */ - public void setAggregationPrefix(String aggregationPrefix) { - this.aggregationPrefix = aggregationPrefix; - this.aggregation = aggregation.replace(aggregationPrefix, "u1"); + public void setAggregationPrefix(String prefix) { + this.aggregationPrefix = prefix; + this.aggregation = (prefix == null) ? aggregation : aggregation.replace(aggregationPrefix, "u1"); } public String getElPrefix() { @@ -644,7 +658,7 @@ public class DeployBeanProperty { public String getElPlaceHolder() { if (aggregation != null) { - return aggregation; + return aggregationParsed; } else if (sqlFormulaSelect != null) { return sqlFormulaSelect; } else { diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index a2138104b..dfb611e14 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -273,13 +273,19 @@ class DefaultDbSqlContext implements DbSqlContext { sb.append(" "); } + @Override + public void appendParseSelect(String parseSelect) { + String converted = alias.parse(parseSelect); + sb.append(COMMA); + sb.append(converted); + appendColumnAlias(); + } + @Override public void appendFormulaSelect(String sqlFormulaSelect) { String tableAlias = tableAliasStack.peek(); - String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder, - tableAlias); - + String converted = StringHelper.replaceString(sqlFormulaSelect, tableAliasPlaceHolder, tableAlias); sb.append(COMMA); sb.append(converted); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlBeanLoad.java b/src/main/java/io/ebeaninternal/server/query/SqlBeanLoad.java index fc851f006..b5855576d 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlBeanLoad.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlBeanLoad.java @@ -44,6 +44,13 @@ public class SqlBeanLoad { return lazyLoading; } + /** + * Return the DB read context. + */ + public DbReadContext ctx() { + return ctx; + } + /** * Increment the resultSet index 1. */ @@ -86,4 +93,14 @@ public class SqlBeanLoad { } } + /** + * Load the given value into the property. + */ + public void load(BeanProperty target, Object dbVal) { + if (!refreshLoading) { + target.setValue(bean, dbVal); + } else { + target.setValueIntercept(bean, dbVal); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 5a26fcc5d..1c572cf91 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -418,7 +418,7 @@ public final class SqlTreeBuilder { // make sure we only included the base/embedded bean once if (!selectProps.containsProperty(baseName)) { - BeanProperty p = desc.findBeanProperty(baseName); + SqlTreeProperty p = desc.findSqlTreeProperty(baseName); if (p == null) { logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it."); @@ -436,7 +436,7 @@ public final class SqlTreeBuilder { } else { // find the property including searching the // sub class hierarchy if required - BeanProperty p = desc.findBeanProperty(propName); + SqlTreeProperty p = desc.findSqlTreeProperty(propName); if (p == null) { logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it."); p = desc.findBeanProperty("id"); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 3d16f8ff2..806e64adb 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -48,7 +48,7 @@ class SqlTreeNodeBean implements SqlTreeNode { */ private final boolean partialObject; - protected final BeanProperty[] properties; + protected final SqlTreeProperty[] properties; /** * Extra where clause added by Where annotation on associated many. @@ -87,6 +87,7 @@ class SqlTreeNodeBean implements SqlTreeNode { private boolean intersectionAsOfTableAlias; private final boolean aggregation; + private final boolean aggregationRoot; /** * Construct for leaf node. @@ -124,13 +125,15 @@ class SqlTreeNodeBean implements SqlTreeNode { this.nodeBeanProp = beanProp; this.extraWhere = (beanProp == null) ? null : beanProp.getExtraWhere(); + this.aggregation = props.isAggregation(); + this.aggregationRoot = props.isAggregationRoot(); + // the bean has an Id property and we want to use it - this.readId = withId && (desc.getIdProperty() != null); + this.readId = !aggregationRoot && withId && (desc.getIdProperty() != null); this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions; this.partialObject = props.isPartialObject(); this.properties = props.getProps(); - this.aggregation = props.isAggregation(); this.children = myChildren == null ? NO_CHILDREN : myChildren.toArray(new SqlTreeNode[myChildren.size()]); pathMap = createPathMap(prefix, desc); @@ -186,7 +189,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } idBinder.buildRawSqlSelectChain(prefix, selectChain); } - for (BeanProperty property : properties) { + for (SqlTreeProperty property : properties) { property.buildRawSqlSelectChain(prefix, selectChain); } // recursively continue reading... @@ -289,14 +292,14 @@ class SqlTreeNodeBean implements SqlTreeNode { if (inheritInfo == null) { // normal behavior with no inheritance - for (BeanProperty property : properties) { + for (SqlTreeProperty property : properties) { property.load(sqlBeanLoad); } } else { // take account of inheritance and due to subclassing approach // need to get a 'local' version of the property - for (BeanProperty property : properties) { + for (SqlTreeProperty property : properties) { // get a local version of the BeanProperty BeanProperty p = localDesc.getBeanProperty(property.getName()); if (p != null) { @@ -416,7 +419,7 @@ class SqlTreeNodeBean implements SqlTreeNode { if (readId) { appendSelectId(ctx, idBinder.getBeanProperty()); } - for (BeanProperty property : properties) { + for (SqlTreeProperty property : properties) { if (!property.isAggregation()) { property.appendSelect(ctx, subQuery); } @@ -483,9 +486,9 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * Append the properties to the buffer. */ - private void appendSelect(DbSqlContext ctx, boolean subQuery, BeanProperty[] props) { + private void appendSelect(DbSqlContext ctx, boolean subQuery, SqlTreeProperty[] props) { - for (BeanProperty prop : props) { + for (SqlTreeProperty prop : props) { prop.appendSelect(ctx, subQuery); } } @@ -543,7 +546,7 @@ class SqlTreeNodeBean implements SqlTreeNode { // join and return SqlJoinType to use for child joins joinType = appendFromBaseTable(ctx, joinType); - for (BeanProperty property : properties) { + for (SqlTreeProperty property : properties) { // usually nothing... except for 1-1 Exported property.appendFrom(ctx, joinType); } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java index 9c762b7b8..9c717173e 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java @@ -1,7 +1,6 @@ package io.ebeaninternal.server.query; import io.ebeaninternal.api.ManyWhereJoins; -import io.ebeaninternal.server.deploy.BeanProperty; import java.util.ArrayList; import java.util.Arrays; @@ -21,7 +20,7 @@ public class SqlTreeProperties { /** * The bean properties in order. */ - private final List propsList = new ArrayList<>(); + private final List propsList = new ArrayList<>(); /** * Maintain a list of property names to detect embedded bean additions. @@ -32,6 +31,8 @@ public class SqlTreeProperties { private boolean aggregation; + private String aggregationPath; + SqlTreeProperties() { } @@ -39,17 +40,17 @@ public class SqlTreeProperties { return propNames.contains(propName); } - public void add(BeanProperty[] props) { + public void add(SqlTreeProperty[] props) { propsList.addAll(Arrays.asList(props)); } - public void add(BeanProperty prop) { + public void add(SqlTreeProperty prop) { propsList.add(prop); propNames.add(prop.getName()); } - public BeanProperty[] getProps() { - return propsList.toArray(new BeanProperty[propsList.size()]); + public SqlTreeProperty[] getProps() { + return propsList.toArray(new SqlTreeProperty[propsList.size()]); } boolean isPartialObject() { @@ -77,7 +78,6 @@ public class SqlTreeProperties { boolean requireSqlDistinct(ManyWhereJoins manyWhereJoins) { String joinProperty = aggregationJoin(); if (joinProperty != null) { - aggregation = true; manyWhereJoins.addAggregationJoin(joinProperty); return false; } else { @@ -97,12 +97,21 @@ public class SqlTreeProperties { */ private String aggregationJoin() { if (!allProperties) { - for (BeanProperty beanProperty : propsList) { + for (SqlTreeProperty beanProperty : propsList) { if (beanProperty.isAggregation()) { - return beanProperty.getElPrefix(); + aggregation = true; + aggregationPath = beanProperty.getElPrefix(); + return aggregationPath; } } } return null; } + + /** + * Return true if a top level aggregation which means the Id property must be excluded. + */ + public boolean isAggregationRoot() { + return aggregation && (aggregationPath == null); + } } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java new file mode 100644 index 000000000..2543cc825 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java @@ -0,0 +1,76 @@ +package io.ebeaninternal.server.query; + +import io.ebeaninternal.server.deploy.DbReadContext; +import io.ebeaninternal.server.deploy.DbSqlContext; +import io.ebeaninternal.server.type.ScalarType; + +import java.util.List; + +/** + * A property in the SQL Tree. + * + * A BeanProperty or a dynamically created property based on formula. + */ +public interface SqlTreeProperty { + + /** + * Return the property name. + */ + String getName(); + + /** + * Return the full property name (for error messages). + */ + String getFullBeanName(); + + /** + * Return true if the property is the Id. + */ + boolean isId(); + + /** + * Return true if the property is an embedded type. + */ + boolean isEmbedded(); + + /** + * Return true if the property is an aggregation. + */ + boolean isAggregation(); + + /** + * Return the Expression language prefix (join path). + */ + String getElPrefix(); + + /** + * Return the underlying scalar type for the property (for findSingleAttribute). + */ + ScalarType getScalarType(); + + /** + * For RawSql build the select chain. + */ + void buildRawSqlSelectChain(String prefix, List selectChain); + + /** + * Load into the bean (from the DataReader/ResultSet). + */ + void load(SqlBeanLoad sqlBeanLoad); + + /** + * Ignore the property (moving the column index position without reading). + */ + void loadIgnore(DbReadContext ctx); + + /** + * Append to the select clause. + */ + void appendSelect(DbSqlContext ctx, boolean subQuery); + + /** + * Append to the from clause. + */ + void appendFrom(DbSqlContext ctx, SqlJoinType joinType); + +} diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java new file mode 100644 index 000000000..c3d840603 --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java @@ -0,0 +1,35 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.BaseTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FormulaPropertyPathTest extends BaseTestCase { + + //private BeanDescriptor customerDesc = getBeanDescriptor(Customer.class); + + @Test + public void isFormula() { + + assertFormula("max(foo)", "max", "foo"); + assertFormula("min(bar)", "min", "bar"); + assertFormula("avg(baz)", "avg", "baz"); + } + + @Test + public void isFormula_count() { + assertFormula("count(moo)", "count", "moo"); + assertFormula("count(distinct joo)", "count", "joo"); + } + + private void assertFormula(String input, String aggType, String baseProperty) { + + FormulaPropertyPath propertyPath = new FormulaPropertyPath(input); + + assertThat(propertyPath.isFormula()).isTrue(); + assertThat(propertyPath.basePropertyName()).isEqualTo(baseProperty); + assertThat(propertyPath.aggType()).isEqualTo(aggType); + + } +} diff --git a/src/test/java/org/tests/model/tevent/TEventOne.java b/src/test/java/org/tests/model/tevent/TEventOne.java index c5b1dbb01..88bc2e2fd 100644 --- a/src/test/java/org/tests/model/tevent/TEventOne.java +++ b/src/test/java/org/tests/model/tevent/TEventOne.java @@ -13,17 +13,27 @@ import java.util.List; @Entity public class TEventOne { + public enum Status { + AA, + BB + } + @Id Long id; String name; + Status status; + @Version Long version; @OneToOne TEvent event; + @Aggregation("max(version)") + Long maxVersion; + @Aggregation("count(logs.id)") Long count; @@ -36,8 +46,14 @@ public class TEventOne { @OneToMany(mappedBy = "event", cascade = CascadeType.ALL) List logs; - public TEventOne(String name) { + public TEventOne(String name, Status status) { this.name = name; + this.status = status; + } + + @Override + public String toString() { + return "id:" + id + " name:" + name + " status:" + status + " mv:" + maxVersion + " ct:" + count; } public Long getId() { @@ -60,10 +76,18 @@ public class TEventOne { return totalAmount; } + public Long getMaxVersion() { + return maxVersion; + } + public String getName() { return name; } + public Status getStatus() { + return status; + } + public void setName(String name) { this.name = name; } diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index abd586eb9..34c231b26 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -3,11 +3,18 @@ package org.tests.query.aggregation; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import org.assertj.core.api.Assertions; +import org.ebeantest.LoggedSqlCollector; import org.junit.BeforeClass; import org.junit.Test; +import org.tests.model.basic.Contact; +import org.tests.model.basic.Order; +import org.tests.model.basic.OrderDetail; +import org.tests.model.basic.ResetBasicData; import org.tests.model.tevent.TEventMany; import org.tests.model.tevent.TEventOne; +import java.sql.Timestamp; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -16,17 +23,23 @@ public class TestAggregationCount extends BaseTestCase { @BeforeClass public static void setup() { - TEventOne one = new TEventOne("first"); + TEventOne one = new TEventOne("first", TEventOne.Status.AA); one.getLogs().add(new TEventMany("all", 1, 10)); one.getLogs().add(new TEventMany("be", 2, 12.2)); one.getLogs().add(new TEventMany("add", 3, 13)); Ebean.save(one); - TEventOne two = new TEventOne("second"); + TEventOne two = new TEventOne("second", TEventOne.Status.AA); two.getLogs().add(new TEventMany("at", 10, 10)); two.getLogs().add(new TEventMany("add", 30, 13)); two.getLogs().add(new TEventMany("alf", 30, 13)); Ebean.save(two); + + TEventOne three = new TEventOne("thrird", TEventOne.Status.BB); + Ebean.save(three); + three.setName("third"); + Ebean.save(three); + } @Test @@ -36,7 +49,7 @@ public class TestAggregationCount extends BaseTestCase { List list = query.findList(); String sql = sqlOf(query, 5); - assertThat(sql).contains("select t0.id, t0.name, t0.version, t0.event_id from tevent_one t0"); + assertThat(sql).contains("select t0.id, t0.name, t0.status, t0.version, t0.event_id from tevent_one t0"); for (TEventOne eventOne : list) { // lazy loading on Aggregation properties @@ -172,4 +185,200 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql).contains("select t0.id, t0.name, count(u1.id), t1.id, t1.name from tevent_one t0 left join tevent t1 on t1.id = t0.event_id join tevent_many u1 on u1.event_id = t0.id "); assertThat(sql).contains("group by t0.id, t0.name, t1.id, t1.name"); } + + @Test + public void testTopLevelAggregation() { + + Query query0 = Ebean.find(TEventOne.class) + .select("status, maxVersion") + .where().isNotNull("name") + .having().ge("maxVersion", 1) + .query(); + + List list = query0.findList(); + + String sql = sqlOf(query0, 5); + assertThat(sql).contains("select t0.status, max(t0.version) from tevent_one t0"); + assertThat(sql).contains("where t0.name is not null"); + assertThat(sql).contains("group by t0.status"); + assertThat(sql).contains("having max(t0.version) >= ?"); + + + LoggedSqlCollector.start(); + + for (TEventOne eventOne : list) { + assertThat(eventOne.getStatus()).isNotNull(); + assertThat(eventOne.getMaxVersion()).isNotNull(); + + // bean has no Id, so it is not in Persistence Context, nor Load context + assertThat(eventOne.getId()).isNull(); + // ... and it will not invoke lazy loading + assertThat(eventOne.getName()).isNull(); + } + + List lazyLoadSql = LoggedSqlCollector.stop(); + assertThat(lazyLoadSql).isEmpty(); + } + + @Test + public void testDynamicSingleAttributeAggregation() { + + ResetBasicData.reset(); + + Query query0 = Ebean.find(Order.class) + .select("max(updtime)") + .where().eq("status", Order.Status.NEW) + .query(); + + Timestamp maxUpdateTime = query0.findSingleAttribute(); + System.out.println(""+maxUpdateTime); + assertThat(maxUpdateTime).isNotNull(); + + String sql = sqlOf(query0, 5); + assertThat(sql).contains("select max(t0.updtime) from o_order t0"); + + Timestamp maxNotNew = Ebean.find(Order.class) + .select("max(updtime)") + .where().ne("status", Order.Status.NEW) + .findSingleAttribute(); + + assertThat(maxNotNew).isNotNull(); + + } + + @Test + public void testDynamicSingleAttributeAggregation_maxInteger() { + + ResetBasicData.reset(); + + Query query = Ebean.find(OrderDetail.class) + .select("max(orderQty)"); + + Integer maxOrderQty = query.findSingleAttribute(); + System.out.println(""+maxOrderQty); + Assertions.assertThat(maxOrderQty).isGreaterThan(20); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select max(t0.order_qty) from o_order_detail t0"); + } + + @Test + public void testDynamicSingleAttributeAggregation_minInteger() { + + ResetBasicData.reset(); + + Query query = Ebean.find(OrderDetail.class) + .select("min(orderQty)"); + + Integer minOrderQty = query.findSingleAttribute(); + System.out.println(""+minOrderQty); + assertThat(minOrderQty).isLessThan(10); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select min(t0.order_qty) from o_order_detail t0"); + } + + @Test + public void testDynamicSingleAttributeAggregation_maxString() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Contact.class) + .select("max(lastName)"); + + String maxName = query.findSingleAttribute(); + System.out.println(""+maxName); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select max(t0.last_name) from contact t0"); + } + + @Test + public void testDynamicSingleAttributeAggregation_minString() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Contact.class) + .select("min(firstName)"); + + String minName = query.findSingleAttribute(); + System.out.println(""+minName); + assertThat(minName).isNotNull(); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select min(t0.first_name) from contact t0"); + } + + + @Test + public void testDynamicSingleAttributeAggregation_count() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Contact.class) + .select("count(lastName)"); + + Long count = query.findSingleAttribute(); + System.out.println(""+count); + assertThat(count).isNotNull(); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select count(t0.last_name) from contact t0"); + } + + @Test + public void testDynamicSingleAttributeAggregation_countDistinct() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Contact.class) + .select("count(distinct lastName)"); + + Long count = query.findSingleAttribute(); + System.out.println(""+count); + assertThat(count).isNotNull(); + + String sql = sqlOf(query, 5); + assertThat(sql).contains("select count(distinct t0.last_name) from contact t0"); + } + + @Test + public void example() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + String maxLastName = + Ebean.find(Contact.class) + .select("max(lastName)") + .where().isNull("phone") + .findSingleAttribute(); + + assertThat(maxLastName).isNotNull(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select max(t0.last_name) from contact t0"); + } + + @Test + public void example_countDistinct() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + Long count = + Ebean.find(Contact.class) + .select("count(distinct lastName)") + .where().isEmpty("notes") + .findSingleAttribute(); + + System.out.println(""+count); + assertThat(count).isNotNull(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select count(distinct t0.last_name) from contact t0 where not exists (select 1 from contact_note x where x.contact_id = t0.id)"); + } + } diff --git a/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java b/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java index ade6d2a91..ff482a03e 100644 --- a/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java +++ b/src/test/java/org/tests/query/other/TestQuerySingleAttribute.java @@ -99,6 +99,21 @@ public class TestQuerySingleAttribute extends BaseTestCase { assertThat(name).isNotNull(); } + @Test + public void findSingleAttribute_with_aggregate() { + + ResetBasicData.reset(); + + Query query = Ebean.find(Customer.class) + .select("max(name)") + .where().gt("id", 1).query(); + + String name = query.findSingleAttribute(); + + assertThat(sqlOf(query)).contains("select max(t0.name) from o_customer t0"); + assertThat(name).isNotNull(); + } + @Test public void findSingleAttribute_viaExpression() { From 05b8adbf6e7ccf0d6f654dbe15bab09c9a30f97f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 16:37:47 +1300 Subject: [PATCH 0139/1036] No effective change - change test from extends testcase to normal junit --- .../server/rawsql/TestRawSqlColumnParsing.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java index c24d47b6d..b9b5175db 100644 --- a/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java +++ b/src/test/java/io/ebeaninternal/server/rawsql/TestRawSqlColumnParsing.java @@ -2,12 +2,15 @@ package io.ebeaninternal.server.rawsql; import io.ebeaninternal.server.rawsql.SpiRawSql.ColumnMapping; import io.ebeaninternal.server.rawsql.SpiRawSql.ColumnMapping.Column; -import junit.framework.TestCase; +import org.junit.Test; import java.util.Map; -public class TestRawSqlColumnParsing extends TestCase { +import static org.junit.Assert.assertEquals; +public class TestRawSqlColumnParsing { + + @Test public void test_simple() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a,b,c"); @@ -30,6 +33,7 @@ public class TestRawSqlColumnParsing extends TestCase { } + @Test public void test_simpleWithSpacing() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse(" a , b , c "); @@ -52,6 +56,7 @@ public class TestRawSqlColumnParsing extends TestCase { } + @Test public void test_withAlias() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a a0,b b1, c c2 , d d3 , e e4 "); @@ -88,6 +93,7 @@ public class TestRawSqlColumnParsing extends TestCase { } + @Test public void test_withDatabaseFunction() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a a0,b b1, MONTH(MAKEDATE(2015, 241)) m2 , d d3 , e e4 "); @@ -124,6 +130,7 @@ public class TestRawSqlColumnParsing extends TestCase { } + @Test public void test_withAsAlias() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a as a0,'b' b1, \"c(blah)\" as c2 , d as d3 , e as e4 "); @@ -160,6 +167,7 @@ public class TestRawSqlColumnParsing extends TestCase { } + @Test public void test_doubleColon() { ColumnMapping columnMapping = DRawSqlColumnsParser.parse("a,MD5(id::text) as b,c"); From c1c85b67c28c22b17cef8062cdc7a4f8f6c145d3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 17:29:45 +1300 Subject: [PATCH 0140/1036] #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)") --- .../server/core/OrmQueryRequest.java | 2 +- .../server/deploy/BeanDescriptor.java | 17 +--- .../server/deploy/DeployPropertyParser.java | 22 +++++ .../DynamicPropertyAggregationFormula.java | 15 ++-- .../server/deploy/FormulaPropertyPath.java | 85 +++++++++++-------- .../querydefn/OrmQueryPropertiesParser.java | 13 ++- .../server/rawsql/DRawSqlColumnsParser.java | 40 +++------ .../server/util/DSelectColumnsParser.java | 55 ++++++++++++ .../deploy/DeployPropertyParserTest.java | 10 +-- .../deploy/FormulaPropertyPathTest.java | 26 ++++-- .../server/util/DSelectColumnsParserTest.java | 60 +++++++++++++ .../aggregation/TestAggregationCount.java | 21 +++++ 12 files changed, 266 insertions(+), 100 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java create mode 100644 src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 7df2185b3..490e53762 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -222,7 +222,7 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery if (query.isRawSql()) { return new DeployPropertyParserMap(query.getRawSql().getColumnMapping().getMapping()); } else { - return beanDescriptor.createDeployPropertyParser(); + return beanDescriptor.parser(); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 2552d2600..41ba76d32 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1582,7 +1582,7 @@ public class BeanDescriptor implements BeanType { } } - public DeployPropertyParser createDeployPropertyParser() { + public DeployPropertyParser parser() { return new DeployPropertyParser(this); } @@ -2453,18 +2453,7 @@ public class BeanDescriptor implements BeanType { */ private SqlTreeProperty findSqlTreeFormula(String formulaExpression) { - return dynamicProperty.computeIfAbsent(formulaExpression, (formula) -> { - FormulaPropertyPath propertyFormula = new FormulaPropertyPath(formula); - if (!propertyFormula.isFormula()) { - throw new IllegalStateException("unable to parse formula [" + formula + "} on bean type " + fullName); - } - String baseName = propertyFormula.basePropertyName(); - BeanProperty base = _findBeanProperty(baseName); - if (base == null) { - throw new IllegalStateException("unable to find property [" + baseName + "] from formula [" + formula + "} on bean type " + fullName); - } - return propertyFormula.formulaProperty(base); - }); + return dynamicProperty.computeIfAbsent(formulaExpression, (formula) -> new FormulaPropertyPath(this, formula).build()); } /** @@ -2497,7 +2486,7 @@ public class BeanDescriptor implements BeanType { return _findBeanProperty(propName); } - private BeanProperty _findBeanProperty(String propName) { + BeanProperty _findBeanProperty(String propName) { BeanProperty prop = propMap.get(propName); if (prop == null && inheritInfo != null) { // search in sub types... diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java index 320d76a96..bf98172a2 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployPropertyParser.java @@ -22,10 +22,29 @@ public final class DeployPropertyParser extends DeployParser { private final Set includes = new HashSet<>(); + private boolean catchFirst; + + private ElPropertyDeploy firstProp; + DeployPropertyParser(BeanDescriptor beanDescriptor) { this.beanDescriptor = beanDescriptor; } + /** + * Set to true to catch the first property. + */ + public DeployPropertyParser setCatchFirst(boolean catchFirst) { + this.catchFirst = catchFirst; + return this; + } + + /** + * Return the first property found by the parser. + */ + public ElPropertyDeploy getFirstProp() { + return firstProp; + } + @Override public Set getIncludes() { return includes; @@ -45,6 +64,9 @@ public final class DeployPropertyParser extends DeployParser { if (elProp == null) { return null; } else { + if (catchFirst && firstProp == null) { + firstProp = elProp; + } addIncludes(elProp.getElPrefix()); return elProp.getElPlaceholder(encrypted); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java index e7f55721e..28f494bd4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java @@ -10,24 +10,27 @@ import javax.persistence.PersistenceException; */ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { - private final String parsedAggregation; + private final String parsedFormula; + + private final boolean aggregate; private final BeanProperty asTarget; - DynamicPropertyAggregationFormula(String name, ScalarType scalarType, String parsedAggregation, BeanProperty asTarget) { + DynamicPropertyAggregationFormula(String name, ScalarType scalarType, String parsedFormula, boolean aggregate, BeanProperty asTarget) { super(name, name, null, scalarType); - this.parsedAggregation = parsedAggregation; + this.parsedFormula = parsedFormula; + this.aggregate = aggregate; this.asTarget = asTarget; } @Override public String toString() { - return "DynamicPropertyFormula[" + parsedAggregation + "]"; + return "DynamicPropertyFormula[" + parsedFormula + "]"; } @Override public boolean isAggregation() { - return true; + return aggregate; } @Override @@ -46,7 +49,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { @Override public void appendSelect(DbSqlContext ctx, boolean subQuery) { - ctx.appendParseSelect(parsedAggregation); + ctx.appendParseSelect(parsedFormula); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index bb350f536..b4c82f790 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.deploy; +import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.type.ScalarType; @@ -9,27 +10,34 @@ import java.util.regex.Pattern; class FormulaPropertyPath { - private static final Pattern pattern = Pattern.compile("(max|min|avg|count)\\((.*)\\)"); + private static final String[] AGG_FUNCTIONS = {"count","max","min","avg"}; + + private static final Pattern pattern = Pattern.compile("([a-zA-Z]*)\\((.*)\\)"); private static final String DISTINCT_ = "distinct "; - private final String aggType; + private final BeanDescriptor descriptor; - private final String baseName; + private final String formula; + + private final String outerFunction; + + private final String internalExpression; private boolean countDistinct; - FormulaPropertyPath(String propName) { + FormulaPropertyPath(BeanDescriptor descriptor, String formula) { - Matcher matcher = pattern.matcher(propName); - if (matcher.find()) { - aggType = matcher.group(1); - baseName = trimDistinct(matcher.group(2)); + this.descriptor = descriptor; + this.formula = formula; - } else { - aggType = null; - baseName = null; + Matcher matcher = pattern.matcher(formula); + if (!matcher.find()) { + throw new IllegalStateException("Unable to parse formula [" + formula + "]"); } + //int groupCount = matcher.groupCount(); + outerFunction = matcher.group(1); + internalExpression = trimDistinct(matcher.group(2)); } private String trimDistinct(String propertyName) { @@ -41,49 +49,58 @@ class FormulaPropertyPath { } } - boolean isFormula() { - return aggType != null; - } - String aggType() { - return aggType; + return outerFunction; } String basePropertyName() { - return baseName; + return internalExpression; } - /** - * Create a bean property dynamically for the formula in the select clause. - */ - SqlTreeProperty formulaProperty(BeanProperty base) { - String parsedAggregation = buildFormula(base); - String name = logicalName(); + SqlTreeProperty build() { - ScalarType scalarType = base.getScalarType(); + DeployPropertyParser parser = descriptor.parser().setCatchFirst(true); + + String parsed = parser.parse(internalExpression); + ElPropertyDeploy firstProp = parser.getFirstProp(); + + ScalarType scalarType; if (isCount()) { // count maps to Long / BIGINT - scalarType = base.getBeanDescriptor().getScalarType(Types.BIGINT); + scalarType = descriptor.getScalarType(Types.BIGINT); + } else { + // determine scalarType based on first property found by parser + if (firstProp != null) { + scalarType = firstProp.getBeanProperty().getScalarType(); + } else { + throw new IllegalStateException("unable to determine scalarType of formula [" + formula + "] for type " + descriptor+" - maybe use a cast like ::String ?"); + } } - return new DynamicPropertyAggregationFormula(name, scalarType, parsedAggregation, null); + String parsedAggregation = buildFormula(parsed); + return new DynamicPropertyAggregationFormula(formula, scalarType, parsedAggregation, isAggregate(),null); } - private String buildFormula(BeanProperty base) { + private boolean isAggregate() { + for (String aggFunction : AGG_FUNCTIONS) { + if (aggFunction.equals(outerFunction)) { + return true; + } + } + return false; + } + + private String buildFormula(String parsed) { if (countDistinct) { - return "count(distinct ${}"+base.getDbColumn()+")"; + return "count(distinct "+parsed+")"; } else { - return aggType+"(${}"+base.getDbColumn()+")"; + return outerFunction +"("+parsed+")"; } } private boolean isCount() { - return aggType.equals("count"); - } - - private String logicalName() { - return aggType+Character.toUpperCase(baseName.charAt(0))+baseName.substring(1); + return outerFunction.equals("count"); } } diff --git a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java index 9b774c9bc..1baa3409a 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPropertiesParser.java @@ -2,8 +2,10 @@ package io.ebeaninternal.server.querydefn; import io.ebean.FetchConfig; import io.ebean.util.StringHelper; +import io.ebeaninternal.server.util.DSelectColumnsParser; import java.util.LinkedHashSet; +import java.util.List; /** * Parses the path properties string. @@ -113,10 +115,10 @@ class OrmQueryPropertiesParser { return null; } - String[] res = inputProperties.split(","); + List res = splitRawSelect(inputProperties); StringBuilder sb = new StringBuilder(70); - LinkedHashSet propertySet = new LinkedHashSet<>(res.length * 2); + LinkedHashSet propertySet = new LinkedHashSet<>(res.size() * 2); int count = 0; String temp; @@ -148,6 +150,13 @@ class OrmQueryPropertiesParser { return propertySet; } + /** + * Split allowing 'dynamic function based properties'. + */ + private List splitRawSelect(String inputProperties) { + return DSelectColumnsParser.parse(inputProperties); + } + private int parseBatchHint(int pos, String option) { int startPos = pos + option.length(); diff --git a/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java b/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java index 6e17ed5a9..92e3e1078 100644 --- a/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java +++ b/src/main/java/io/ebeaninternal/server/rawsql/DRawSqlColumnsParser.java @@ -1,10 +1,12 @@ package io.ebeaninternal.server.rawsql; import io.ebeaninternal.server.rawsql.SpiRawSql.ColumnMapping; +import io.ebeaninternal.server.util.DSelectColumnsParser; -import java.util.regex.Pattern; import javax.persistence.PersistenceException; import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; /** * Parses columnMapping (select clause) mapping columns to bean properties. @@ -13,12 +15,8 @@ final class DRawSqlColumnsParser { private static final Pattern COLINFO_SPLIT = Pattern.compile("\\s(?=[^\\)]*(?:\\(|$))"); - private final int end; - private final String sqlSelect; - private int pos; - private int indexPos; public static ColumnMapping parse(String sqlSelect) { @@ -27,25 +25,21 @@ final class DRawSqlColumnsParser { private DRawSqlColumnsParser(String sqlSelect) { this.sqlSelect = sqlSelect; - this.end = sqlSelect.length(); } private ColumnMapping parse() { - ArrayList columns = new ArrayList<>(); - while (pos <= end) { - ColumnMapping.Column c = nextColumnInfo(); - columns.add(c); - } + List columnList = DSelectColumnsParser.parse(sqlSelect); + List columns = new ArrayList<>(columnList.size()); + + for (String rawColumn : columnList) { + columns.add(parseColumn(rawColumn)); + } return new ColumnMapping(columns); } - private ColumnMapping.Column nextColumnInfo() { - int start = pos; - nextComma(); - String colInfo = sqlSelect.substring(start, pos++); - colInfo = colInfo.trim(); + private ColumnMapping.Column parseColumn(String colInfo) { String[] split = COLINFO_SPLIT.split(colInfo); if (split.length > 1) { @@ -82,18 +76,4 @@ final class DRawSqlColumnsParser { return new ColumnMapping.Column(indexPos++, sb.toString(), split[split.length - 1]); } - private void nextComma() { - boolean inQuote = false; - int inbrackets = 0; - while (pos < end) { - char c = sqlSelect.charAt(pos); - if (c == '\'') inQuote = !inQuote; - else if (c == '(') inbrackets++; - else if (c == ')') inbrackets--; - else if (!inQuote && inbrackets == 0 && c == ',') { - return; - } - pos++; - } - } } diff --git a/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java b/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java new file mode 100644 index 000000000..c172f92b2 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/util/DSelectColumnsParser.java @@ -0,0 +1,55 @@ +package io.ebeaninternal.server.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * Splits a select clause into 'logical columns' taking into account functions and quotes. + */ +public final class DSelectColumnsParser { + + private final int end; + + private final String selectClause; + + private int pos; + + public static List parse(String sqlSelect) { + return new DSelectColumnsParser(sqlSelect).parse(); + } + + private DSelectColumnsParser(String selectClause) { + this.selectClause = selectClause; + this.end = selectClause.length(); + } + + private List parse() { + + ArrayList columns = new ArrayList<>(); + while (pos <= end) { + columns.add(nextColumnInfo()); + } + return columns; + } + + private String nextColumnInfo() { + int start = pos; + nextComma(); + return selectClause.substring(start, pos++).trim(); + } + + private void nextComma() { + boolean inQuote = false; + int inBrackets = 0; + while (pos < end) { + char c = selectClause.charAt(pos); + if (c == '\'') inQuote = !inQuote; + else if (c == '(') inBrackets++; + else if (c == ')') inBrackets--; + else if (!inQuote && inBrackets == 0 && c == ',') { + return; + } + pos++; + } + } +} diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index 9c7369a46..10056984e 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -46,7 +46,7 @@ public class DeployPropertyParserTest extends BaseTestCase { @Test public void combined_withAtColumn() { - assertThat(adddressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')"); + assertThat(addressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')"); } @Test @@ -55,11 +55,11 @@ public class DeployPropertyParserTest extends BaseTestCase { } private DeployPropertyParser parser() { - return descriptor.createDeployPropertyParser(); + return descriptor.parser(); } - - private DeployPropertyParser adddressParser() { - return addressBeanDescriptor.createDeployPropertyParser(); + + private DeployPropertyParser addressParser() { + return addressBeanDescriptor.parser(); } } diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java index c3d840603..b990d6077 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java @@ -1,35 +1,45 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; +import io.ebeaninternal.server.query.SqlTreeProperty; import org.junit.Test; +import org.tests.model.basic.Customer; import static org.assertj.core.api.Assertions.assertThat; public class FormulaPropertyPathTest extends BaseTestCase { - //private BeanDescriptor customerDesc = getBeanDescriptor(Customer.class); + private BeanDescriptor customerDesc = getBeanDescriptor(Customer.class); @Test public void isFormula() { - assertFormula("max(foo)", "max", "foo"); - assertFormula("min(bar)", "min", "bar"); - assertFormula("avg(baz)", "avg", "baz"); + assertFormula("max(version)", "max", "version"); + assertFormula("min(name)", "min", "name"); + assertFormula("avg(id)", "avg", "id"); } @Test public void isFormula_count() { - assertFormula("count(moo)", "count", "moo"); - assertFormula("count(distinct joo)", "count", "joo"); + assertFormula("count(status)", "count", "status"); + assertFormula("count(distinct name)", "count", "name"); + } + + @Test + public void concat() { + + assertFormula("concat(name,'-end')", "concat", "name,'-end'"); } private void assertFormula(String input, String aggType, String baseProperty) { - FormulaPropertyPath propertyPath = new FormulaPropertyPath(input); + FormulaPropertyPath propertyPath = new FormulaPropertyPath(customerDesc, input); - assertThat(propertyPath.isFormula()).isTrue(); assertThat(propertyPath.basePropertyName()).isEqualTo(baseProperty); assertThat(propertyPath.aggType()).isEqualTo(aggType); + SqlTreeProperty treeProperty = propertyPath.build(); + + assertThat(treeProperty).isNotNull(); } } diff --git a/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java b/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java new file mode 100644 index 000000000..0b30e225c --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/util/DSelectColumnsParserTest.java @@ -0,0 +1,60 @@ +package io.ebeaninternal.server.util; + +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DSelectColumnsParserTest { + + @Test + public void parse() { + + List cols = DSelectColumnsParser.parse("a,MD5(id::text) as b,c"); + assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c"); + } + + @Test + public void whitespace_is_trimmed() { + + List cols = DSelectColumnsParser.parse("a , MD5(id::text) as b , c "); + assertThat(cols).containsExactly("a", "MD5(id::text) as b", "c"); + } + + @Test + public void nestedFunctions() { + + List cols = DSelectColumnsParser.parse("a , concat(id,'sd',inner(foo)) as b , c "); + assertThat(cols).containsExactly("a", "concat(id,'sd',inner(foo)) as b", "c"); + } + + @Test + public void basic() { + + List cols = DSelectColumnsParser.parse("name , status , billingAddress "); + assertThat(cols).containsExactly("name", "status", "billingAddress"); + } + + @Test + public void basic_noWhitespace() { + + List cols = DSelectColumnsParser.parse("a,b,c"); + assertThat(cols).containsExactly("a", "b", "c"); + } + + @Test + public void formula_noWhitespace() { + + List cols = DSelectColumnsParser.parse("a,concat(x,y),c"); + assertThat(cols).containsExactly("a", "concat(x,y)", "c"); + } + + @Test + public void with_logicalCast_andAsAlias() { + + List cols = DSelectColumnsParser.parse("name , concat(status,'-end')::String as fullName , billingAddress "); + assertThat(cols).containsExactly("name", "concat(status,'-end')::String as fullName", "billingAddress"); + } + +} diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 34c231b26..6a0c4404a 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -381,4 +381,25 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql.get(0)).contains("select count(distinct t0.last_name) from contact t0 where not exists (select 1 from contact_note x where x.contact_id = t0.id)"); } + @Test + public void example_nonAggregateFormula() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List names = + + Ebean.find(Contact.class) + .select("concat(lastName,', ',firstName)") + .where().isNull("phone") + .orderBy().asc("lastName") + .findSingleAttributeList(); + + assertThat(names).isNotEmpty(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select concat(t0.last_name,', ',t0.first_name) from contact t0 where t0.phone is null order by t0.last_name"); + } + } From e1af7c29eb0b2620e7c556cbc0a85322e6476ef6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 17:35:26 +1300 Subject: [PATCH 0141/1036] #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)") Concat automatically maps to String ScalarType --- .../server/deploy/FormulaPropertyPath.java | 21 ++++++++++++------- .../aggregation/TestAggregationCount.java | 21 +++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index b4c82f790..cc7d86bc1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -10,7 +10,7 @@ import java.util.regex.Pattern; class FormulaPropertyPath { - private static final String[] AGG_FUNCTIONS = {"count","max","min","avg"}; + private static final String[] AGG_FUNCTIONS = {"count", "max", "min", "avg"}; private static final Pattern pattern = Pattern.compile("([a-zA-Z]*)\\((.*)\\)"); @@ -41,7 +41,7 @@ class FormulaPropertyPath { } private String trimDistinct(String propertyName) { - if (propertyName.startsWith(DISTINCT_)){ + if (propertyName.startsWith(DISTINCT_)) { countDistinct = true; return propertyName.substring(DISTINCT_.length()); } else { @@ -67,19 +67,22 @@ class FormulaPropertyPath { ScalarType scalarType; if (isCount()) { - // count maps to Long / BIGINT scalarType = descriptor.getScalarType(Types.BIGINT); + + } else if (isConcat()) { + scalarType = descriptor.getScalarType(Types.VARCHAR); + } else { // determine scalarType based on first property found by parser if (firstProp != null) { scalarType = firstProp.getBeanProperty().getScalarType(); } else { - throw new IllegalStateException("unable to determine scalarType of formula [" + formula + "] for type " + descriptor+" - maybe use a cast like ::String ?"); + throw new IllegalStateException("unable to determine scalarType of formula [" + formula + "] for type " + descriptor + " - maybe use a cast like ::String ?"); } } String parsedAggregation = buildFormula(parsed); - return new DynamicPropertyAggregationFormula(formula, scalarType, parsedAggregation, isAggregate(),null); + return new DynamicPropertyAggregationFormula(formula, scalarType, parsedAggregation, isAggregate(), null); } private boolean isAggregate() { @@ -93,9 +96,9 @@ class FormulaPropertyPath { private String buildFormula(String parsed) { if (countDistinct) { - return "count(distinct "+parsed+")"; + return "count(distinct " + parsed + ")"; } else { - return outerFunction +"("+parsed+")"; + return outerFunction + "(" + parsed + ")"; } } @@ -103,4 +106,8 @@ class FormulaPropertyPath { return outerFunction.equals("count"); } + private boolean isConcat() { + return outerFunction.equals("concat"); + } + } diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 6a0c4404a..0ace4031c 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -402,4 +402,25 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql.get(0)).contains("select concat(t0.last_name,', ',t0.first_name) from contact t0 where t0.phone is null order by t0.last_name"); } + @Test + public void concat_expectString() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List names = + + Ebean.find(Contact.class) + .select("concat(updtime,', ',firstName)") + .where().isNull("phone") + .orderBy().asc("lastName") + .findSingleAttributeList(); + + assertThat(names).isNotEmpty(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select concat(t0.updtime,', ',t0.first_name) from contact t0"); + } + } From 873c14faaf5be36d252fa43e1a497dcdfbc6c901 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 20:58:30 +1300 Subject: [PATCH 0142/1036] #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)") Support cast of formula like ... select("max(updtime)::Instant") --- .../server/deploy/BeanDescriptor.java | 4 + .../server/deploy/BeanDescriptorManager.java | 5 + .../server/deploy/BeanDescriptorMap.java | 5 + .../server/deploy/FormulaPropertyPath.java | 69 ++++++++-- .../server/type/DefaultTypeManager.java | 129 ++++++++++-------- .../server/type/TypeManager.java | 5 + .../deploy/FormulaPropertyPathTest.java | 44 +++++- .../aggregation/TestAggregationCount.java | 21 +++ 8 files changed, 208 insertions(+), 74 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 41ba76d32..06810d7e0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -1066,6 +1066,10 @@ public class BeanDescriptor implements BeanType { return owner.getScalarType(jdbcType); } + public ScalarType getScalarType(String cast) { + return owner.getScalarType(cast); + } + /** * Return true if this bean type has a default select clause that is not * simply select all properties. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 9d8c6fbe6..9b2a26d11 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -265,6 +265,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } + @Override + public ScalarType getScalarType(String cast) { + return typeManager.getScalarType(cast); + } + @Override public ScalarType getScalarType(int jdbcType) { return typeManager.getScalarType(jdbcType); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java index 9d8387565..90fe0c5ff 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorMap.java @@ -66,4 +66,9 @@ public interface BeanDescriptorMap { * Return the scalarType for the given JDBC type. */ ScalarType getScalarType(int jdbcType); + + /** + * Return the scalarType for the given logical type. + */ + ScalarType getScalarType(String cast); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index cc7d86bc1..38b348162 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -5,15 +5,11 @@ import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.type.ScalarType; import java.sql.Types; -import java.util.regex.Matcher; -import java.util.regex.Pattern; class FormulaPropertyPath { private static final String[] AGG_FUNCTIONS = {"count", "max", "min", "avg"}; - private static final Pattern pattern = Pattern.compile("([a-zA-Z]*)\\((.*)\\)"); - private static final String DISTINCT_ = "distinct "; private final BeanDescriptor descriptor; @@ -26,18 +22,46 @@ class FormulaPropertyPath { private boolean countDistinct; + private String cast; + private String alias; + FormulaPropertyPath(BeanDescriptor descriptor, String formula) { this.descriptor = descriptor; this.formula = formula; - Matcher matcher = pattern.matcher(formula); - if (!matcher.find()) { + int openBracket = formula.indexOf('('); + int closeBracket = formula.lastIndexOf(')'); + if (openBracket == -1 || closeBracket == -1) { throw new IllegalStateException("Unable to parse formula [" + formula + "]"); } - //int groupCount = matcher.groupCount(); - outerFunction = matcher.group(1); - internalExpression = trimDistinct(matcher.group(2)); + outerFunction = formula.substring(0, openBracket).trim(); + internalExpression = trimDistinct(formula.substring(openBracket+1, closeBracket)); + + if (closeBracket < formula.length() -1) { + // ::CastType as foo + String suffix = formula.substring(closeBracket+1).trim(); + parseSuffix(suffix); + } + } + + private void parseSuffix(String suffix) { + String[] split = suffix.split(" "); + if (split.length == 1) { + if (split[0].startsWith("::")) { + cast = split[0].substring(2); + } else { + alias = split[0]; + } + + } else if (split.length == 2) { + cast = "as".equals(split[0]) ? null : split[0].substring(2); + alias = split[1]; + + } else if (split.length == 3) { + cast = split[0].substring(2); + alias = split[2]; + } } private String trimDistinct(String propertyName) { @@ -49,14 +73,21 @@ class FormulaPropertyPath { } } - String aggType() { + String outerFunction() { return outerFunction; } - String basePropertyName() { + String internalExpression() { return internalExpression; } + String cast() { + return cast; + } + + String alias() { + return alias; + } SqlTreeProperty build() { @@ -66,7 +97,13 @@ class FormulaPropertyPath { ElPropertyDeploy firstProp = parser.getFirstProp(); ScalarType scalarType; - if (isCount()) { + if (cast != null) { + scalarType = descriptor.getScalarType(cast); + if (scalarType == null) { + throw new IllegalStateException("Unable to find scalarType for cast of ["+cast+"] on formula [" + formula + "] for type " + descriptor); + } + + } else if (isCount()) { scalarType = descriptor.getScalarType(Types.BIGINT); } else if (isConcat()) { @@ -81,8 +118,14 @@ class FormulaPropertyPath { } } + String logicalName = (alias == null) ? formula : alias; + BeanProperty targetProperty = null; + if (alias != null) { + targetProperty = descriptor._findBeanProperty(alias); + } + String parsedAggregation = buildFormula(parsed); - return new DynamicPropertyAggregationFormula(formula, scalarType, parsedAggregation, isAggregate(), null); + return new DynamicPropertyAggregationFormula(logicalName, scalarType, parsedAggregation, isAggregate(), targetProperty); } private boolean isAggregate() { diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index 4ffe6074b..ef11a43c5 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -83,6 +83,8 @@ public final class DefaultTypeManager implements TypeManager { private final ConcurrentHashMap> nativeMap; + private final ConcurrentHashMap> logicalMap; + private final DefaultTypeFactory extraTypeFactory; private final ScalarType hstoreType = new ScalarTypePostgresHstore(); @@ -179,6 +181,7 @@ public final class DefaultTypeManager implements TypeManager { this.jsonDateTime = config.getJsonDateTime(); this.typeMap = new ConcurrentHashMap<>(); this.nativeMap = new ConcurrentHashMap<>(); + this.logicalMap = new ConcurrentHashMap<>(); boolean objectMapperPresent = config.getClassLoadConfig().isJacksonObjectMapperPresent(); this.objectMapper = (objectMapperPresent) ? initObjectMapper(config) : null; @@ -289,6 +292,11 @@ public final class DefaultTypeManager implements TypeManager { } } + @Override + public ScalarType getScalarType(String cast) { + return logicalMap.get(cast); + } + /** * Return the ScalarType for the given jdbc type as per java.sql.Types. */ @@ -842,30 +850,35 @@ public final class DefaultTypeManager implements TypeManager { if (config.getClassLoadConfig().isJavaTimePresent()) { logger.debug("Registering java.time data types"); - typeMap.put(java.time.Period.class, new ScalarTypePeriod()); - typeMap.put(java.time.LocalDate.class, new ScalarTypeLocalDate()); - typeMap.put(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(mode)); - typeMap.put(OffsetDateTime.class, new ScalarTypeOffsetDateTime(mode)); - typeMap.put(ZonedDateTime.class, new ScalarTypeZonedDateTime(mode)); - typeMap.put(Instant.class, new ScalarTypeInstant(mode)); + addType(java.time.Period.class, new ScalarTypePeriod()); + addType(java.time.LocalDate.class, new ScalarTypeLocalDate()); + addType(java.time.LocalDateTime.class, new ScalarTypeLocalDateTime(mode)); + addType(OffsetDateTime.class, new ScalarTypeOffsetDateTime(mode)); + addType(ZonedDateTime.class, new ScalarTypeZonedDateTime(mode)); + addType(Instant.class, new ScalarTypeInstant(mode)); - typeMap.put(DayOfWeek.class, new ScalarTypeDayOfWeek()); - typeMap.put(Month.class, new ScalarTypeMonth()); - typeMap.put(Year.class, new ScalarTypeYear()); - typeMap.put(YearMonth.class, new ScalarTypeYearMonthDate()); - typeMap.put(MonthDay.class, new ScalarTypeMonthDay()); - typeMap.put(OffsetTime.class, new ScalarTypeOffsetTime()); - typeMap.put(ZoneId.class, new ScalarTypeZoneId()); - typeMap.put(ZoneOffset.class, new ScalarTypeZoneOffset()); + addType(DayOfWeek.class, new ScalarTypeDayOfWeek()); + addType(Month.class, new ScalarTypeMonth()); + addType(Year.class, new ScalarTypeYear()); + addType(YearMonth.class, new ScalarTypeYearMonthDate()); + addType(MonthDay.class, new ScalarTypeMonthDay()); + addType(OffsetTime.class, new ScalarTypeOffsetTime()); + addType(ZoneId.class, new ScalarTypeZoneId()); + addType(ZoneOffset.class, new ScalarTypeZoneOffset()); boolean localTimeNanos = config.isLocalTimeWithNanos(); - typeMap.put(java.time.LocalTime.class, (localTimeNanos) ? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime()); + addType(java.time.LocalTime.class, (localTimeNanos) ? new ScalarTypeLocalTimeWithNanos() : new ScalarTypeLocalTime()); boolean durationNanos = config.isDurationWithNanos(); - typeMap.put(Duration.class, (durationNanos) ? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration()); + addType(Duration.class, (durationNanos) ? new ScalarTypeDurationWithNanos() : new ScalarTypeDuration()); } } + private void addType(Class clazz, ScalarType scalarType) { + typeMap.put(clazz, scalarType); + logicalMap.putIfAbsent(clazz.getSimpleName(), scalarType); + } + /** * Detect if Joda classes are in the classpath and if so register the Joda data types. */ @@ -876,20 +889,20 @@ public final class DefaultTypeManager implements TypeManager { if (config.getClassLoadConfig().isJodaTimePresent()) { // Joda classes are in the classpath so register the types logger.debug("Registering Joda data types"); - typeMap.put(LocalDateTime.class, new ScalarTypeJodaLocalDateTime(mode)); - typeMap.put(DateTime.class, new ScalarTypeJodaDateTime(mode)); - typeMap.put(LocalDate.class, new ScalarTypeJodaLocalDate()); - typeMap.put(org.joda.time.DateMidnight.class, new ScalarTypeJodaDateMidnight()); - typeMap.put(org.joda.time.Period.class, new ScalarTypeJodaPeriod()); + addType(LocalDateTime.class, new ScalarTypeJodaLocalDateTime(mode)); + addType(DateTime.class, new ScalarTypeJodaDateTime(mode)); + addType(LocalDate.class, new ScalarTypeJodaLocalDate()); + addType(org.joda.time.DateMidnight.class, new ScalarTypeJodaDateMidnight()); + addType(org.joda.time.Period.class, new ScalarTypeJodaPeriod()); String jodaLocalTimeMode = config.getJodaLocalTimeMode(); if ("normal".equalsIgnoreCase(jodaLocalTimeMode)) { // use the expected/normal local time zone - typeMap.put(LocalTime.class, new ScalarTypeJodaLocalTime()); + addType(LocalTime.class, new ScalarTypeJodaLocalTime()); logger.debug("registered ScalarTypeJodaLocalTime"); } else if ("utc".equalsIgnoreCase(jodaLocalTimeMode)) { // use the old UTC based - typeMap.put(LocalTime.class, new ScalarTypeJodaLocalTimeUTC()); + addType(LocalTime.class, new ScalarTypeJodaLocalTimeUTC()); logger.debug("registered ScalarTypeJodaLocalTimeUTC"); } } @@ -908,17 +921,17 @@ public final class DefaultTypeManager implements TypeManager { nativeMap.put(DbPlatformType.HSTORE, hstoreType); ScalarType utilDateType = extraTypeFactory.createUtilDate(mode); - typeMap.put(java.util.Date.class, utilDateType); + addType(java.util.Date.class, utilDateType); ScalarType calType = extraTypeFactory.createCalendar(mode); - typeMap.put(Calendar.class, calType); + addType(Calendar.class, calType); ScalarType mathBigIntType = extraTypeFactory.createMathBigInteger(); - typeMap.put(BigInteger.class, mathBigIntType); + addType(BigInteger.class, mathBigIntType); ScalarTypeBool booleanType = extraTypeFactory.createBoolean(); - typeMap.put(Boolean.class, booleanType); - typeMap.put(boolean.class, booleanType); + addType(Boolean.class, booleanType); + addType(boolean.class, booleanType); // register the boolean literals to the platform for DDL default values databasePlatform.setDbTrueLiteral(booleanType.getDbTrueLiteral()); @@ -934,31 +947,31 @@ public final class DefaultTypeManager implements TypeManager { ServerConfig.DbUuid dbUuid = config.getDbTypeConfig().getDbUuid(); if (offlineMigrationGeneration || (databasePlatform.isNativeUuidType() && dbUuid.useNativeType())) { - typeMap.put(UUID.class, new ScalarTypeUUIDNative()); + addType(UUID.class, new ScalarTypeUUIDNative()); } else { // Store UUID as binary(16) or varchar(40) ScalarType uuidType = dbUuid.useBinary() ? new ScalarTypeUUIDBinary(dbUuid.useBinaryOptimized()) : new ScalarTypeUUIDVarchar(); - typeMap.put(UUID.class, uuidType); + addType(UUID.class, uuidType); } - typeMap.put(File.class, fileType); - typeMap.put(InetAddress.class, inetAddressType); - typeMap.put(Locale.class, localeType); - typeMap.put(Currency.class, currencyType); - typeMap.put(TimeZone.class, timeZoneType); - typeMap.put(URL.class, urlType); - typeMap.put(URI.class, uriType); + addType(File.class, fileType); + addType(InetAddress.class, inetAddressType); + addType(Locale.class, localeType); + addType(Currency.class, currencyType); + addType(TimeZone.class, timeZoneType); + addType(URL.class, urlType); + addType(URI.class, uriType); // String types - typeMap.put(char[].class, charArrayType); - typeMap.put(char.class, charType); - typeMap.put(String.class, stringType); + addType(char[].class, charArrayType); + addType(char.class, charType); + addType(String.class, stringType); nativeMap.put(Types.VARCHAR, stringType); nativeMap.put(Types.CHAR, stringType); nativeMap.put(Types.LONGVARCHAR, longVarcharType); // Class - typeMap.put(Class.class, classType); + addType(Class.class, classType); if (platformClobType == Types.CLOB) { nativeMap.put(Types.CLOB, clobType); @@ -972,7 +985,7 @@ public final class DefaultTypeManager implements TypeManager { } // Binary type - typeMap.put(byte[].class, varbinaryType); + addType(byte[].class, varbinaryType); nativeMap.put(Types.BINARY, binaryType); nativeMap.put(Types.VARBINARY, varbinaryType); nativeMap.put(Types.LONGVARBINARY, longVarbinaryType); @@ -989,43 +1002,43 @@ public final class DefaultTypeManager implements TypeManager { } // Number types - typeMap.put(Byte.class, byteType); - typeMap.put(byte.class, byteType); + addType(Byte.class, byteType); + addType(byte.class, byteType); nativeMap.put(Types.TINYINT, byteType); - typeMap.put(Short.class, shortType); - typeMap.put(short.class, shortType); + addType(Short.class, shortType); + addType(short.class, shortType); nativeMap.put(Types.SMALLINT, shortType); - typeMap.put(Integer.class, integerType); - typeMap.put(int.class, integerType); + addType(Integer.class, integerType); + addType(int.class, integerType); nativeMap.put(Types.INTEGER, integerType); - typeMap.put(Long.class, longType); - typeMap.put(long.class, longType); + addType(Long.class, longType); + addType(long.class, longType); nativeMap.put(Types.BIGINT, longType); - typeMap.put(Double.class, doubleType); - typeMap.put(double.class, doubleType); + addType(Double.class, doubleType); + addType(double.class, doubleType); nativeMap.put(Types.FLOAT, doubleType);// no this is not a bug nativeMap.put(Types.DOUBLE, doubleType); - typeMap.put(Float.class, floatType); - typeMap.put(float.class, floatType); + addType(Float.class, floatType); + addType(float.class, floatType); nativeMap.put(Types.REAL, floatType);// no this is not a bug - typeMap.put(BigDecimal.class, bigDecimalType); + addType(BigDecimal.class, bigDecimalType); nativeMap.put(Types.DECIMAL, bigDecimalType); nativeMap.put(Types.NUMERIC, bigDecimalType); // Temporal types - typeMap.put(Time.class, timeType); + addType(Time.class, timeType); nativeMap.put(Types.TIME, timeType); - typeMap.put(Date.class, dateType); + addType(Date.class, dateType); nativeMap.put(Types.DATE, dateType); ScalarType timestampType = new ScalarTypeTimestamp(mode); - typeMap.put(Timestamp.class, timestampType); + addType(Timestamp.class, timestampType); nativeMap.put(Types.TIMESTAMP, timestampType); } diff --git a/src/main/java/io/ebeaninternal/server/type/TypeManager.java b/src/main/java/io/ebeaninternal/server/type/TypeManager.java index 15827cfbe..ebfebc955 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeManager.java @@ -21,6 +21,11 @@ public interface TypeManager { @SuppressWarnings("rawtypes") void addEnumType(ScalarType type, Class myEnumClass); + /** + * Return the scalar type for the given logical type. + */ + ScalarType getScalarType(String cast); + /** * Return the ScalarType for a given jdbc type. * diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java index b990d6077..9526619c9 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java @@ -31,12 +31,50 @@ public class FormulaPropertyPathTest extends BaseTestCase { assertFormula("concat(name,'-end')", "concat", "name,'-end'"); } - private void assertFormula(String input, String aggType, String baseProperty) { + @Test + public void castFormula() { + + assertFormula("concat(name,'-end')::String", "concat", "name,'-end'", "String", null); + } + + @Test + public void cast_javaInstant() { + + assertFormula("max(updtime)::Instant", "max", "updtime", "Instant", null); + } + + @Test + public void alias() { + assertFormula("concat(name,'-end') name", "concat", "name,'-end'", null, "name"); + assertFormula("concat(name,'-end') as name", "concat", "name,'-end'", null, "name"); + } + + @Test + public void castAndAlias() { + assertFormula("concat(name,'-end')::String name", "concat", "name,'-end'", "String", "name"); + assertFormula("concat(name,'-end')::String as name", "concat", "name,'-end'", "String", "name"); + } + + private void assertFormula(String input, String funcName, String expression) { + assertFormula(input, funcName, expression, null, null); + } + + private void assertFormula(String input, String funcName, String expression, String cast, String alias) { FormulaPropertyPath propertyPath = new FormulaPropertyPath(customerDesc, input); - assertThat(propertyPath.basePropertyName()).isEqualTo(baseProperty); - assertThat(propertyPath.aggType()).isEqualTo(aggType); + assertThat(propertyPath.internalExpression()).isEqualTo(expression); + assertThat(propertyPath.outerFunction()).isEqualTo(funcName); + if (cast != null) { + assertThat(propertyPath.cast()).isEqualTo(cast); + } else { + assertThat(propertyPath.cast()).isNull(); + } + if (alias != null) { + assertThat(propertyPath.alias()).isEqualTo(alias); + } else { + assertThat(propertyPath.alias()).isNull(); + } SqlTreeProperty treeProperty = propertyPath.build(); diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 0ace4031c..63732da01 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -15,6 +15,7 @@ import org.tests.model.tevent.TEventMany; import org.tests.model.tevent.TEventOne; import java.sql.Timestamp; +import java.time.Instant; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -423,4 +424,24 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql.get(0)).contains("select concat(t0.updtime,', ',t0.first_name) from contact t0"); } + @Test + public void explicitCast() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + Instant instant = + + Ebean.find(Contact.class) + .select("max(updtime)::Instant") + .where().isNull("phone") + .findSingleAttribute(); + + assertThat(instant).isNotNull(); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select max(t0.updtime) from contact t0 where t0.phone is null"); + } + } From a18cac035bdae28d2b71dfec70461166c1068fe1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 6 Mar 2018 21:14:26 +1300 Subject: [PATCH 0143/1036] #1333 - ENH: Support "dynamic formula" with findSingleAttributeList() ... e.g. .select("concat(lastName,', ',firstName)") Support property alias via "AS" ... concat(lastName,', ',firstName) as lastName --- .../server/deploy/DbSqlContext.java | 2 +- .../DynamicPropertyAggregationFormula.java | 7 +++-- .../server/deploy/FormulaPropertyPath.java | 2 +- .../server/query/DefaultDbSqlContext.java | 10 ++++--- .../aggregation/TestAggregationCount.java | 27 +++++++++++++++++++ 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java index 5b7e335f0..0eca9a112 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java @@ -67,7 +67,7 @@ public interface DbSqlContext { /** * Parse and add formula with standard table alias replacement. */ - void appendParseSelect(String parseSelect); + void appendParseSelect(String parseSelect, String alias); /** * Append a Sql Formula select. This converts the "${ta}" keyword to the diff --git a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java index 28f494bd4..d238e7ca2 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java @@ -16,11 +16,14 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { private final BeanProperty asTarget; - DynamicPropertyAggregationFormula(String name, ScalarType scalarType, String parsedFormula, boolean aggregate, BeanProperty asTarget) { + private final String alias; + + DynamicPropertyAggregationFormula(String name, ScalarType scalarType, String parsedFormula, boolean aggregate, BeanProperty asTarget, String alias) { super(name, name, null, scalarType); this.parsedFormula = parsedFormula; this.aggregate = aggregate; this.asTarget = asTarget; + this.alias = alias; } @Override @@ -49,7 +52,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { @Override public void appendSelect(DbSqlContext ctx, boolean subQuery) { - ctx.appendParseSelect(parsedFormula); + ctx.appendParseSelect(parsedFormula, alias); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index 38b348162..817868cd5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -125,7 +125,7 @@ class FormulaPropertyPath { } String parsedAggregation = buildFormula(parsed); - return new DynamicPropertyAggregationFormula(logicalName, scalarType, parsedAggregation, isAggregate(), targetProperty); + return new DynamicPropertyAggregationFormula(logicalName, scalarType, parsedAggregation, isAggregate(), targetProperty, alias); } private boolean isAggregate() { diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index dfb611e14..f40b9c2cf 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -274,11 +274,15 @@ class DefaultDbSqlContext implements DbSqlContext { } @Override - public void appendParseSelect(String parseSelect) { - String converted = alias.parse(parseSelect); + public void appendParseSelect(String parseSelect, String columnAlias) { + String converted = this.alias.parse(parseSelect); sb.append(COMMA); sb.append(converted); - appendColumnAlias(); + if (columnAlias != null) { + sb.append(" ").append(columnAlias); + } else { + appendColumnAlias(); + } } @Override diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 63732da01..330e769f9 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -444,4 +444,31 @@ public class TestAggregationCount extends BaseTestCase { assertThat(sql.get(0)).contains("select max(t0.updtime) from contact t0 where t0.phone is null"); } + + @Test + public void formula_mapToProperty() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List contacts = + + Ebean.find(Contact.class) + .select("email, concat(lastName,', ',firstName) as lastName") + .where().isNull("phone") + .orderBy().asc("lastName") + .findList(); + + assertThat(contacts).isNotEmpty(); + + for (Contact name : contacts) { + String lastName = name.getLastName(); + assertThat(lastName).contains(", "); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) lastName from contact t0 where t0.phone is null order by t0.last_name; --bind()"); + } + } From 55a257a64ce2a569d9b821c148b8be206dec05f4 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 01:52:18 +1300 Subject: [PATCH 0144/1036] #1334 - ENH: Convert ORM query into DTO query ... with dynamic formula support --- src/main/java/io/ebean/Query.java | 8 + .../io/ebeaninternal/api/SpiDtoQuery.java | 10 +- .../io/ebeaninternal/api/SpiEbeanServer.java | 11 + .../java/io/ebeaninternal/api/SpiQuery.java | 15 + .../server/core/AbstractSqlQueryRequest.java | 28 +- .../server/core/DefaultServer.java | 15 + .../server/core/DtoQueryRequest.java | 38 ++- .../server/core/OrmQueryEngine.java | 5 + .../server/core/OrmQueryRequest.java | 12 + .../server/core/RelationalQueryRequest.java | 2 +- .../server/core/SpiOrmQueryRequest.java | 5 + .../server/core/SpiResultSet.java | 29 ++ .../server/dto/DtoBeanDescriptor.java | 6 +- .../io/ebeaninternal/server/dto/DtoMeta.java | 17 +- .../server/profile/DQueryPlanMetric.java | 2 +- .../io/ebeaninternal/server/query/CQuery.java | 26 +- .../server/query/CQueryEngine.java | 34 ++ .../server/query/DefaultOrmQueryEngine.java | 7 + .../query/DefaultRelationalQueryEngine.java | 7 +- .../server/query/SqlTreeBuilder.java | 9 +- .../server/query/dto/DtoQueryEngine.java | 7 +- .../server/querydefn/DefaultDtoQuery.java | 41 ++- .../server/querydefn/DefaultOrmQuery.java | 30 +- .../server/querydefn/OrmQueryPlanKey.java | 5 +- .../java/io/ebean/DtoQueryFromOrmTest.java | 297 ++++++++++++++++++ .../ebeaninternal/api/TDSpiEbeanServer.java | 11 + .../server/querydefn/OrmQueryPlanKeyTest.java | 156 ++++----- .../aggregation/TestAggregationCount.java | 25 +- 28 files changed, 720 insertions(+), 138 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/core/SpiResultSet.java create mode 100644 src/test/java/io/ebean/DtoQueryFromOrmTest.java diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java index c7e4ed104..c5a5f425e 100644 --- a/src/main/java/io/ebean/Query.java +++ b/src/main/java/io/ebean/Query.java @@ -236,6 +236,14 @@ public interface Query { */ Query asDraft(); + /** + * Convert the query to a DTO bean query. + *

+ * We effectively use the underlying ORM query to build the SQL and then execute + * and map it into DTO beans. + */ + DtoQuery asDto(Class dtoClass); + /** * Cancel the query execution if supported by the underlying database and * driver. diff --git a/src/main/java/io/ebeaninternal/api/SpiDtoQuery.java b/src/main/java/io/ebeaninternal/api/SpiDtoQuery.java index d2c4b1fb9..c7d3e4f88 100644 --- a/src/main/java/io/ebeaninternal/api/SpiDtoQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiDtoQuery.java @@ -17,7 +17,7 @@ public interface SpiDtoQuery extends DtoQuery, SpiSqlBinding { /** * Get the query plan for the cache. */ - DtoQueryPlan getQueryPlan(String planKey); + DtoQueryPlan getQueryPlan(Object planKey); /** * Build the query plan. @@ -27,7 +27,7 @@ public interface SpiDtoQuery extends DtoQuery, SpiSqlBinding { /** * Put the query plan into the cache. */ - void putQueryPlan(String planKey, DtoQueryPlan plan); + void putQueryPlan(Object planKey, DtoQueryPlan plan); /** * Return true if the query is in relaxed mapping mode. @@ -43,4 +43,10 @@ public interface SpiDtoQuery extends DtoQuery, SpiSqlBinding { * Return the associated DTO bean type. */ Class getType(); + + /** + * Return an underlying ORM query (if this query is built from an ORM query). + */ + SpiQuery getOrmQuery(); + } diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java index 0e6af2a99..305672805 100644 --- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java @@ -1,5 +1,6 @@ package io.ebeaninternal.api; +import io.ebean.DtoQuery; import io.ebean.EbeanServer; import io.ebean.PersistenceContextScope; import io.ebean.Query; @@ -14,6 +15,7 @@ import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; +import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.query.CQuery; @@ -246,4 +248,13 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL */ void findDtoEachWhile(SpiDtoQuery query, Predicate consumer); + /** + * Return / wrap the ORM query as a DTO query. + */ + DtoQuery findDto(Class dtoType, SpiQuery ormQuery); + + /** + * Execute the underlying ORM query returning as a JDBC ResultSet to map to DTO beans. + */ + SpiResultSet findResultSet(SpiQuery ormQuery, SpiTransaction transaction); } diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index 065d3c9a5..adaa9f422 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -215,6 +215,11 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { */ BeanDescriptor getBeanDescriptor(); + /** + * Return the query plan key. + */ + Object getQueryPlanKey(); + /** * Return the RawSql that was set to use for this query. */ @@ -748,6 +753,16 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { */ boolean isDistinct(); + /** + * Return true if the Id property is manually included in the query (DTO queries). + */ + boolean isManualId(); + + /** + * Set to true when we only include the Id property if it is explicitly included in the select(). + */ + void setManualId(boolean manualId); + /** * Set default select clauses where none have been explicitly defined. */ diff --git a/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java index 7726fae36..03feedaf4 100644 --- a/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java @@ -5,6 +5,7 @@ import io.ebean.Transaction; import io.ebean.util.JdbcClose; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiSqlBinding; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.lib.util.Str; @@ -25,7 +26,7 @@ public abstract class AbstractSqlQueryRequest { private final SpiSqlBinding query; - protected final SpiEbeanServer ebeanServer; + protected final SpiEbeanServer server; protected SpiTransaction trans; @@ -45,7 +46,7 @@ public abstract class AbstractSqlQueryRequest { * Create the BeanFindRequest. */ AbstractSqlQueryRequest(SpiEbeanServer server, SpiSqlBinding query, Transaction t) { - this.ebeanServer = server; + this.server = server; this.query = query; this.trans = (SpiTransaction) t; } @@ -55,10 +56,10 @@ public abstract class AbstractSqlQueryRequest { */ public void initTransIfRequired() { if (trans == null) { - trans = ebeanServer.currentServerTransaction(); + trans = server.currentServerTransaction(); if (trans == null || !trans.isActive()) { // create a local readOnly transaction - trans = ebeanServer.createQueryTransaction(null); + trans = server.createQueryTransaction(null); createdTransaction = true; } } @@ -73,8 +74,8 @@ public abstract class AbstractSqlQueryRequest { } } - public EbeanServer getEbeanServer() { - return ebeanServer; + public EbeanServer getServer() { + return server; } public SpiTransaction getTransaction() { @@ -85,7 +86,10 @@ public abstract class AbstractSqlQueryRequest { return trans.isLogSql(); } - abstract void setResultSet(ResultSet resultSet) throws SQLException; + /** + * Set the resultSet and associated query plan if known. + */ + abstract void setResultSet(ResultSet resultSet, Object queryPlanKey) throws SQLException; /** * Return the bindLog for this request. @@ -132,7 +136,7 @@ public abstract class AbstractSqlQueryRequest { int firstRow = query.getFirstRow(); int maxRows = query.getMaxRows(); if (firstRow > 0 || maxRows > 0) { - return ebeanServer.getDatabasePlatform().getBasicSqlLimiter().limit(sql, firstRow, maxRows); + return server.getDatabasePlatform().getBasicSqlLimiter().limit(sql, firstRow, maxRows); } return sql; } @@ -140,7 +144,11 @@ public abstract class AbstractSqlQueryRequest { /** * Prepare and execute the SQL using the Binder. */ - public void executeSql(Binder binder) throws SQLException { + public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException { + executeAsSql(binder); + } + + protected void executeAsSql(Binder binder) throws SQLException { startNano = System.nanoTime(); @@ -169,7 +177,7 @@ public abstract class AbstractSqlQueryRequest { trans.logSql(logSql); } - setResultSet(pstmt.executeQuery()); + setResultSet(pstmt.executeQuery(), null); } /** diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index e74e14e53..6629aee54 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -985,6 +985,21 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return new DefaultDtoQuery<>(this, descriptor, sql.trim()); } + @Override + public DtoQuery findDto(Class dtoType, SpiQuery ormQuery) { + + DtoBeanDescriptor descriptor = dtoBeanManager.getDescriptor(dtoType); + return new DefaultDtoQuery<>(this, descriptor, ormQuery); + } + + @Override + public SpiResultSet findResultSet(SpiQuery ormQuery, SpiTransaction transaction) { + + SpiOrmQueryRequest request = createQueryRequest(ormQuery.getType(), ormQuery, transaction); + request.initTransIfRequired(); + return request.findResultSet(); + } + @Override public SqlQuery createSqlQuery(String sql) { return new DefaultRelationalQuery(this, sql.trim()); diff --git a/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java index b0801eb2e..99ba16058 100644 --- a/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/DtoQueryRequest.java @@ -2,9 +2,11 @@ package io.ebeaninternal.server.core; import io.ebeaninternal.api.SpiDtoQuery; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.dto.DtoColumn; import io.ebeaninternal.server.dto.DtoMappingRequest; import io.ebeaninternal.server.dto.DtoQueryPlan; +import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.query.dto.DtoQueryEngine; import io.ebeaninternal.server.type.DataReader; import io.ebeaninternal.server.type.RsetDataReader; @@ -37,15 +39,39 @@ public final class DtoQueryRequest extends AbstractSqlQueryRequest { this.query = query; } + /** + * Prepare and execute the SQL using the Binder. + */ @Override - protected void setResultSet(ResultSet resultSet) throws SQLException { - this.resultSet = resultSet; - this.dataReader = new RsetDataReader(ebeanServer.getDataTimeZone(), resultSet); - obtainPlan(); + public void executeSql(Binder binder, SpiQuery.Type type) throws SQLException { + SpiQuery ormQuery = query.getOrmQuery(); + if (ormQuery != null) { + ormQuery.setType(type); + ormQuery.setManualId(true); + + // execute the underlying ORM query returning the ResultSet + SpiResultSet result = server.findResultSet(ormQuery, trans); + this.pstmt = result.getStatement(); + this.sql = ormQuery.getGeneratedSql(); + setResultSet(result.getResultSet(), ormQuery.getQueryPlanKey()); + + } else { + // native SQL query execution + executeAsSql(binder); + } } - private void obtainPlan() throws SQLException { - String planKey = query.planKey(); + @Override + protected void setResultSet(ResultSet resultSet, Object queryPlanKey) throws SQLException { + this.resultSet = resultSet; + this.dataReader = new RsetDataReader(server.getDataTimeZone(), resultSet); + obtainPlan(queryPlanKey); + } + + private void obtainPlan(Object planKey) throws SQLException { + if (planKey == null) { + planKey = query.planKey(); + } plan = query.getQueryPlan(planKey); if (plan == null) { plan = query.buildPlan(mappingRequest()); diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java index aeda6a8ad..b080e4a29 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryEngine.java @@ -13,6 +13,11 @@ import java.util.List; */ public interface OrmQueryEngine { + /** + * Execute the ORM query returning the JDBC ResultSet (for DTO query processing). + */ + SpiResultSet findResultSet(OrmQueryRequest request); + /** * Execute the 'find by id' query returning a single bean. */ diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 490e53762..5a9e3f6a8 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -353,6 +353,13 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery return query.getType() == Type.BEAN; } + /** + * Return true if this is a findEach, findIterate type query where we expect many results. + */ + public boolean isFindIterate() { + return query.getType() == Type.ITERATE; + } + /** * Execute the query as a delete. */ @@ -376,6 +383,11 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery return rows; } + @Override + public SpiResultSet findResultSet() { + return queryEngine.findResultSet(this); + } + /** * Execute the query as findById. */ diff --git a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java index 81ae0aad9..dace84109 100644 --- a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java @@ -36,7 +36,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest { } @Override - protected void setResultSet(ResultSet resultSet) throws SQLException { + protected void setResultSet(ResultSet resultSet, Object planKey) throws SQLException { this.resultSet = resultSet; this.propertyNames = getPropertyNames(); // calculate the initialCapacity of the Map to reduce rehashing diff --git a/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java index 32ab198ff..68895bb88 100644 --- a/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/SpiOrmQueryRequest.java @@ -114,6 +114,11 @@ public interface SpiOrmQueryRequest extends BeanQueryRequest, DocQueryRequ */ List findSingleAttributeList(); + /** + * Execute returning the ResultSet. + */ + SpiResultSet findResultSet(); + /** * Try to get the query result from the query cache. */ diff --git a/src/main/java/io/ebeaninternal/server/core/SpiResultSet.java b/src/main/java/io/ebeaninternal/server/core/SpiResultSet.java new file mode 100644 index 000000000..6c539e564 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/core/SpiResultSet.java @@ -0,0 +1,29 @@ +package io.ebeaninternal.server.core; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +/** + * Hold the JDBC PreparedStatement and ResultSet. + * + * These both must be closed properly when done. + */ +public class SpiResultSet { + + private final PreparedStatement statement; + + private final ResultSet resultSet; + + public SpiResultSet(PreparedStatement statement, ResultSet resultSet) { + this.statement = statement; + this.resultSet = resultSet; + } + + public PreparedStatement getStatement() { + return statement; + } + + public ResultSet getResultSet() { + return resultSet; + } +} diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java index 6d7698857..81920e858 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java @@ -10,7 +10,7 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DtoBeanDescriptor { - private final Map plans = new ConcurrentHashMap<>(); + private final Map plans = new ConcurrentHashMap<>(); private final Class dtoType; @@ -25,7 +25,7 @@ public class DtoBeanDescriptor { return dtoType; } - public DtoQueryPlan getQueryPlan(String planKey) { + public DtoQueryPlan getQueryPlan(Object planKey) { return plans.get(planKey); } @@ -33,7 +33,7 @@ public class DtoBeanDescriptor { return meta.match(request); } - public void putQueryPlan(String planKey, DtoQueryPlan plan) { + public void putQueryPlan(Object planKey, DtoQueryPlan plan) { plans.put(planKey, plan); } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoMeta.java b/src/main/java/io/ebeaninternal/server/dto/DtoMeta.java index 272e962b5..bd26cfaee 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoMeta.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoMeta.java @@ -1,5 +1,7 @@ package io.ebeaninternal.server.dto; +import io.ebean.util.StringHelper; + import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; @@ -81,7 +83,7 @@ class DtoMeta { int pos = 0; for (int i = firstOnes; i < cols.length; i++) { String label = cols[i].getLabel(); - DtoReadSet property = propMap.get(label.toUpperCase()); + DtoReadSet property = findProperty(label); if (property == null || property.isReadOnly()) { if (request.isRelaxedMode()) { property = DtoReadSetColumnSkip.INSTANCE; @@ -103,7 +105,7 @@ class DtoMeta { for (int i = 0; i < cols.length; i++) { String label = cols[i].getLabel(); - DtoReadSet property = propMap.get(label.toUpperCase()); + DtoReadSet property = findProperty(label); if (property == null || property.isReadOnly()) { if (request.isRelaxedMode()) { property = DtoReadSetColumnSkip.INSTANCE; @@ -116,4 +118,15 @@ class DtoMeta { return new DtoQueryPlanConSetter(request, defaultConstructor, setterProps); } + + private DtoReadSet findProperty(String label) { + + String upperLabel = label.toUpperCase(); + DtoMetaProperty property = propMap.get(upperLabel); + if (property == null) { + upperLabel = StringHelper.replaceString(upperLabel, "_", ""); + property = propMap.get(upperLabel); + } + return property; + } } diff --git a/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java b/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java index 4ba29d8c3..b358a5584 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java +++ b/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java @@ -41,7 +41,7 @@ class DQueryPlanMetric implements QueryPlanMetric { @Override public String toString() { - return meta +" "+ stats; + return meta + " " + stats + " sql:" + getSql(); } @Override diff --git a/src/main/java/io/ebeaninternal/server/query/CQuery.java b/src/main/java/io/ebeaninternal/server/query/CQuery.java index 6ab29d742..da7bdd090 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -310,11 +310,21 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran private boolean prepareBindExecuteQueryWithOption(boolean forwardOnlyHint) throws SQLException { + ResultSet resultSet = prepareResultSet(forwardOnlyHint); + if (resultSet == null) { + return false; + } + dataReader = queryPlan.createDataReader(resultSet); + return true; + } + + ResultSet prepareResultSet(boolean forwardOnlyHint) throws SQLException { + synchronized (this) { if (cancelled || query.isCancelled()) { // cancelled before we started cancelled = true; - return false; + return null; } startNano = System.nanoTime(); @@ -328,9 +338,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran ResultSet suppliedResultSet = query.getRawSql().getResultSet(); if (suppliedResultSet != null) { // this is a user supplied ResultSet so use that - dataReader = queryPlan.createDataReader(suppliedResultSet); bindLog = ""; - return true; + return suppliedResultSet; } } @@ -353,10 +362,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran bindLog = predicates.bind(dataBind); // executeQuery - ResultSet rset = pstmt.executeQuery(); - dataReader = queryPlan.createDataReader(rset); - - return true; + return pstmt.executeQuery(); } } @@ -793,4 +799,10 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran } } + /** + * Return the underlying PreparedStatement. + */ + PreparedStatement getPstmt() { + return pstmt; + } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java index f03efc1a0..d4a3bd6ba 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java @@ -8,12 +8,14 @@ import io.ebean.bean.EntityBean; import io.ebean.bean.ObjectGraphNode; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.util.JdbcClose; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.DiffHelp; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.core.OrmQueryRequest; +import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.lib.util.Str; import io.ebeaninternal.server.persist.Binder; @@ -22,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.LinkedHashMap; import java.util.List; @@ -325,6 +328,37 @@ public class CQueryEngine { return historySupport.getSysPeriodLower(rootTableAlias); } + /** + * Execute returning the ResultSet and PreparedStatement for processing (by DTO query usually). + */ + public SpiResultSet findResultSet(OrmQueryRequest request) { + CQuery cquery = queryBuilder.buildQuery(request); + try { + boolean fwdOnly; + if (request.isFindIterate()) { + // findEach ... + fwdOnly = forwardOnlyHintOnFindIterate; + if (defaultFetchSizeFindEach > 0) { + request.setDefaultFetchBuffer(defaultFetchSizeFindEach); + } + } else { + // findList - aggressive fetch + fwdOnly = false; + if (defaultFetchSizeFindList > 0) { + request.setDefaultFetchBuffer(defaultFetchSizeFindList); + } + } + ResultSet resultSet = cquery.prepareResultSet(fwdOnly); + if (request.isLogSql()) { + logSql(cquery); + } + return new SpiResultSet(cquery.getPstmt(), resultSet); + + } catch (SQLException e) { + JdbcClose.close(cquery.getPstmt()); + throw cquery.createPersistenceException(e); + } + } /** * Find a list/map/set of beans. diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java index bed19babe..c6c042c92 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -9,6 +9,7 @@ import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.OrmQueryEngine; import io.ebeaninternal.server.core.OrmQueryRequest; +import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.persist.Binder; @@ -77,6 +78,12 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { return queryEngine.update(request); } + @Override + public SpiResultSet findResultSet(OrmQueryRequest request) { + flushJdbcBatchOnQuery(request); + return queryEngine.findResultSet(request); + } + @Override public int findCount(OrmQueryRequest request) { diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java index f401863a2..4be7bec7b 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.query; import io.ebean.SqlRow; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.core.RelationalQueryEngine; import io.ebeaninternal.server.core.RelationalQueryRequest; @@ -39,7 +40,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine { public void findEach(RelationalQueryRequest request, Predicate consumer) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.ITERATE); while (request.next()) { if (!consumer.test(readRow(request))) { break; @@ -59,7 +60,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine { public void findEach(RelationalQueryRequest request, Consumer consumer) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.ITERATE); while (request.next()) { consumer.accept(readRow(request)); } @@ -77,7 +78,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine { public List findList(RelationalQueryRequest request) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.LIST); List rows = new ArrayList<>(); while (request.next()) { rows.add(readRow(request)); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 1c572cf91..8811096eb 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -442,7 +442,7 @@ public final class SqlTreeBuilder { p = desc.findBeanProperty("id"); selectProps.add(p); - } else if (p.isId() && isNotSingleAttribute()) { + } else if (p.isId() && excludeIdProperty()) { // do not bother to include id for normal queries as the // id is always added (except for subQueries) @@ -722,6 +722,13 @@ public final class SqlTreeBuilder { } + /** + * Return true if the Id property should be excluded (as it is automatically included). + */ + private boolean excludeIdProperty() { + return query == null || !query.isSingleAttribute() && !query.isManualId(); + } + /** * Return true if the query is not a single attribute query. */ diff --git a/src/main/java/io/ebeaninternal/server/query/dto/DtoQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/dto/DtoQueryEngine.java index 29944d117..fceed1465 100644 --- a/src/main/java/io/ebeaninternal/server/query/dto/DtoQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/dto/DtoQueryEngine.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.query.dto; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.DtoQueryRequest; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.persist.Binder; @@ -20,7 +21,7 @@ public class DtoQueryEngine { public List findList(DtoQueryRequest request) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.LIST); List rows = new ArrayList<>(); while (request.next()) { rows.add(request.readNextBean()); @@ -36,7 +37,7 @@ public class DtoQueryEngine { public void findEach(DtoQueryRequest request, Consumer consumer) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.ITERATE); while (request.next()) { consumer.accept(request.readNextBean()); } @@ -50,7 +51,7 @@ public class DtoQueryEngine { public void findEachWhile(DtoQueryRequest request, Predicate consumer) { try { - request.executeSql(binder); + request.executeSql(binder, SpiQuery.Type.ITERATE); while (request.next()) { if (!consumer.test(request.readNextBean())) { break; diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java index a3def9baa..cf3158974 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java @@ -4,6 +4,7 @@ import io.ebean.DtoQuery; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiDtoQuery; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.dto.DtoBeanDescriptor; import io.ebeaninternal.server.dto.DtoMappingRequest; import io.ebeaninternal.server.dto.DtoQueryPlan; @@ -22,6 +23,8 @@ public class DefaultDtoQuery implements SpiDtoQuery { private final DtoBeanDescriptor descriptor; + private final SpiQuery ormQuery; + private String sql; private int firstRow; @@ -42,11 +45,21 @@ public class DefaultDtoQuery implements SpiDtoQuery { private final BindParams bindParams = new BindParams(); /** - * Additional supply a query detail object. + * Create given an underlying ORM query. + */ + public DefaultDtoQuery(SpiEbeanServer server, DtoBeanDescriptor descriptor, SpiQuery ormQuery) { + this.server = server; + this.descriptor = descriptor; + this.ormQuery = ormQuery; + } + + /** + * Create given a native SQL query. */ public DefaultDtoQuery(SpiEbeanServer server, DtoBeanDescriptor descriptor, String sql) { this.server = server; this.descriptor = descriptor; + this.ormQuery = null; this.sql = sql; } @@ -56,7 +69,7 @@ public class DefaultDtoQuery implements SpiDtoQuery { } @Override - public DtoQueryPlan getQueryPlan(String planKey) { + public DtoQueryPlan getQueryPlan(Object planKey) { return descriptor.getQueryPlan(planKey); } @@ -66,7 +79,7 @@ public class DefaultDtoQuery implements SpiDtoQuery { } @Override - public void putQueryPlan(String planKey, DtoQueryPlan plan) { + public void putQueryPlan(Object planKey, DtoQueryPlan plan) { descriptor.putQueryPlan(planKey, plan); } @@ -97,13 +110,21 @@ public class DefaultDtoQuery implements SpiDtoQuery { @Override public DtoQuery setParameter(int position, Object value) { - bindParams.setParameter(position, value); + if (ormQuery != null) { + ormQuery.setParameter(position, value); + } else { + bindParams.setParameter(position, value); + } return this; } @Override public DtoQuery setParameter(String paramName, Object value) { - bindParams.setParameter(paramName, value); + if (ormQuery != null) { + ormQuery.setParameter(paramName, value); + } else { + bindParams.setParameter(paramName, value); + } return this; } @@ -117,6 +138,10 @@ public class DefaultDtoQuery implements SpiDtoQuery { return descriptor.getType(); } + public SpiQuery getOrmQuery() { + return ormQuery; + } + @Override public DtoQuery setRelaxedMode() { this.relaxedMode = true; @@ -147,6 +172,9 @@ public class DefaultDtoQuery implements SpiDtoQuery { @Override public DtoQuery setFirstRow(int firstRow) { this.firstRow = firstRow; + if (ormQuery != null) { + ormQuery.setFirstRow(firstRow); + } return this; } @@ -158,6 +186,9 @@ public class DefaultDtoQuery implements SpiDtoQuery { @Override public DtoQuery setMaxRows(int maxRows) { this.maxRows = maxRows; + if (ormQuery != null) { + ormQuery.setMaxRows(maxRows); + } return this; } diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index a66619796..7a908b410 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.querydefn; import io.ebean.CacheMode; import io.ebean.CountDistinctOrder; +import io.ebean.DtoQuery; import io.ebean.Expression; import io.ebean.ExpressionFactory; import io.ebean.ExpressionList; @@ -130,6 +131,11 @@ public class DefaultOrmQuery implements SpiQuery { private String lazyLoadManyPath; + /** + * Flag set for report/DTO beans when we may choose to explicitly include the Id property. + */ + private boolean manualId; + /** * Set to true by a user wanting a DISTINCT query (id property must be excluded). */ @@ -280,6 +286,11 @@ public class DefaultOrmQuery implements SpiQuery { this.nativeSql = nativeSql; } + @Override + public DtoQuery asDto(Class dtoClass) { + return server.findDto(dtoClass, this); + } + @Override public BeanDescriptor getBeanDescriptor() { return beanDescriptor; @@ -668,7 +679,7 @@ public class DefaultOrmQuery implements SpiQuery { */ @Override public boolean isWithId() { - return !distinct && !singleAttribute; + return !manualId && !distinct && !singleAttribute; } @Override @@ -1027,7 +1038,7 @@ public class DefaultOrmQuery implements SpiQuery { queryPlanKey = new NativeSqlQueryPlanKey(nativeSql + "-" + firstRow + "-" + maxRows); } else { queryPlanKey = new OrmQueryPlanKey(beanDescriptor.getDiscValue(), m2mIncludeJoin, type, detail, maxRows, firstRow, - disableLazyLoading, orderBy, + disableLazyLoading, manualId, orderBy, distinct, sqlDistinct, mapKey, id, bindParams, whereExpressions, havingExpressions, temporalMode, forUpdate, rootTableAlias, rawSql, updateProperties, countDistinctOrder); } @@ -1044,6 +1055,11 @@ public class DefaultOrmQuery implements SpiQuery { return nativeSql; } + @Override + public Object getQueryPlanKey() { + return queryPlanKey; + } + /** * Prepare the query which prepares any expressions (sub-query expressions etc) and calculates the query plan key. */ @@ -1475,6 +1491,16 @@ public class DefaultOrmQuery implements SpiQuery { return this; } + @Override + public boolean isManualId() { + return manualId; + } + + @Override + public void setManualId(boolean manualId) { + this.manualId = manualId; + } + /** * return true if user specified to use SQL DISTINCT (effectively excludes id property). */ diff --git a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java index eb7ca79c1..da91f6ea2 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java @@ -22,7 +22,7 @@ class OrmQueryPlanKey implements CQueryPlanKey { private final String description; OrmQueryPlanKey(String discValue, TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, - OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, + boolean manualId, OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, Query.ForUpdate forUpdate, String rootTableAlias, SpiRawSql rawSql, OrmUpdateProperties updateProperties, CountDistinctOrder countDistinctOrder) { @@ -42,6 +42,9 @@ class OrmQueryPlanKey implements CQueryPlanKey { if (id != null) { sb.append(",id:"); } + if (manualId) { + sb.append(",manId:"); + } if (distinct) { sb.append(",dist:"); } diff --git a/src/test/java/io/ebean/DtoQueryFromOrmTest.java b/src/test/java/io/ebean/DtoQueryFromOrmTest.java new file mode 100644 index 000000000..af22c17c6 --- /dev/null +++ b/src/test/java/io/ebean/DtoQueryFromOrmTest.java @@ -0,0 +1,297 @@ +package io.ebean; + +import io.ebean.meta.MetaQueryMetric; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Ignore; +import org.junit.Test; +import org.tests.model.basic.Contact; +import org.tests.model.basic.ResetBasicData; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DtoQueryFromOrmTest extends BaseTestCase { + +// @BeforeClass +// public static void resetStats() { +// Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); +// } +// +// @AfterClass +// public static void reportStats() { +// List stats = Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(false); +// for (MetaQueryMetric stat : stats) { +// System.out.println(stat); +// } +// } + + @Ignore + @Test + public void testPlanHits() { + + ResetBasicData.reset(); + + Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); + + String[] prefix = {"Bl", "B", "Red"}; + + for (String val : prefix) { + List list = Ebean.find(Contact.class) + .select("email, concat(lastName,', ',firstName) as fullName") + .where().istartsWith("concat(lastName,', ',firstName)", val) + .orderBy().asc("lastName") + .setMaxRows(10) + .asDto(ContactDto.class) + .findList(); + + System.out.println("List:" + list); + } + + List stats = Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); + for (MetaQueryMetric stat : stats) { + System.out.println(stat); + } + + assertThat(stats).hasSize(1); + assertThat(stats.get(0).getCount()).isEqualTo(3); + + } + + @Test + public void asDto_withExplicitId() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + DtoQuery query = + Ebean.find(Contact.class) + // we must explicitly add the id property for DTO query (if we want it) + .select("id, email, concat(lastName,', ',firstName) as fullName") + .where().isNotNull("email").isNotNull("lastName") + .orderBy().asc("lastName") + .asDto(ContactDto.class) + .setRelaxedMode(); + + List dtos = query.findList(); + + assertThat(dtos).isNotEmpty(); + + for (ContactDto dto : dtos) { + assertThat(dto.getEmail()).isNotNull(); + assertThat(dto.getFullName()).isNotNull(); + System.out.println(dto); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } + + @Test + public void asDto_withoutExplicitId() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + DtoQuery query = + Ebean.find(Contact.class) + .select("email, concat(lastName,', ',firstName) as fullName") + .where().isNotNull("email").isNotNull("lastName") + .orderBy().asc("lastName") + .asDto(ContactDto.class); + + List dtos = query.findList(); + + assertThat(dtos).isNotEmpty(); + + for (ContactDto dto : dtos) { + assertThat(dto.getEmail()).isNotNull(); + assertThat(dto.getFullName()).isNotNull(); + System.out.println(dto); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } + + + @Test + public void example() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List contactDtos + = Ebean.find(Contact.class) + .select("email, concat(lastName,', ',firstName) as fullName") + .where().isNotNull("email").isNotNull("lastName") + .orderBy().asc("lastName") + .setMaxRows(10) + .asDto(ContactDto.class) + .findList(); + + assertThat(contactDtos).isNotEmpty(); + + for (ContactDto dto : contactDtos) { + assertThat(dto.getEmail()).isNotNull(); + assertThat(dto.getFullName()).isNotNull(); + System.out.println(dto); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } + + @Test + public void example_explicitId() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List contactDtos + = Ebean.find(Contact.class) + .select("id, email, concat(lastName,', ',firstName) as fullName") + .where().isNotNull("email").isNotNull("lastName") + .orderBy().asc("lastName") + .setMaxRows(10) + .asDto(ContactDto.class) + .findList(); + + assertThat(contactDtos).isNotEmpty(); + + for (ContactDto dto : contactDtos) { + System.out.println(dto); + assertThat(dto.getId()).isNotNull(); + assertThat(dto.getFullName()).isNotNull(); + assertThat(dto.getEmail()).isNotNull(); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } + + @Test + public void example_singleProperty() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List contactDtos + = Ebean.find(Contact.class) + .select("concat(lastName,', ',firstName) as fullName") + .where().isNotNull("lastName") + .orderBy().asc("lastName") + .asDto(ContactDto.class) + .setFirstRow(2) + .setMaxRows(5) + .findList(); + + assertThat(contactDtos).isNotEmpty(); + + for (ContactDto dto : contactDtos) { + System.out.println(dto); + assertThat(dto.getFullName()).isNotNull(); + assertThat(dto.getId()).isNull(); + assertThat(dto.getEmail()).isNull(); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where"); + } + + + @Test + public void example_aggregate() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + + List contactDtos + = Ebean.find(Contact.class) + .select("lastName, count(*) as totalCount") + .where().isNotNull("lastName") + .having().gt("count(*)", 1) + .orderBy().desc("count(*)") + .asDto(ContactTotals.class) + .findList(); + + assertThat(contactDtos).isNotEmpty(); + + for (ContactTotals dto : contactDtos) { + assertThat(dto.getLastName()).isNotNull(); + assertThat(dto.getTotalCount()).isNotNull(); + } + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.last_name, count(*) totalCount from contact t0 where t0.last_name is not null group by t0.last_name having count(*) > ?"); + } + + public static class ContactTotals { + + String lastName; + Long totalCount; + + @Override + public String toString() { + return "lastName:" + lastName + " total:" + totalCount; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Long getTotalCount() { + return totalCount; + } + + public void setTotalCount(Long totalCount) { + this.totalCount = totalCount; + } + } + + public static class ContactDto { + + String email; + String fullName; + Integer id; + + @Override + public String toString() { + return "id:" + id + " email:" + email + " fn:" + fullName; + } + + public String getEmail() { + return email; + } + + public String getFullName() { + return fullName; + } + + public void setEmail(String email) { + this.email = email; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } +} diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index 28bf61ec4..349767266 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -41,6 +41,7 @@ import io.ebean.plugin.SpiServer; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; +import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.query.CQuery; @@ -414,6 +415,16 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public DtoQuery findDto(Class dtoType, SpiQuery ormQuery) { + return null; + } + + @Override + public SpiResultSet findResultSet(SpiQuery ormQuery, SpiTransaction transaction) { + return null; + } + @Override public SqlQuery createSqlQuery(String sql) { return null; diff --git a/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java b/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java index 1ab27c6d0..7df67e9a7 100644 --- a/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java +++ b/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java @@ -10,8 +10,8 @@ import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; import io.ebeaninternal.server.expression.BaseExpressionTest; -import org.tests.model.basic.Customer; import org.junit.Test; +import org.tests.model.basic.Customer; import static org.assertj.core.api.Assertions.assertThat; @@ -21,8 +21,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_defaults() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @@ -30,9 +30,9 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffDiscValue() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey("A", null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key3 = new OrmQueryPlanKey("B", null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey("A", null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key3 = new OrmQueryPlanKey("B", null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); assertDifferent(key2, key3); } @@ -42,8 +42,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { TableJoin tableJoin = tableJoin("table", "id", "customer_id"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -54,8 +54,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); TableJoin tableJoin2 = tableJoin("two", "id", "customer_id"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -66,8 +66,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); TableJoin tableJoin2 = tableJoin("one", "id", "customer_id"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @@ -82,8 +82,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffQueryType() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.LIST, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.LIST, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -91,8 +91,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_firstRowsDifferent() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 10, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 10, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -100,8 +100,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_maxRowsDifferent() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -109,8 +109,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_firstRowsMaxRowsSame() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @@ -118,8 +118,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffDisableLazyLoading() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, true, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, true, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -128,8 +128,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { public void equals_when_diffOrderByNull() { OrderBy o1 = new OrderBy<>("id"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -139,121 +139,121 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { OrderBy o1 = new OrderBy<>("id, name"); OrderBy o2 = new OrderBy<>("id, name"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, o2, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o2, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @Test public void equals_when_diffDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_sameDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @Test public void equals_when_diffSqlDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_sameSqlDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @Test public void equals_when_diffMapKeyNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffMapKey() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, "diff", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "diff", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_sameMapKey() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @Test public void equals_when_diffIdNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_idBothGiven() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, 23, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 23, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @Test public void equals_when_diffTemporalMode() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffForUpdate() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffForUpdate_NoWait() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.NOWAIT, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.NOWAIT, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffForUpdate_SkipLocked() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.SKIPLOCKED, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.SKIPLOCKED, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffRootAliasNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_diffRootAlias() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "diff", null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "diff", null, null, null); assertDifferent(key1, key2); } @Test public void equals_when_sameRootAlias() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); assertSame(key1, key2); } @@ -280,8 +280,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpressionList list1 = list_id_eq_42(); SpiExpressionList list2 = list_id_eq_43(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, list2, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list2, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @@ -292,8 +292,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpressionList where1 = list_id_eq_42(); SpiExpressionList where2 = list_id_eq_42_and_name_eq_rob(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, where1, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, where2, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, where1, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, where2, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -302,8 +302,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpressionList list1 = list_id_eq_42(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -312,8 +312,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpressionList list1 = list_id_eq_42(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -323,8 +323,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpression having1 = list_id_eq_42().copyForPlanKey(); SpiExpression having2 = list_id_eq_42_and_name_eq_rob().copyForPlanKey(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -334,8 +334,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpression having1 = list_id_eq_42().copyForPlanKey(); SpiExpression having2 = list_id_eq_42().copyForPlanKey(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertSame(key1, key2); } @@ -344,8 +344,8 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } @@ -354,8 +354,16 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + assertDifferent(key1, key2); + } + + @Test + public void equals_when_manualId() { + + OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, true, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); assertDifferent(key1, key2); } diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 330e769f9..dcbdcdf1e 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -3,7 +3,6 @@ package org.tests.query.aggregation; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; -import org.assertj.core.api.Assertions; import org.ebeantest.LoggedSqlCollector; import org.junit.BeforeClass; import org.junit.Test; @@ -40,7 +39,6 @@ public class TestAggregationCount extends BaseTestCase { Ebean.save(three); three.setName("third"); Ebean.save(three); - } @Test @@ -232,7 +230,6 @@ public class TestAggregationCount extends BaseTestCase { .query(); Timestamp maxUpdateTime = query0.findSingleAttribute(); - System.out.println(""+maxUpdateTime); assertThat(maxUpdateTime).isNotNull(); String sql = sqlOf(query0, 5); @@ -256,8 +253,7 @@ public class TestAggregationCount extends BaseTestCase { .select("max(orderQty)"); Integer maxOrderQty = query.findSingleAttribute(); - System.out.println(""+maxOrderQty); - Assertions.assertThat(maxOrderQty).isGreaterThan(20); + assertThat(maxOrderQty).isGreaterThan(20); String sql = sqlOf(query, 5); assertThat(sql).contains("select max(t0.order_qty) from o_order_detail t0"); @@ -272,7 +268,6 @@ public class TestAggregationCount extends BaseTestCase { .select("min(orderQty)"); Integer minOrderQty = query.findSingleAttribute(); - System.out.println(""+minOrderQty); assertThat(minOrderQty).isLessThan(10); String sql = sqlOf(query, 5); @@ -288,7 +283,7 @@ public class TestAggregationCount extends BaseTestCase { .select("max(lastName)"); String maxName = query.findSingleAttribute(); - System.out.println(""+maxName); + assertThat(maxName).isNotNull(); String sql = sqlOf(query, 5); assertThat(sql).contains("select max(t0.last_name) from contact t0"); @@ -303,7 +298,6 @@ public class TestAggregationCount extends BaseTestCase { .select("min(firstName)"); String minName = query.findSingleAttribute(); - System.out.println(""+minName); assertThat(minName).isNotNull(); String sql = sqlOf(query, 5); @@ -320,7 +314,6 @@ public class TestAggregationCount extends BaseTestCase { .select("count(lastName)"); Long count = query.findSingleAttribute(); - System.out.println(""+count); assertThat(count).isNotNull(); String sql = sqlOf(query, 5); @@ -336,7 +329,6 @@ public class TestAggregationCount extends BaseTestCase { .select("count(distinct lastName)"); Long count = query.findSingleAttribute(); - System.out.println(""+count); assertThat(count).isNotNull(); String sql = sqlOf(query, 5); @@ -352,9 +344,9 @@ public class TestAggregationCount extends BaseTestCase { String maxLastName = Ebean.find(Contact.class) - .select("max(lastName)") - .where().isNull("phone") - .findSingleAttribute(); + .select("max(lastName)") + .where().isNull("phone") + .findSingleAttribute(); assertThat(maxLastName).isNotNull(); @@ -371,11 +363,10 @@ public class TestAggregationCount extends BaseTestCase { Long count = Ebean.find(Contact.class) - .select("count(distinct lastName)") - .where().isEmpty("notes") - .findSingleAttribute(); + .select("count(distinct lastName)") + .where().isEmpty("notes") + .findSingleAttribute(); - System.out.println(""+count); assertThat(count).isNotNull(); List sql = LoggedSqlCollector.stop(); From 3cb52917e34f0b96bb205e1c0dfb1ff0af94bd0b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 02:03:54 +1300 Subject: [PATCH 0145/1036] #1335 - Add Try catch to YAML loading ... add system property ebeanSkipYaml ... to enable skipping the read of application.yml (well, all yml) --- .../io/ebean/config/properties/Loader.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/ebean/config/properties/Loader.java b/src/main/java/io/ebean/config/properties/Loader.java index 036b504fa..283b2c6e2 100644 --- a/src/main/java/io/ebean/config/properties/Loader.java +++ b/src/main/java/io/ebean/config/properties/Loader.java @@ -28,16 +28,18 @@ class Loader { private YamlLoader yamlLoader; Loader() { - - try { - Class exists = Class.forName("org.yaml.snakeyaml.Yaml"); - if (exists != null) { - yamlLoader = new YamlLoader(loadContext); - } - } catch (Exception e) { - // ignored - } - } + String skipYaml = System.getProperty("ebeanSkipYaml"); + if (!"true".equals(skipYaml)) { + try { + Class exists = Class.forName("org.yaml.snakeyaml.Yaml"); + if (exists != null) { + yamlLoader = new YamlLoader(loadContext); + } + } catch (Exception e) { + // ignored + } + } + } /** * Load the configuration with the expected ordering. @@ -115,7 +117,11 @@ class Loader { void loadYaml(String resourcePath, Source source) { if (yamlLoader != null) { - yamlLoader.load(resource(resourcePath, source)); + try { + yamlLoader.load(resource(resourcePath, source)); + } catch (Exception e) { + log.warn("Failed to read yml from:" + resourcePath, e); + } } } From 2019bc7bf1454f50936d673293fb9266b65bcd4c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 02:19:10 +1300 Subject: [PATCH 0146/1036] #1336 - Change DDL generation such that it does create index before alter table add foreign key --- .../dbmigration/ddlgeneration/platform/BaseTableDdl.java | 7 +++---- .../assert/BaseTableDdlTest/createTable-applyLast.txt | 2 +- .../resources/assert/ModelBuild_compoundKeyTest/apply.sql | 4 ++-- .../assert/ModelBuild_explicitSequencesTest/apply.sql | 2 +- .../assert/ModelBuild_explicitSequencesTest/pg-apply.sql | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 459531eea..f396312f2 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -435,15 +435,15 @@ public class BaseTableDdl implements TableDdl { protected void writeForeignKey(DdlWrite write, WriteForeignKey request) throws IOException { - String tableName = lowerTableName(request.table()); DdlBuffer fkeyBuffer = write.applyForeignKeys(); - alterTableAddForeignKey(fkeyBuffer, request); - + String tableName = lowerTableName(request.table()); if (request.indexName() != null) { // no matching unique constraint so add the index fkeyBuffer.append(platformDdl.createIndex(request.indexName(), tableName, request.cols())).endOfStatement(); } + alterTableAddForeignKey(fkeyBuffer, request); + fkeyBuffer.end(); write.dropAllForeignKeys() @@ -455,7 +455,6 @@ public class BaseTableDdl implements TableDdl { } write.dropAllForeignKeys().end(); - } protected void alterTableAddForeignKey(DdlBuffer buffer, WriteForeignKey request) throws IOException { diff --git a/src/test/resources/assert/BaseTableDdlTest/createTable-applyLast.txt b/src/test/resources/assert/BaseTableDdlTest/createTable-applyLast.txt index 1f68497c3..c542cc572 100644 --- a/src/test/resources/assert/BaseTableDdlTest/createTable-applyLast.txt +++ b/src/test/resources/assert/BaseTableDdlTest/createTable-applyLast.txt @@ -1,3 +1,3 @@ -alter table mytable add constraint fk_mytable_order_id foreign key (order_id) references orders (id) on delete restrict on update restrict; create index ix_mytable_order_id on mytable (order_id); +alter table mytable add constraint fk_mytable_order_id foreign key (order_id) references orders (id) on delete restrict on update restrict; diff --git a/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql b/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql index e0789ab8a..8951d13e2 100644 --- a/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql +++ b/src/test/resources/assert/ModelBuild_compoundKeyTest/apply.sql @@ -21,9 +21,9 @@ create table ckey_parent ( constraint pk_ckey_parent primary key (one_key,two_key) ); -alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); +alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; diff --git a/src/test/resources/assert/ModelBuild_explicitSequencesTest/apply.sql b/src/test/resources/assert/ModelBuild_explicitSequencesTest/apply.sql index 88a80916d..331c29ad3 100644 --- a/src/test/resources/assert/ModelBuild_explicitSequencesTest/apply.sql +++ b/src/test/resources/assert/ModelBuild_explicitSequencesTest/apply.sql @@ -13,6 +13,6 @@ create table phones ( constraint pk_phones primary key (id) ); -alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; diff --git a/src/test/resources/assert/ModelBuild_explicitSequencesTest/pg-apply.sql b/src/test/resources/assert/ModelBuild_explicitSequencesTest/pg-apply.sql index d22ff78ec..329da196f 100644 --- a/src/test/resources/assert/ModelBuild_explicitSequencesTest/pg-apply.sql +++ b/src/test/resources/assert/ModelBuild_explicitSequencesTest/pg-apply.sql @@ -13,6 +13,6 @@ create table phones ( constraint pk_phones primary key (id) ); -alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; From 1ba21d5c4324fa3e15c568a41fcaa631d5785538 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 02:22:58 +1300 Subject: [PATCH 0147/1036] Bump to 11.14.1-SNAPSHOT ... Modified DDL generation order of create index vs alter table add FK --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bf454b12d..ada2fa29c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.13.2-SNAPSHOT + 11.14.1-SNAPSHOT jar ebean From 70c3860a65f3c5becebd05de85e86b1f029a67e6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 02:24:07 +1300 Subject: [PATCH 0148/1036] [maven-release-plugin] prepare release ebean-11.14.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ada2fa29c..b9c202534 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.1-SNAPSHOT + 11.14.1 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.14.1 From 70aed3906edb0b554a2217cef1741dc76548e27d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 02:24:21 +1300 Subject: [PATCH 0149/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b9c202534..8918f3d3d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.1 + 11.14.2-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.14.1 + HEAD From 47e8d27212126cf7e7b7aca8c241c5838674ed9a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 16:21:00 +1300 Subject: [PATCH 0150/1036] #1337 - Fix YamlLoader ... such that it loads multi-part yml source --- src/main/java/io/ebean/config/properties/YamlLoader.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebean/config/properties/YamlLoader.java b/src/main/java/io/ebean/config/properties/YamlLoader.java index 2c472b22b..b7157810e 100644 --- a/src/main/java/io/ebean/config/properties/YamlLoader.java +++ b/src/main/java/io/ebean/config/properties/YamlLoader.java @@ -21,9 +21,12 @@ class YamlLoader { this.loadContext = loadContext; } + @SuppressWarnings("unchecked") void load(InputStream is) { if (is != null) { - loadMap(yaml.load(is), null); + for (Object map : yaml.loadAll(is)) { + loadMap((Map)map, null); + } } } From baa7242939047f525beb3f5445e23ac5eeddcc1a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 16:43:42 +1300 Subject: [PATCH 0151/1036] #1338 - Regression since 11.12.1 - resolve expressions in Properties given to serverConfig.loadFromProperties() --- src/main/java/io/ebean/config/ServerConfig.java | 12 ++++++++++-- .../config/properties/PropertiesLoader.java | 16 ++++++++++++++++ .../io/ebean/config/PropertiesWrapperTest.java | 14 +++++++++++--- .../java/io/ebean/config/ServerConfigTest.java | 16 ++++++++++++++++ 4 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 0c6edcc64..b0b5f362a 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -2642,7 +2642,8 @@ public class ServerConfig { * Load settings from ebean.properties. */ public void loadFromProperties() { - loadFromProperties(PropertiesLoader.load()); + this.properties = PropertiesLoader.load(); + configureFromProperties(); } /** @@ -2650,7 +2651,14 @@ public class ServerConfig { */ public void loadFromProperties(Properties properties) { // keep the properties used for configuration so that these are available for plugins - this.properties = properties; + this.properties = PropertiesLoader.eval(properties); + configureFromProperties(); + } + + /** + * Load the settings from the given properties + */ + private void configureFromProperties() { autoConfiguration(); PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties); loadSettings(p); diff --git a/src/main/java/io/ebean/config/properties/PropertiesLoader.java b/src/main/java/io/ebean/config/properties/PropertiesLoader.java index b62236de3..560d255e5 100644 --- a/src/main/java/io/ebean/config/properties/PropertiesLoader.java +++ b/src/main/java/io/ebean/config/properties/PropertiesLoader.java @@ -1,5 +1,6 @@ package io.ebean.config.properties; +import java.util.Enumeration; import java.util.Properties; /** @@ -66,4 +67,19 @@ public class PropertiesLoader { properties.setProperty(key, value); } + /** + * Return a copy of the properties with 'eval' run on all the values. + * This resolves expressions like ${HOME} etc. + */ + public static Properties eval(Properties properties) { + Properties evalCopy = new Properties(); + + Enumeration names = properties.propertyNames(); + while (names.hasMoreElements()) { + String name = (String)names.nextElement(); + String value = PropertyEval.eval(properties.getProperty(name)); + evalCopy.setProperty(name, value); + } + return evalCopy; + } } diff --git a/src/test/java/io/ebean/config/PropertiesWrapperTest.java b/src/test/java/io/ebean/config/PropertiesWrapperTest.java index ee9e294f4..016af03c6 100644 --- a/src/test/java/io/ebean/config/PropertiesWrapperTest.java +++ b/src/test/java/io/ebean/config/PropertiesWrapperTest.java @@ -1,6 +1,7 @@ package io.ebean.config; import io.ebean.annotation.Platform; +import io.ebean.config.properties.PropertiesLoader; import org.junit.Test; import java.util.Properties; @@ -50,6 +51,9 @@ public class PropertiesWrapperTest { @Test public void testGetProperties() { + String home = System.getenv("HOME"); + String tmpDir = System.getProperty("java.io.tmpdir"); + Properties properties = new Properties(); properties.put("someBasic", "hello"); properties.put("someInt", "42"); @@ -57,16 +61,20 @@ public class PropertiesWrapperTest { properties.put("somePath", "${HOME}/hello"); properties.put("someSystemProp", "/aaa/${java.io.tmpdir}/bbb"); - PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", properties); + Properties evalCopy = PropertiesLoader.eval(properties); + PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", evalCopy); assertEquals(42, pw.getInt("someInt", 99)); assertEquals(Double.valueOf(5.5D), (Double.valueOf(pw.getDouble("someDouble", 99.9D)))); + assertEquals(home + "/hello", pw.get("somePath", null)); + assertEquals(tmpDir, "/aaa/" + tmpDir + "/bbb", pw.get("someSystemProp")); - - pw = new PropertiesWrapper(properties); + pw = new PropertiesWrapper(evalCopy); assertEquals(42, pw.getInt("someInt", 99)); assertEquals(Double.valueOf(5.5D), (Double.valueOf(pw.getDouble("someDouble", 99.9D)))); + assertEquals(home + "/hello", pw.get("somePath", null)); + assertEquals(tmpDir, "/aaa/" + tmpDir + "/bbb", pw.get("someSystemProp")); } } diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index fcf62fee5..8ee588ad3 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import java.util.Properties; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -24,6 +25,21 @@ public class ServerConfigTest { assertNotNull(serverConfig.getProperties()); } + @Test + public void evalPropertiesInput() { + + String home = System.getenv("HOME"); + + Properties props = new Properties(); + props.setProperty("ddl.initSql", "${HOME}/initSql"); + + ServerConfig serverConfig = new ServerConfig(); + serverConfig.loadFromProperties(props); + + String ddlInitSql = serverConfig.getDdlInitSql(); + assertThat(ddlInitSql).isEqualTo(home+"/initSql"); + } + @Test public void testLoadWithProperties() { From e182190f96a297c59f44c2b112b8bb1c2b4ca548 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 20:19:48 +1300 Subject: [PATCH 0152/1036] #1339 - Regression: Fix for not throwing OptimisticLockException when loaded bean has @Version property set --- .../io/ebean/bean/EntityBeanIntercept.java | 38 +++++++++++++------ .../java/org/tests/basic/TestIUDVanilla.java | 15 +++++++- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/src/main/java/io/ebean/bean/EntityBeanIntercept.java index 17b1eac73..de6c82456 100644 --- a/src/main/java/io/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/io/ebean/bean/EntityBeanIntercept.java @@ -529,6 +529,16 @@ public final class EntityBeanIntercept implements Serializable { } } + /** + * Set old value but force it to be set regardless if it already has a value. + */ + private void setOriginalValueForce(int propertyIndex, Object value) { + if (origValues == null) { + origValues = new Object[owner._ebean_getPropertyNames().length]; + } + origValues[propertyIndex] = value; + } + /** * For forced update on a 'New' bean set all the loaded properties to changed. */ @@ -901,15 +911,19 @@ public final class EntityBeanIntercept implements Serializable { if (setDirtyState) { setOriginalValue(propertyIndex, origValue); - if (!dirty) { - dirty = true; - if (embeddedOwner != null) { - // Cascade dirty state from Embedded bean to parent bean - embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex); - } - if (nodeUsageCollector != null) { - nodeUsageCollector.setModified(); - } + setDirtyStatus(); + } + } + + private void setDirtyStatus() { + if (!dirty) { + dirty = true; + if (embeddedOwner != null) { + // Cascade dirty state from Embedded bean to parent bean + embeddedOwner._ebean_getIntercept().setEmbeddedDirty(embeddedOwnerIndex); + } + if (nodeUsageCollector != null) { + nodeUsageCollector.setModified(); } } } @@ -1049,10 +1063,12 @@ public final class EntityBeanIntercept implements Serializable { } /** - * Explicitly set an old value. + * Explicitly set an old value with force (the old value is forced even it is already set). */ public void setOldValue(int propertyIndex, Object oldValue) { - setChangedPropertyValue(propertyIndex, true, oldValue); + setChangedProperty(propertyIndex); + setOriginalValueForce(propertyIndex, oldValue); + setDirtyStatus(); } /** diff --git a/src/test/java/org/tests/basic/TestIUDVanilla.java b/src/test/java/org/tests/basic/TestIUDVanilla.java index f215d1614..f5117c4e7 100644 --- a/src/test/java/org/tests/basic/TestIUDVanilla.java +++ b/src/test/java/org/tests/basic/TestIUDVanilla.java @@ -2,10 +2,12 @@ package org.tests.basic; import io.ebean.BaseTestCase; import io.ebean.Ebean; -import org.tests.model.basic.EBasicVer; import org.junit.Assert; import org.junit.Test; +import org.tests.model.basic.EBasicVer; +import org.tests.model.basic.UTMaster; +import javax.persistence.OptimisticLockException; import java.sql.Timestamp; public class TestIUDVanilla extends BaseTestCase { @@ -66,4 +68,15 @@ public class TestIUDVanilla extends BaseTestCase { Ebean.update(e3); } + + @Test(expected = OptimisticLockException.class) + public void modifyVersion_expect_optimisticLock() { + + UTMaster e0 = new UTMaster("save me"); + Ebean.save(e0); + + // for this case we know 42 should throw OptimisticLockException + e0.setVersion(42); + Ebean.update(e0); + } } From 4d8bc0a2ce44c66bb1502875a44148462b02ffd5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 20:22:25 +1300 Subject: [PATCH 0153/1036] [maven-release-plugin] prepare release ebean-11.14.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8918f3d3d..f750608b0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.2-SNAPSHOT + 11.14.2 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.14.2 From 54ba1480ebbefa8a18f960b9577597e92bde8fa6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 7 Mar 2018 20:22:38 +1300 Subject: [PATCH 0154/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f750608b0..d97ca7ad8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.2 + 11.14.3-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.14.2 + HEAD From c0efd49c73c67030f29f426db3f25e95d0387694 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 14:12:32 +1300 Subject: [PATCH 0155/1036] #1341 - Cascade persist with JDBC batch and BeanPersistAdapter with preUpdate() that invokes lazy loading on persisted bean ... results in OptimisticLockException --- .../server/persist/BatchedBeanHolder.java | 15 ++++--- .../event/BeanPersistControllerTest.java | 43 +++++++++++++++++++ 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/persist/BatchedBeanHolder.java b/src/main/java/io/ebeaninternal/server/persist/BatchedBeanHolder.java index cfe05cd8c..6c974cc56 100644 --- a/src/main/java/io/ebeaninternal/server/persist/BatchedBeanHolder.java +++ b/src/main/java/io/ebeaninternal/server/persist/BatchedBeanHolder.java @@ -85,16 +85,19 @@ public class BatchedBeanHolder { // Note updates and deletes can result in many PreparedStatements // if their where clauses differ via use of IS NOT NULL. if (deletes != null && !deletes.isEmpty()) { - control.executeNow(deletes); - deletes.clear(); + ArrayList bufferedDeletes = deletes; + deletes = new ArrayList<>(); + control.executeNow(bufferedDeletes); } if (inserts != null && !inserts.isEmpty()) { - control.executeNow(inserts); - inserts.clear(); + ArrayList bufferedInserts = inserts; + inserts = new ArrayList<>(); + control.executeNow(bufferedInserts); } if (updates != null && !updates.isEmpty()) { - control.executeNow(updates); - updates.clear(); + ArrayList bufferedUpdates = updates; + updates = new ArrayList<>(); + control.executeNow(bufferedUpdates); } persistedBeans.clear(); } diff --git a/src/test/java/io/ebean/event/BeanPersistControllerTest.java b/src/test/java/io/ebean/event/BeanPersistControllerTest.java index 58d351a1c..e63f77bc3 100644 --- a/src/test/java/io/ebean/event/BeanPersistControllerTest.java +++ b/src/test/java/io/ebean/event/BeanPersistControllerTest.java @@ -3,9 +3,12 @@ package io.ebean.event; import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; +import io.ebean.Transaction; import io.ebean.config.ServerConfig; import org.junit.Test; import org.tests.model.basic.EBasicVer; +import org.tests.model.basic.UTDetail; +import org.tests.model.basic.UTMaster; import java.util.ArrayList; import java.util.Arrays; @@ -19,6 +22,36 @@ public class BeanPersistControllerTest { private PersistAdapter stopPersistingAdapter = new PersistAdapter(false); + @Test + public void issue_1341() { + + EbeanServer ebeanServer = getEbeanServer(continuePersistingAdapter); + + UTMaster bean0 = new UTMaster("one0"); + UTDetail detail0 = new UTDetail("detail0", 12, 23D); + bean0.getDetails().add(detail0); + + ebeanServer.save(bean0); + + UTMaster master = ebeanServer.find(UTMaster.class) + .setId(bean0.getId()) + .fetch("details", "name, version") + .findOne(); + + UTDetail utDetail = master.getDetails().get(0); + utDetail.setName("detail0 mod"); + + Transaction txn = ebeanServer.beginTransaction(); + try { + txn.setBatchMode(true); + ebeanServer.save(master); + txn.commit(); + } finally { + txn.end(); + } + + } + @Test public void testInsertUpdateDelete_given_continuePersistingAdapter() { @@ -91,6 +124,8 @@ public class BeanPersistControllerTest { config.setRegister(false); config.setDefaultServer(false); config.getClasses().add(EBasicVer.class); + config.getClasses().add(UTMaster.class); + config.getClasses().add(UTDetail.class); config.add(persistAdapter); @@ -130,6 +165,14 @@ public class BeanPersistControllerTest { @Override public boolean preUpdate(BeanPersistRequest request) { methodsCalled.add("preUpdate"); + + Object bean = request.getBean(); + if (bean instanceof UTDetail) { + UTDetail detail = (UTDetail)bean; + // invoke lazy loading ... which invoke the flush of the jdbc batch + detail.setQty(42); + } + return continueDefaultPersisting; } From 4b594fb53393b2866c2d2c35c3880e44e6a37955 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 14:16:30 +1300 Subject: [PATCH 0156/1036] [maven-release-plugin] prepare release ebean-11.14.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d97ca7ad8..4deeb42da 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.3-SNAPSHOT + 11.14.3 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.14.3 From dbf5f3b57b71052b42c40f095d296d04176c8bf1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 14:16:45 +1300 Subject: [PATCH 0157/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4deeb42da..2c541ae1b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.3 + 11.14.4-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.14.3 + HEAD From 6258a5d263ab1c4b1ce6369fd464a5028cf47043 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 14:36:18 +1300 Subject: [PATCH 0158/1036] Logging only change - Drop the logging from WARN to DEBUG for beans without an Id property (which is not usual but valid for Ebean) --- .../io/ebeaninternal/server/deploy/BeanDescriptorManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 9b2a26d11..b0044d91a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1353,7 +1353,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // bean doesn't have an Id property if (desc.isBaseTableType() && desc.getBeanFinder() == null) { // expecting an id property - logger.warn(Message.msg("deploy.nouid", desc.getFullName())); + logger.debug(Message.msg("deploy.nouid", desc.getFullName())); } return; } From 4fc7898f85f052d5f54e50b2a5535d1788644f34 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:36:53 +1300 Subject: [PATCH 0159/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Changes to main --- .../java/io/ebean/config/ServerConfig.java | 2 +- .../sqlserver/SqlServer16Platform.java | 26 +++++++++++++++++++ .../sqlserver/SqlServer17Platform.java | 16 ++++++++++++ .../sqlserver/SqlServer2005Platform.java | 2 +- ...atform.java => SqlServerBasePlatform.java} | 20 ++++++++------ .../dbmigration/DefaultDbMigration.java | 9 +++++-- .../extraddl/model/ExtraDdlXmlReader.java | 22 ++++++++++++++++ .../server/core/DatabasePlatformFactory.java | 20 +++++++++----- .../server/core/PlatformDdlBuilder.java | 6 +++-- 9 files changed, 102 insertions(+), 21 deletions(-) create mode 100644 src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java create mode 100644 src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java rename src/main/java/io/ebean/config/dbplatform/sqlserver/{SqlServerPlatform.java => SqlServerBasePlatform.java} (86%) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index b0b5f362a..f32473ec6 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -1740,7 +1740,7 @@ public class ServerConfig { * that you don't have access to. *

*

- * Values are oracle, h2, postgres, mysql, mssqlserver2005. + * Values are oracle, h2, postgres, mysql, sqlserver16, sqlserver17. *

*/ public void setDatabasePlatformName(String databasePlatformName) { diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java new file mode 100644 index 000000000..af0d7582a --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java @@ -0,0 +1,26 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.DbType; +import io.ebean.config.dbplatform.IdType; + +/** + * Microsoft SQL Server platform that has non-UTF8 types (char, varchar, text) and default to Identity rather than Sequence. + */ +public class SqlServer16Platform extends SqlServerBasePlatform { + + public SqlServer16Platform() { + super(); + this.platform = Platform.SQLSERVER16; + // default to use Identity rather than sequences + this.dbIdentity.setIdType(IdType.IDENTITY); + + // non-utf8 column types + dbTypeMap.put(DbType.CHAR, new DbPlatformType("char", 1)); + dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar", 255)); + dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text")); + dbTypeMap.put(DbType.CLOB, new DbPlatformType("text")); + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java new file mode 100644 index 000000000..fd17bbe9f --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java @@ -0,0 +1,16 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.annotation.Platform; + +/** + * Microsoft SQL Server platform - NVarchar UTF types and Sequence preference. + */ +public class SqlServer17Platform extends SqlServerBasePlatform { + + public SqlServer17Platform() { + super(); + this.platform = Platform.SQLSERVER17; + this.columnAliasPrefix = null; + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java index 0473e9d3f..44eea1a04 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java @@ -3,7 +3,7 @@ package io.ebean.config.dbplatform.sqlserver; /** * SQL Server platform using the older ROW_NUMBER() mechanism. */ -public class SqlServer2005Platform extends SqlServerPlatform { +public class SqlServer2005Platform extends SqlServer16Platform { public SqlServer2005Platform() { this.sqlLimiter = new SqlServer2005SqlLimiter(); diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java similarity index 86% rename from src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java rename to src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index 31e1a8525..39727c7b2 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -16,11 +16,11 @@ import javax.sql.DataSource; import java.sql.Types; /** - * Microsoft SQL Server platform. + * Base Microsoft SQL Server platform - NVarchar UTF types and Sequence preference by default. */ -public class SqlServerPlatform extends DatabasePlatform { +abstract class SqlServerBasePlatform extends DatabasePlatform { - public SqlServerPlatform() { + SqlServerBasePlatform() { super(); this.platform = Platform.SQLSERVER; // disable persistBatchOnCascade mode for @@ -31,7 +31,7 @@ public class SqlServerPlatform extends DatabasePlatform { this.sqlLimiter = new SqlServerSqlLimiter(); this.basicSqlLimiter = new SqlServerBasicSqlLimiter(); this.historySupport = new SqlServerHistorySupport(); - this.dbIdentity.setIdType(IdType.IDENTITY); + this.dbIdentity.setIdType(IdType.SEQUENCE); this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsIdentity(true); this.dbIdentity.setSupportsSequence(true); @@ -63,18 +63,22 @@ public class SqlServerPlatform extends DatabasePlatform { dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint")); dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28)); - dbTypeMap.put(DbType.BLOB, new DbPlatformType("image")); - dbTypeMap.put(DbType.CLOB, new DbPlatformType("text")); - dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image")); - dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text")); dbTypeMap.put(DbType.DATE, new DbPlatformType("date")); dbTypeMap.put(DbType.TIME, new DbPlatformType("time")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2")); + // UTF8 aware types - overwritten in SqlServer16 platform + dbTypeMap.put(DbType.CHAR, new DbPlatformType("nchar", 1)); + dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255)); + dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.CLOB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.JSON, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); dbTypeMap.put(DbType.JSONB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.BLOB, new DbPlatformType("image")); + dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image")); } @Override diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index d767d62a6..c548bbc64 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -15,7 +15,8 @@ import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform; import io.ebean.config.dbplatform.sqlite.SQLitePlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebean.dbmigration.DbMigration; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; @@ -554,8 +555,12 @@ public class DefaultDbMigration implements DbMigration { return new OraclePlatform(); case SQLANYWHERE: return new SqlAnywherePlatform(); + case SQLSERVER16: + return new SqlServer16Platform(); + case SQLSERVER17: + return new SqlServer17Platform(); case SQLSERVER: - return new SqlServerPlatform(); + throw new IllegalArgumentException("Please choose the more specific SQLSERVER16 or SQLSERVER17 platform. Refer to issue #1340 for details"); case DB2: return new DB2Platform(); case SQLITE: diff --git a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java index 629c9d202..a478a1ac7 100644 --- a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java +++ b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java @@ -1,5 +1,6 @@ package io.ebeaninternal.extraddl.model; +import io.ebean.annotation.Platform; import io.ebean.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,6 +17,8 @@ public class ExtraDdlXmlReader { private static final Logger logger = LoggerFactory.getLogger(ExtraDdlXmlReader.class); + private static final String SQLSERVER = Platform.SQLSERVER.name().toLowerCase(); + /** * Return the combined extra DDL that should be run given the platform name. */ @@ -52,14 +55,33 @@ public class ExtraDdlXmlReader { return true; } + String genericMatch = genericPlatformMatch(platformName); + for (String name : StringHelper.splitNames(platforms)) { if (name.toLowerCase().contains(platformName)) { return true; + } else if (genericMatch != null && genericMatch.equals(name.toLowerCase())) { + // allow sqlserver ... to match sqlserver17 and sqlserver16 platforms + return true; } } return false; } + /** + * Return a "generic" platform name that can be used. e.g. sqlserver17 -> sqlserver. + */ + private static String genericPlatformMatch(String platformName) { + switch (platformName) { + case "sqlserver17": + return SQLSERVER; + case "sqlserver16": + return SQLSERVER; + default: + return null; + } + } + /** * Read and return a ExtraDdl from an xml document at the given resource path. */ diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index 496f67cbb..3f98a1c6d 100644 --- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -1,17 +1,18 @@ package io.ebeaninternal.server.core; import io.ebean.config.ServerConfig; -import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.Postgres8Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; -import io.ebean.config.dbplatform.sqlite.SQLitePlatform; import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform; +import io.ebean.config.dbplatform.sqlite.SQLitePlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.dbmigration.DbOffline; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,8 +53,7 @@ public class DatabasePlatformFactory { } if (serverConfig.getDataSourceConfig().isOffline()) { - String m = "You must specify a DatabasePlatformName when you are offline"; - throw new PersistenceException(m); + throw new PersistenceException("You must specify a DatabasePlatformName when you are offline"); } // guess using meta data from driver return byDataSource(serverConfig.getDataSource()); @@ -84,8 +84,14 @@ public class DatabasePlatformFactory { if (dbName.equals("oracle") || dbName.equals("oracle10") || dbName.equals("oracle9")) { return new OraclePlatform(); } + if (dbName.equals("sqlserver16")) { + return new SqlServer16Platform(); + } + if (dbName.equals("sqlserver17")) { + return new SqlServer17Platform(); + } if (dbName.equals("sqlserver")) { - return new SqlServerPlatform(); + throw new IllegalArgumentException("Please choose the more specific sqlserver16 or sqlserver17 platform. Refer to issue #1340 for details"); } if (dbName.equals("sqlanywhere")) { return new SqlAnywherePlatform(); @@ -137,7 +143,7 @@ public class DatabasePlatformFactory { if (dbProductName.contains("oracle")) { return new OraclePlatform(); } else if (dbProductName.contains("microsoft")) { - return new SqlServerPlatform(); + throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via ServerConfig.setDatabasePlatformName. Refer to issue #1340 for more details"); } else if (dbProductName.contains("mysql")) { return new MySqlPlatform(); } else if (dbProductName.contains("h2")) { diff --git a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java index 560bc519e..efd69538e 100644 --- a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java +++ b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java @@ -38,10 +38,12 @@ public class PlatformDdlBuilder { return new PlatformDdl(platform); case POSTGRES: return new PostgresDdl(platform); - case SQLSERVER: - return new SqlServerDdl(platform); case SQLANYWHERE: return new PlatformDdl(platform); + case SQLSERVER16: + case SQLSERVER17: + case SQLSERVER: + return new SqlServerDdl(platform); default: return new PlatformDdl(platform); } From eef514f922c4cf0735c396a475513314a3430c06 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:37:29 +1300 Subject: [PATCH 0160/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Changes to pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2c541ae1b..9d9eee542 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ io.ebean ebean-annotation - 3.8 + 3.11 From 8e0d2f8749cbc57ec68fdd360c590eaad85e1624 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:39:10 +1300 Subject: [PATCH 0161/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). test - dbmigration ddl --- .../migrationtest/sqlserver/1.0__initial.sql | 48 ++--- .../migrationtest/sqlserver/1.1.sql | 22 +-- .../migrationtest/sqlserver/1.3.sql | 4 +- .../sqlserver17/1.0__initial.sql | 160 ++++++++++++++++ .../migrationtest/sqlserver17/1.1.sql | 104 ++++++++++ .../sqlserver17/1.2__dropsFor_1.1.sql | 43 +++++ .../migrationtest/sqlserver17/1.3.sql | 62 ++++++ .../sqlserver17/1.4__dropsFor_1.3.sql | 179 ++++++++++++++++++ 8 files changed, 585 insertions(+), 37 deletions(-) create mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver17/1.0__initial.sql create mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver17/1.1.sql create mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver17/1.2__dropsFor_1.1.sql create mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver17/1.3.sql create mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver17/1.4__dropsFor_1.3.sql diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql index be7ab17be..ea820be14 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql @@ -2,22 +2,22 @@ -- apply changes create table migtest_ckey_assoc ( id integer not null, - assoc_one varchar(255), + assoc_one nvarchar(255), constraint pk_migtest_ckey_assoc primary key (id) ); create sequence migtest_ckey_assoc_seq as bigint start with 1 ; create table migtest_ckey_detail ( id integer not null, - something varchar(255), + something nvarchar(255), constraint pk_migtest_ckey_detail primary key (id) ); create sequence migtest_ckey_detail_seq as bigint start with 1 ; create table migtest_ckey_parent ( one_key integer not null, - two_key varchar(127) not null, - name varchar(255), + two_key nvarchar(127) not null, + name nvarchar(255), version integer not null, constraint pk_migtest_ckey_parent primary key (one_key,two_key) ); @@ -64,19 +64,19 @@ create sequence migtest_fk_set_null_seq as bigint start with 1 ; create table migtest_e_basic ( id integer not null, - status varchar(1), - name varchar(127), - description varchar(127), + status nvarchar(1), + name nvarchar(127), + description nvarchar(127), some_date datetime2, old_boolean bit default 0 not null, old_boolean2 bit, eref_id integer, - indextest1 varchar(127), - indextest2 varchar(127), - indextest3 varchar(127), - indextest4 varchar(127), - indextest5 varchar(127), - indextest6 varchar(127), + indextest1 nvarchar(127), + indextest2 nvarchar(127), + indextest3 nvarchar(127), + indextest4 nvarchar(127), + indextest5 nvarchar(127), + indextest6 nvarchar(127), user_id integer not null, constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), constraint pk_migtest_e_basic primary key (id) @@ -87,21 +87,21 @@ create sequence migtest_e_basic_seq as bigint start with 1 ; create table migtest_e_history ( id integer not null, - test_string varchar(255), + test_string nvarchar(255), constraint pk_migtest_e_history primary key (id) ); create sequence migtest_e_history_seq as bigint start with 1 ; create table migtest_e_history2 ( id integer not null, - test_string varchar(255), + test_string nvarchar(255), constraint pk_migtest_e_history2 primary key (id) ); create sequence migtest_e_history2_seq as bigint start with 1 ; create table migtest_e_ref ( id integer not null, - name varchar(127) not null, + name nvarchar(127) not null, constraint pk_migtest_e_ref primary key (id) ); alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); @@ -109,49 +109,49 @@ create sequence migtest_e_ref_seq as bigint start with 1 ; create table migtest_e_softdelete ( id integer not null, - test_string varchar(255), + test_string nvarchar(255), constraint pk_migtest_e_softdelete primary key (id) ); create sequence migtest_e_softdelete_seq as bigint start with 1 ; create table migtest_mtm_c ( id integer not null, - name varchar(255), + name nvarchar(255), constraint pk_migtest_mtm_c primary key (id) ); create sequence migtest_mtm_c_seq as bigint start with 1 ; create table migtest_mtm_m ( id numeric(19) not null, - name varchar(255), + name nvarchar(255), constraint pk_migtest_mtm_m primary key (id) ); create sequence migtest_mtm_m_seq as bigint start with 1 ; create table migtest_oto_child ( id integer not null, - name varchar(255), + name nvarchar(255), constraint pk_migtest_oto_child primary key (id) ); create sequence migtest_oto_child_seq as bigint start with 1 ; create table migtest_oto_master ( id numeric(19) not null, - name varchar(255), + name nvarchar(255), constraint pk_migtest_oto_master primary key (id) ); create sequence migtest_oto_master_seq as bigint start with 1 ; create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); alter table migtest_e_history2 add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql index e20737814..90c1f96bf 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql @@ -19,7 +19,7 @@ create table migtest_mtm_m_migtest_mtm_c ( ); alter table migtest_ckey_detail add one_key integer; -alter table migtest_ckey_detail add two_key varchar(127); +alter table migtest_ckey_detail add two_key nvarchar(127); alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key); alter table migtest_ckey_parent add assoc_id integer; @@ -34,7 +34,7 @@ alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id for update migtest_e_basic set status = 'A' where status is null; IF (OBJECT_ID('ck_migtest_e_basic_status', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; alter table migtest_e_basic add default 'A' for status; -alter table migtest_e_basic alter column status varchar(1) not null; +alter table migtest_e_basic alter column status nvarchar(1) not null; alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?')); -- rename all collisions; @@ -47,7 +47,7 @@ alter table migtest_e_basic alter column some_date datetime2 not null; insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); alter table migtest_e_basic alter column user_id integer; -alter table migtest_e_basic add new_string_field varchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add new_string_field nvarchar(255) default 'foo''bar' not null; alter table migtest_e_basic add new_boolean_field bit default 1 not null; update migtest_e_basic set new_boolean_field = old_boolean; @@ -68,9 +68,9 @@ alter table migtest_e_history alter column test_string numeric(19); update migtest_e_history2 set test_string = 'unknown' where test_string is null; alter table migtest_e_history2 add default 'unknown' for test_string; -alter table migtest_e_history2 alter column test_string varchar(255) not null; -alter table migtest_e_history2 add test_string2 varchar(255); -alter table migtest_e_history2 add test_string3 varchar(255) default 'unknown' not null; +alter table migtest_e_history2 alter column test_string nvarchar(255) not null; +alter table migtest_e_history2 add test_string2 nvarchar(255); +alter table migtest_e_history2 add test_string3 nvarchar(255) default 'unknown' not null; alter table migtest_e_softdelete add deleted bit default 0 not null; @@ -80,20 +80,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest1') drop index ix_migtest_e_basic_indextest1 ON migtest_e_basic; IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest5') drop index ix_migtest_e_basic_indextest5 ON migtest_e_basic; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id); create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id); alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql index 5109fb90e..50c300716 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql @@ -2,7 +2,7 @@ -- apply changes create table migtest_e_ref ( id integer not null, - name varchar(127) not null, + name nvarchar(127) not null, constraint pk_migtest_e_ref primary key (id) ); alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); @@ -57,6 +57,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest3') drop index ix_migtest_e_basic_indextest3 ON migtest_e_basic; IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest6') drop index ix_migtest_e_basic_indextest6 ON migtest_e_basic; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.0__initial.sql new file mode 100644 index 000000000..ea820be14 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.0__initial.sql @@ -0,0 +1,160 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create table migtest_ckey_assoc ( + id integer not null, + assoc_one nvarchar(255), + constraint pk_migtest_ckey_assoc primary key (id) +); +create sequence migtest_ckey_assoc_seq as bigint start with 1 ; + +create table migtest_ckey_detail ( + id integer not null, + something nvarchar(255), + constraint pk_migtest_ckey_detail primary key (id) +); +create sequence migtest_ckey_detail_seq as bigint start with 1 ; + +create table migtest_ckey_parent ( + one_key integer not null, + two_key nvarchar(127) not null, + name nvarchar(255), + version integer not null, + constraint pk_migtest_ckey_parent primary key (one_key,two_key) +); + +create table migtest_fk_cascade ( + id numeric(19) not null, + one_id numeric(19), + constraint pk_migtest_fk_cascade primary key (id) +); +create sequence migtest_fk_cascade_seq as bigint start with 1 ; + +create table migtest_fk_cascade_one ( + id numeric(19) not null, + constraint pk_migtest_fk_cascade_one primary key (id) +); +create sequence migtest_fk_cascade_one_seq as bigint start with 1 ; + +create table migtest_fk_none ( + id numeric(19) not null, + one_id numeric(19), + constraint pk_migtest_fk_none primary key (id) +); +create sequence migtest_fk_none_seq as bigint start with 1 ; + +create table migtest_fk_none_via_join ( + id numeric(19) not null, + one_id numeric(19), + constraint pk_migtest_fk_none_via_join primary key (id) +); +create sequence migtest_fk_none_via_join_seq as bigint start with 1 ; + +create table migtest_fk_one ( + id numeric(19) not null, + constraint pk_migtest_fk_one primary key (id) +); +create sequence migtest_fk_one_seq as bigint start with 1 ; + +create table migtest_fk_set_null ( + id numeric(19) not null, + one_id numeric(19), + constraint pk_migtest_fk_set_null primary key (id) +); +create sequence migtest_fk_set_null_seq as bigint start with 1 ; + +create table migtest_e_basic ( + id integer not null, + status nvarchar(1), + name nvarchar(127), + description nvarchar(127), + some_date datetime2, + old_boolean bit default 0 not null, + old_boolean2 bit, + eref_id integer, + indextest1 nvarchar(127), + indextest2 nvarchar(127), + indextest3 nvarchar(127), + indextest4 nvarchar(127), + indextest5 nvarchar(127), + indextest6 nvarchar(127), + user_id integer not null, + constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), + constraint pk_migtest_e_basic primary key (id) +); +create unique nonclustered index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) where indextest2 is not null; +create unique nonclustered index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) where indextest6 is not null; +create sequence migtest_e_basic_seq as bigint start with 1 ; + +create table migtest_e_history ( + id integer not null, + test_string nvarchar(255), + constraint pk_migtest_e_history primary key (id) +); +create sequence migtest_e_history_seq as bigint start with 1 ; + +create table migtest_e_history2 ( + id integer not null, + test_string nvarchar(255), + constraint pk_migtest_e_history2 primary key (id) +); +create sequence migtest_e_history2_seq as bigint start with 1 ; + +create table migtest_e_ref ( + id integer not null, + name nvarchar(127) not null, + constraint pk_migtest_e_ref primary key (id) +); +alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); +create sequence migtest_e_ref_seq as bigint start with 1 ; + +create table migtest_e_softdelete ( + id integer not null, + test_string nvarchar(255), + constraint pk_migtest_e_softdelete primary key (id) +); +create sequence migtest_e_softdelete_seq as bigint start with 1 ; + +create table migtest_mtm_c ( + id integer not null, + name nvarchar(255), + constraint pk_migtest_mtm_c primary key (id) +); +create sequence migtest_mtm_c_seq as bigint start with 1 ; + +create table migtest_mtm_m ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_migtest_mtm_m primary key (id) +); +create sequence migtest_mtm_m_seq as bigint start with 1 ; + +create table migtest_oto_child ( + id integer not null, + name nvarchar(255), + constraint pk_migtest_oto_child primary key (id) +); +create sequence migtest_oto_child_seq as bigint start with 1 ; + +create table migtest_oto_master ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_migtest_oto_master primary key (id) +); +create sequence migtest_oto_master_seq as bigint start with 1 ; + +create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); +create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); +create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; + +create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; + +create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); + +alter table migtest_e_history2 + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table migtest_e_history2 set (system_versioning = on (history_table=dbo.migtest_e_history2_history)); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.1.sql new file mode 100644 index 000000000..90c1f96bf --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.1.sql @@ -0,0 +1,104 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create table migtest_e_user ( + id integer not null, + constraint pk_migtest_e_user primary key (id) +); +create sequence migtest_e_user_seq as bigint start with 1 ; + +create table migtest_mtm_c_migtest_mtm_m ( + migtest_mtm_c_id integer not null, + migtest_mtm_m_id numeric(19) not null, + constraint pk_migtest_mtm_c_migtest_mtm_m primary key (migtest_mtm_c_id,migtest_mtm_m_id) +); + +create table migtest_mtm_m_migtest_mtm_c ( + migtest_mtm_m_id numeric(19) not null, + migtest_mtm_c_id integer not null, + constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id) +); + +alter table migtest_ckey_detail add one_key integer; +alter table migtest_ckey_detail add two_key nvarchar(127); + +alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key); +alter table migtest_ckey_parent add assoc_id integer; + +IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id); +alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id); +alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id); +IF OBJECT_ID('fk_migtest_fk_set_null_one_id', 'F') IS NOT NULL alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id); + +update migtest_e_basic set status = 'A' where status is null; +IF (OBJECT_ID('ck_migtest_e_basic_status', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; +alter table migtest_e_basic add default 'A' for status; +alter table migtest_e_basic alter column status nvarchar(1) not null; +alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?')); + +-- rename all collisions; +create unique nonclustered index uq_migtest_e_basic_description on migtest_e_basic(description) where description is not null; + +update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null; +alter table migtest_e_basic add default '2000-01-01T00:00:00' for some_date; +alter table migtest_e_basic alter column some_date datetime2 not null; + +insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; +alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); +alter table migtest_e_basic alter column user_id integer; +alter table migtest_e_basic add new_string_field nvarchar(255) default 'foo''bar' not null; +alter table migtest_e_basic add new_boolean_field bit default 1 not null; +update migtest_e_basic set new_boolean_field = old_boolean; + +alter table migtest_e_basic add new_boolean_field2 bit default 1 not null; +alter table migtest_e_basic add progress integer default 0 not null; +alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); +alter table migtest_e_basic add new_integer integer default 42 not null; + +IF (OBJECT_ID('uq_migtest_e_basic_indextest2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest2') drop index uq_migtest_e_basic_indextest2 ON migtest_e_basic; +IF (OBJECT_ID('uq_migtest_e_basic_indextest6', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest6') drop index uq_migtest_e_basic_indextest6 ON migtest_e_basic; +create unique nonclustered index uq_migtest_e_basic_status_indextest1 on migtest_e_basic(status,indextest1) where indextest1 is not null; +create unique nonclustered index uq_migtest_e_basic_name on migtest_e_basic(name) where name is not null; +create unique nonclustered index uq_migtest_e_basic_indextest4 on migtest_e_basic(indextest4) where indextest4 is not null; +create unique nonclustered index uq_migtest_e_basic_indextest5 on migtest_e_basic(indextest5) where indextest5 is not null; +alter table migtest_e_history alter column test_string numeric(19); + +update migtest_e_history2 set test_string = 'unknown' where test_string is null; +alter table migtest_e_history2 add default 'unknown' for test_string; +alter table migtest_e_history2 alter column test_string nvarchar(255) not null; +alter table migtest_e_history2 add test_string2 nvarchar(255); +alter table migtest_e_history2 add test_string3 nvarchar(255) default 'unknown' not null; + +alter table migtest_e_softdelete add deleted bit default 0 not null; + +alter table migtest_oto_child add master_id numeric(19); + +create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); +create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest1') drop index ix_migtest_e_basic_indextest1 ON migtest_e_basic; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest5') drop index ix_migtest_e_basic_indextest5 ON migtest_e_basic; +create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); + +create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); + +create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); + +create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); + +create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id); + +alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id); + +alter table migtest_e_history + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table migtest_e_history set (system_versioning = on (history_table=dbo.migtest_e_history_history)); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/1.2__dropsFor_1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.2__dropsFor_1.1.sql new file mode 100644 index 000000000..d3a7a9a24 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.2__dropsFor_1.1.sql @@ -0,0 +1,43 @@ +-- Migrationscripts for ebean unittest +-- apply changes +-- drop column migtest_e_basic.old_boolean; +IF (OBJECT_ID('uq_migtest_e_basic_old_boolean', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_old_boolean; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_old_boolean') drop index uq_migtest_e_basic_old_boolean ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'old_boolean'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_old_boolean', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_old_boolean; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_old_boolean') drop index ix_migtest_e_basic_old_boolean ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_old_boolean', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_old_boolean; +alter table migtest_e_basic drop column old_boolean; + +-- drop column migtest_e_basic.old_boolean2; +IF (OBJECT_ID('uq_migtest_e_basic_old_boolean2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_old_boolean2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_old_boolean2') drop index uq_migtest_e_basic_old_boolean2 ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'old_boolean2'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_old_boolean2', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_old_boolean2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_old_boolean2') drop index ix_migtest_e_basic_old_boolean2 ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_old_boolean2', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_old_boolean2; +alter table migtest_e_basic drop column old_boolean2; + +-- drop column migtest_e_basic.eref_id; +IF (OBJECT_ID('uq_migtest_e_basic_eref_id', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_eref_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_eref_id') drop index uq_migtest_e_basic_eref_id ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'eref_id'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_eref_id', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_eref_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_eref_id') drop index ix_migtest_e_basic_eref_id ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_eref_id', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_eref_id; +alter table migtest_e_basic drop column eref_id; + +IF OBJECT_ID('migtest_e_ref', 'U') IS NOT NULL drop table migtest_e_ref; +IF OBJECT_ID('migtest_e_ref_seq', 'SO') IS NOT NULL drop sequence migtest_e_ref_seq; diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.3.sql new file mode 100644 index 000000000..50c300716 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.3.sql @@ -0,0 +1,62 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create table migtest_e_ref ( + id integer not null, + name nvarchar(127) not null, + constraint pk_migtest_e_ref primary key (id) +); +alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); +create sequence migtest_e_ref_seq as bigint start with 1 ; + +IF OBJECT_ID('fk_migtest_ckey_detail_parent', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_parent; +IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; +IF OBJECT_ID('fk_migtest_fk_none_one_id', 'F') IS NOT NULL alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id; +IF OBJECT_ID('fk_migtest_fk_none_via_join_one_id', 'F') IS NOT NULL alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id; +IF OBJECT_ID('fk_migtest_fk_set_null_one_id', 'F') IS NOT NULL alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; +IF (OBJECT_ID('ck_migtest_e_basic_status', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'status'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I')); +IF (OBJECT_ID('uq_migtest_e_basic_description', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_description; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_description') drop index uq_migtest_e_basic_description ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'some_date'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; + +update migtest_e_basic set user_id = 23 where user_id is null; +IF OBJECT_ID('fk_migtest_e_basic_user_id', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; +alter table migtest_e_basic add default 23 for user_id; +alter table migtest_e_basic alter column user_id integer not null; +alter table migtest_e_basic add old_boolean bit default 0 not null; +alter table migtest_e_basic add old_boolean2 bit; +alter table migtest_e_basic add eref_id integer; + +IF (OBJECT_ID('uq_migtest_e_basic_status_indextest1', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_status_indextest1; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_status_indextest1') drop index uq_migtest_e_basic_status_indextest1 ON migtest_e_basic; +IF (OBJECT_ID('uq_migtest_e_basic_name', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_name') drop index uq_migtest_e_basic_name ON migtest_e_basic; +IF (OBJECT_ID('uq_migtest_e_basic_indextest4', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest4; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest4') drop index uq_migtest_e_basic_indextest4 ON migtest_e_basic; +IF (OBJECT_ID('uq_migtest_e_basic_indextest5', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest5; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest5') drop index uq_migtest_e_basic_indextest5 ON migtest_e_basic; +create unique nonclustered index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) where indextest2 is not null; +create unique nonclustered index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) where indextest6 is not null; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string'; +if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; +create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); +create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest3') drop index ix_migtest_e_basic_indextest3 ON migtest_e_basic; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest6') drop index ix_migtest_e_basic_indextest6 ON migtest_e_basic; +create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); + diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/1.4__dropsFor_1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.4__dropsFor_1.3.sql new file mode 100644 index 000000000..50be4368d --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/1.4__dropsFor_1.3.sql @@ -0,0 +1,179 @@ +-- Migrationscripts for ebean unittest +-- apply changes +-- drop column migtest_ckey_detail.one_key; +IF (OBJECT_ID('uq_migtest_ckey_detail_one_key', 'UQ') IS NOT NULL) alter table migtest_ckey_detail drop constraint uq_migtest_ckey_detail_one_key; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'uq_migtest_ckey_detail_one_key') drop index uq_migtest_ckey_detail_one_key ON migtest_ckey_detail; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_ckey_detail') and t2.name = 'one_key'; +if @Tmp is not null EXEC('alter table migtest_ckey_detail drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_ckey_detail_one_key', 'C') IS NOT NULL) alter table migtest_ckey_detail drop constraint ck_migtest_ckey_detail_one_key; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'ix_migtest_ckey_detail_one_key') drop index ix_migtest_ckey_detail_one_key ON migtest_ckey_detail; +IF OBJECT_ID('fk_migtest_ckey_detail_one_key', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_one_key; +alter table migtest_ckey_detail drop column one_key; + +-- drop column migtest_ckey_detail.two_key; +IF (OBJECT_ID('uq_migtest_ckey_detail_two_key', 'UQ') IS NOT NULL) alter table migtest_ckey_detail drop constraint uq_migtest_ckey_detail_two_key; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'uq_migtest_ckey_detail_two_key') drop index uq_migtest_ckey_detail_two_key ON migtest_ckey_detail; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_ckey_detail') and t2.name = 'two_key'; +if @Tmp is not null EXEC('alter table migtest_ckey_detail drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_ckey_detail_two_key', 'C') IS NOT NULL) alter table migtest_ckey_detail drop constraint ck_migtest_ckey_detail_two_key; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'ix_migtest_ckey_detail_two_key') drop index ix_migtest_ckey_detail_two_key ON migtest_ckey_detail; +IF OBJECT_ID('fk_migtest_ckey_detail_two_key', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_two_key; +alter table migtest_ckey_detail drop column two_key; + +-- drop column migtest_ckey_parent.assoc_id; +IF (OBJECT_ID('uq_migtest_ckey_parent_assoc_id', 'UQ') IS NOT NULL) alter table migtest_ckey_parent drop constraint uq_migtest_ckey_parent_assoc_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_parent','U') AND name = 'uq_migtest_ckey_parent_assoc_id') drop index uq_migtest_ckey_parent_assoc_id ON migtest_ckey_parent; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_ckey_parent') and t2.name = 'assoc_id'; +if @Tmp is not null EXEC('alter table migtest_ckey_parent drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_ckey_parent_assoc_id', 'C') IS NOT NULL) alter table migtest_ckey_parent drop constraint ck_migtest_ckey_parent_assoc_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_parent','U') AND name = 'ix_migtest_ckey_parent_assoc_id') drop index ix_migtest_ckey_parent_assoc_id ON migtest_ckey_parent; +IF OBJECT_ID('fk_migtest_ckey_parent_assoc_id', 'F') IS NOT NULL alter table migtest_ckey_parent drop constraint fk_migtest_ckey_parent_assoc_id; +alter table migtest_ckey_parent drop column assoc_id; + +-- drop column migtest_e_basic.new_string_field; +IF (OBJECT_ID('uq_migtest_e_basic_new_string_field', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_string_field; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_string_field') drop index uq_migtest_e_basic_new_string_field ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_string_field'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_new_string_field', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_string_field; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_string_field') drop index ix_migtest_e_basic_new_string_field ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_new_string_field', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_string_field; +alter table migtest_e_basic drop column new_string_field; + +-- drop column migtest_e_basic.new_boolean_field; +IF (OBJECT_ID('uq_migtest_e_basic_new_boolean_field', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_boolean_field; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_boolean_field') drop index uq_migtest_e_basic_new_boolean_field ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_boolean_field'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_new_boolean_field', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_boolean_field; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_boolean_field') drop index ix_migtest_e_basic_new_boolean_field ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_new_boolean_field', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_boolean_field; +alter table migtest_e_basic drop column new_boolean_field; + +-- drop column migtest_e_basic.new_boolean_field2; +IF (OBJECT_ID('uq_migtest_e_basic_new_boolean_field2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_boolean_field2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_boolean_field2') drop index uq_migtest_e_basic_new_boolean_field2 ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_boolean_field2'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_new_boolean_field2', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_boolean_field2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_boolean_field2') drop index ix_migtest_e_basic_new_boolean_field2 ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_new_boolean_field2', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_boolean_field2; +alter table migtest_e_basic drop column new_boolean_field2; + +-- drop column migtest_e_basic.progress; +IF (OBJECT_ID('uq_migtest_e_basic_progress', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_progress; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_progress') drop index uq_migtest_e_basic_progress ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'progress'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_progress', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_progress; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_progress') drop index ix_migtest_e_basic_progress ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_progress', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_progress; +alter table migtest_e_basic drop column progress; + +-- drop column migtest_e_basic.new_integer; +IF (OBJECT_ID('uq_migtest_e_basic_new_integer', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_integer; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_integer') drop index uq_migtest_e_basic_new_integer ON migtest_e_basic; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_integer'; +if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_basic_new_integer', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_integer; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_integer') drop index ix_migtest_e_basic_new_integer ON migtest_e_basic; +IF OBJECT_ID('fk_migtest_e_basic_new_integer', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_integer; +alter table migtest_e_basic drop column new_integer; + +-- drop column migtest_e_history2.test_string2; +IF (OBJECT_ID('uq_migtest_e_history2_test_string2', 'UQ') IS NOT NULL) alter table migtest_e_history2 drop constraint uq_migtest_e_history2_test_string2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'uq_migtest_e_history2_test_string2') drop index uq_migtest_e_history2_test_string2 ON migtest_e_history2; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string2'; +if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_history2_test_string2', 'C') IS NOT NULL) alter table migtest_e_history2 drop constraint ck_migtest_e_history2_test_string2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'ix_migtest_e_history2_test_string2') drop index ix_migtest_e_history2_test_string2 ON migtest_e_history2; +IF OBJECT_ID('fk_migtest_e_history2_test_string2', 'F') IS NOT NULL alter table migtest_e_history2 drop constraint fk_migtest_e_history2_test_string2; +alter table migtest_e_history2 drop column test_string2; + +-- drop column migtest_e_history2.test_string3; +IF (OBJECT_ID('uq_migtest_e_history2_test_string3', 'UQ') IS NOT NULL) alter table migtest_e_history2 drop constraint uq_migtest_e_history2_test_string3; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'uq_migtest_e_history2_test_string3') drop index uq_migtest_e_history2_test_string3 ON migtest_e_history2; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string3'; +if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_history2_test_string3', 'C') IS NOT NULL) alter table migtest_e_history2 drop constraint ck_migtest_e_history2_test_string3; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'ix_migtest_e_history2_test_string3') drop index ix_migtest_e_history2_test_string3 ON migtest_e_history2; +IF OBJECT_ID('fk_migtest_e_history2_test_string3', 'F') IS NOT NULL alter table migtest_e_history2 drop constraint fk_migtest_e_history2_test_string3; +alter table migtest_e_history2 drop column test_string3; + +-- drop column migtest_e_softdelete.deleted; +IF (OBJECT_ID('uq_migtest_e_softdelete_deleted', 'UQ') IS NOT NULL) alter table migtest_e_softdelete drop constraint uq_migtest_e_softdelete_deleted; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_softdelete','U') AND name = 'uq_migtest_e_softdelete_deleted') drop index uq_migtest_e_softdelete_deleted ON migtest_e_softdelete; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_softdelete') and t2.name = 'deleted'; +if @Tmp is not null EXEC('alter table migtest_e_softdelete drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_e_softdelete_deleted', 'C') IS NOT NULL) alter table migtest_e_softdelete drop constraint ck_migtest_e_softdelete_deleted; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_softdelete','U') AND name = 'ix_migtest_e_softdelete_deleted') drop index ix_migtest_e_softdelete_deleted ON migtest_e_softdelete; +IF OBJECT_ID('fk_migtest_e_softdelete_deleted', 'F') IS NOT NULL alter table migtest_e_softdelete drop constraint fk_migtest_e_softdelete_deleted; +alter table migtest_e_softdelete drop column deleted; + +-- drop column migtest_oto_child.master_id; +IF (OBJECT_ID('uq_migtest_oto_child_master_id', 'UQ') IS NOT NULL) alter table migtest_oto_child drop constraint uq_migtest_oto_child_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_oto_child','U') AND name = 'uq_migtest_oto_child_master_id') drop index uq_migtest_oto_child_master_id ON migtest_oto_child; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_oto_child') and t2.name = 'master_id'; +if @Tmp is not null EXEC('alter table migtest_oto_child drop constraint ' + @Tmp)$$; +IF (OBJECT_ID('ck_migtest_oto_child_master_id', 'C') IS NOT NULL) alter table migtest_oto_child drop constraint ck_migtest_oto_child_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_oto_child','U') AND name = 'ix_migtest_oto_child_master_id') drop index ix_migtest_oto_child_master_id ON migtest_oto_child; +IF OBJECT_ID('fk_migtest_oto_child_master_id', 'F') IS NOT NULL alter table migtest_oto_child drop constraint fk_migtest_oto_child_master_id; +alter table migtest_oto_child drop column master_id; + +IF OBJECT_ID('migtest_e_user', 'U') IS NOT NULL drop table migtest_e_user; +IF OBJECT_ID('migtest_e_user_seq', 'SO') IS NOT NULL drop sequence migtest_e_user_seq; +IF OBJECT_ID('migtest_mtm_c_migtest_mtm_m', 'U') IS NOT NULL drop table migtest_mtm_c_migtest_mtm_m; +IF OBJECT_ID('migtest_mtm_m_migtest_mtm_c', 'U') IS NOT NULL drop table migtest_mtm_m_migtest_mtm_c; +-- dropping history support for migtest_e_history; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_history') and t2.name = 'sys_periodFrom'; +if @Tmp is not null EXEC('alter table migtest_e_history drop constraint ' + @Tmp)$$; +delimiter $$ +DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 + join sys.columns t2 on t1.object_id = t2.default_object_id + where t1.parent_object_id = OBJECT_ID('migtest_e_history') and t2.name = 'sys_periodTo'; +if @Tmp is not null EXEC('alter table migtest_e_history drop constraint ' + @Tmp)$$; +alter table migtest_e_history set (system_versioning = off); +alter table migtest_e_history drop period for system_time; +alter table migtest_e_history drop column sys_periodFrom; +alter table migtest_e_history drop column sys_periodTo; +IF OBJECT_ID('migtest_e_history_history', 'U') IS NOT NULL drop table migtest_e_history_history; + From f840cfc2ae2ec15f23d788b5486c3b86c9c808dd Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:40:11 +1300 Subject: [PATCH 0162/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). test changes --- src/test/java/io/ebean/BaseTestCase.java | 2 +- .../java/io/ebean/ConditionalTestRunner.java | 4 + .../java/io/ebean/DtoQueryFromOrmTest.java | 14 +- .../config/MatchingNamingConventionTest.java | 4 +- .../config/ServerConfigSqlServerTest.java | 134 ++++++++++++++++++ .../dbplatform/DatabasePlatformTest.java | 8 +- .../sqlserver/SqlServer2016PlatformTest.java | 4 +- .../dbmigration/DbMigrationSqlServerTest.java | 28 ++++ .../ebean/event/BeanFindControllerTest.java | 11 +- .../dbmigration/DbMigrationGenerateTest.java | 11 +- .../ddlgeneration/BaseDdlHandlerTest.java | 6 +- .../platform/PlatformDdl_AlterColumnTest.java | 6 +- .../PlatformDdl_dropUniqueConstraintTest.java | 4 +- .../extraddl/model/ExtraDdlXmlReaderTest.java | 37 ++++- .../aggregation/TestAggregationCount.java | 12 +- .../TestExplicitTransactionMode.java | 5 + src/test/resources/ebean.properties | 8 +- 17 files changed, 260 insertions(+), 38 deletions(-) create mode 100644 src/test/java/io/ebean/config/ServerConfigSqlServerTest.java create mode 100644 src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index bdef878cf..16e4ef45d 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -93,7 +93,7 @@ public abstract class BaseTestCase { * so tests that do this need to be skipped for SQL Server. */ public boolean isSqlServer() { - return Platform.SQLSERVER == platform(); + return Platform.SQLSERVER17 == platform(); } public boolean isH2() { diff --git a/src/test/java/io/ebean/ConditionalTestRunner.java b/src/test/java/io/ebean/ConditionalTestRunner.java index b70f572f0..c60b46b73 100644 --- a/src/test/java/io/ebean/ConditionalTestRunner.java +++ b/src/test/java/io/ebean/ConditionalTestRunner.java @@ -42,6 +42,10 @@ public class ConditionalTestRunner extends BlockJUnit4ClassRunner { if (p.equals(current)) { return true; } + if (p == Platform.SQLSERVER && current == Platform.SQLSERVER17) { + // treat SQLSERVER as SQLSERVER17 in testing + return true; + } } return false; } diff --git a/src/test/java/io/ebean/DtoQueryFromOrmTest.java b/src/test/java/io/ebean/DtoQueryFromOrmTest.java index af22c17c6..c72cfa330 100644 --- a/src/test/java/io/ebean/DtoQueryFromOrmTest.java +++ b/src/test/java/io/ebean/DtoQueryFromOrmTest.java @@ -142,7 +142,13 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + if (isSqlServer()) { + assertThat(sql.get(0)).contains("select top 10 t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + + } else { + assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } } @Test @@ -171,7 +177,11 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + if (isSqlServer()) { + assertThat(sql.get(0)).contains("select top 10 t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } else { + assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + } } @Test diff --git a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java index 2cca6c06d..677b572e7 100644 --- a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java +++ b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java @@ -1,7 +1,7 @@ package io.ebean.config; import io.ebean.config.dbplatform.h2.H2Platform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import org.junit.Test; import static org.assertj.core.api.StrictAssertions.assertThat; @@ -18,7 +18,7 @@ public class MatchingNamingConventionTest { @Test public void getColumnFromProperty_when_allQuoted() { - SqlServerPlatform platform = new SqlServerPlatform(); + SqlServer17Platform platform = new SqlServer17Platform(); ServerConfig config = new ServerConfig(); config.setAllQuotedIdentifiers(true); diff --git a/src/test/java/io/ebean/config/ServerConfigSqlServerTest.java b/src/test/java/io/ebean/config/ServerConfigSqlServerTest.java new file mode 100644 index 000000000..7e3e73bba --- /dev/null +++ b/src/test/java/io/ebean/config/ServerConfigSqlServerTest.java @@ -0,0 +1,134 @@ +package io.ebean.config; + + +import io.ebean.EbeanServer; +import io.ebean.EbeanServerFactory; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; +import org.junit.Ignore; +import org.junit.Test; +import org.tests.model.basic.EBasicVer; + +import javax.persistence.PersistenceException; +import java.util.Properties; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ServerConfigSqlServerTest { + + @Ignore + @ForPlatform({Platform.SQLSERVER, Platform.SQLSERVER17, Platform.SQLSERVER16}) + @Test(expected = PersistenceException.class) + public void need_explicitPlatform() { + + Properties props = props("some_sqlserver"); + + // no explicit databasePlatformName set .. + //props.setProperty("ebean.some_sqlserver.databasePlatformName", "sqlserver17"); + + ServerConfig config = new ServerConfig(); + config.setName("some_sqlserver"); + config.loadFromProperties(props); + + // not explicitly set ... so we fail to start +// config.setDatabasePlatform(new SqlServer17Platform()); +// config.setDatabasePlatformName("sqlserver17"); + + config.setDefaultServer(false); + config.setRegister(false); + config.getClasses().add(EBasicVer.class); + + EbeanServer sqlServer = EbeanServerFactory.create(config); + + assertThat(sqlServer).isNotNull(); + +// javax.persistence.PersistenceException: java.lang.IllegalArgumentException: For SqlServer please choose the more specific sqlserver16 or sqlserver17 platform via ServerConfig.setDatabasePlatformName. Refer to issue #1340 for details +// +// at io.ebeaninternal.server.core.DatabasePlatformFactory.create(DatabasePlatformFactory.java:62) +// at io.ebeaninternal.server.core.DefaultContainer.setDatabasePlatform(DefaultContainer.java:266) +// at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:126) +// at io.ebeaninternal.server.core.DefaultContainer.createServer(DefaultContainer.java:45) +// at io.ebean.EbeanServerFactory.createInternal(EbeanServerFactory.java:109) +// at io.ebean.EbeanServerFactory.create(EbeanServerFactory.java:70) +// at io.ebean.config.ServerConfigSqlServerTest.need_explicitPlatform(ServerConfigSqlServerTest.java:35) + + } + + @Ignore + @ForPlatform({Platform.SQLSERVER, Platform.SQLSERVER17, Platform.SQLSERVER16}) + @Test + public void explicit_17() { + + String name = "testsqlserver17"; + + ServerConfig config = new ServerConfig(); + config.setName(name); + + Properties props = props(name); + + // set via properties + //props.setProperty("ebean.testsqlserver17.databasePlatformName", "sqlserver17"); + + // or set programmatically ... + config.setDatabasePlatformName("sqlserver17"); + + config.setDefaultServer(false); + config.setRegister(false); + config.setDdlGenerate(true); + config.setDdlRun(true); + config.loadFromProperties(props); + config.getClasses().add(EBasicVer.class); + + EbeanServer sqlServer = EbeanServerFactory.create(config); + + assertThat(sqlServer).isNotNull(); + } + + @Ignore + @ForPlatform({Platform.SQLSERVER, Platform.SQLSERVER17, Platform.SQLSERVER16}) + @Test + public void explicit_16() { + + String name = "testsqlserver16"; + Properties props = props(name); + //props.setProperty("ebean.testsqlserver16.databasePlatformName", "sqlserver16"); + + ServerConfig config = new ServerConfig(); + config.setDefaultServer(false); + config.setRegister(false); + config.setDdlGenerate(true); + config.setDdlRun(true); + + config.setName(name); // match dataSource + config.setDatabasePlatformName("sqlserver16"); + config.loadFromProperties(props); + config.getClasses().add(EBasicVer.class); + + EbeanServer sqlServer = EbeanServerFactory.create(config); + + assertThat(sqlServer).isNotNull(); + } + + private Properties props(String dbName) { + + Properties props = new Properties(); + + // automatically start docker sqlserver 2017 container ... + props.setProperty("ebean.test.platform", "sqlserver"); + props.setProperty("ebean.test.dbName", "test_ebean"); + props.setProperty("ebean.test.ddlMode", "dropCreate"); + //props.setProperty("ebean.test.containerMode","dropCreate"); + + + props.setProperty(key(dbName, "username"), "test_ebean"); + props.setProperty(key(dbName, "password"), "SqlS3rv#r"); + props.setProperty(key(dbName, "url"), "jdbc:sqlserver://localhost:1433;databaseName=test_ebean"); + props.setProperty(key(dbName, "driver"), "com.microsoft.sqlserver.jdbc.SQLServerDriver"); + + return props; + } + + private String key(String dbName, String key) { + return "datasource." + dbName + "." + key; + } +} diff --git a/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java b/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java index 65fe0426e..a1e9de455 100644 --- a/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java @@ -1,12 +1,12 @@ package io.ebean.config.dbplatform; -import io.ebean.config.DbTypeConfig; import io.ebean.annotation.Platform; +import io.ebean.config.DbTypeConfig; import io.ebean.config.MatchingNamingConvention; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -20,7 +20,7 @@ public class DatabasePlatformTest { config.setAllQuotedIdentifiers(true); config.setNamingConvention(new MatchingNamingConvention()); - DatabasePlatform dbPlatform = new SqlServerPlatform(); + DatabasePlatform dbPlatform = new SqlServer17Platform(); dbPlatform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); assertEquals(dbPlatform.convertQuotedIdentifiers("order"),"[order]"); @@ -33,7 +33,7 @@ public class DatabasePlatformTest { ServerConfig config = new ServerConfig(); - DatabasePlatform dbPlatform = new SqlServerPlatform(); + DatabasePlatform dbPlatform = new SqlServer17Platform(); dbPlatform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); assertEquals(dbPlatform.convertQuotedIdentifiers("order"),"order"); diff --git a/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServer2016PlatformTest.java b/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServer2016PlatformTest.java index c6efddc6a..092adcebe 100644 --- a/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServer2016PlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/sqlserver/SqlServer2016PlatformTest.java @@ -2,7 +2,7 @@ package io.ebean.config.dbplatform.sqlserver; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertTrue; /** * @author Vilmos Nagy @@ -11,7 +11,7 @@ public class SqlServer2016PlatformTest { @Test public void testHistorySupport() { - SqlServerPlatform platform = new SqlServerPlatform(); + SqlServer17Platform platform = new SqlServer17Platform(); assertTrue(platform.getHistorySupport() instanceof SqlServerHistorySupport); } } diff --git a/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java b/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java new file mode 100644 index 000000000..84249a1d4 --- /dev/null +++ b/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java @@ -0,0 +1,28 @@ +package io.ebean.dbmigration; + +import io.ebean.annotation.Platform; +import org.junit.Test; + +public class DbMigrationSqlServerTest { + + @Test(expected = IllegalArgumentException.class) + public void need_explicitPlatform() { + + DbMigration dbMigration = DbMigration.create(); + dbMigration.setPlatform(Platform.SQLSERVER); + } + + @Test + public void explicit_16_isGood() { + + DbMigration dbMigration = DbMigration.create(); + dbMigration.setPlatform(Platform.SQLSERVER16); + } + + @Test + public void explicit_17_isGood() { + + DbMigration dbMigration = DbMigration.create(); + dbMigration.setPlatform(Platform.SQLSERVER17); + } +} diff --git a/src/test/java/io/ebean/event/BeanFindControllerTest.java b/src/test/java/io/ebean/event/BeanFindControllerTest.java index 0d21ffda1..c47d5edca 100644 --- a/src/test/java/io/ebean/event/BeanFindControllerTest.java +++ b/src/test/java/io/ebean/event/BeanFindControllerTest.java @@ -6,14 +6,17 @@ import io.ebean.EbeanServerFactory; import io.ebean.bean.BeanCollection; import io.ebean.common.BeanList; import io.ebean.config.ServerConfig; +import org.junit.Test; +import org.tests.example.ModUuidGenerator; import org.tests.model.basic.EBasic; import org.tests.model.basic.ECustomId; -import org.tests.example.ModUuidGenerator; -import org.junit.Test; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class BeanFindControllerTest extends BaseTestCase { @@ -39,6 +42,8 @@ public class BeanFindControllerTest extends BaseTestCase { EbeanServer ebeanServer = EbeanServerFactory.create(config); + System.clearProperty("ebean.ignoreExtraDdl"); + assertFalse(findController.calledInterceptFind); ebeanServer.find(EBasic.class, 42); assertTrue(findController.calledInterceptFind); diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java index 6d16f0d1c..4966011b6 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java @@ -6,20 +6,19 @@ import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.IdType; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; - -import org.junit.*; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; +import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.assertj.core.api.Assertions.assertThat; - import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import static org.assertj.core.api.Assertions.assertThat; + /** * This is the Migrationscript generator. It generates 3 migrationscript for the models @@ -57,7 +56,7 @@ public class DbMigrationGenerateTest { migration.addPlatform(Platform.SQLITE, "sqlite"); // we need sequence here, so that migration will work properly - DatabasePlatform sqlServer = new SqlServerPlatform(); + DatabasePlatform sqlServer = new SqlServer17Platform(); sqlServer.getDbIdentity().setIdType(IdType.SEQUENCE); migration.addDatabasePlatform(sqlServer, "sqlserver"); diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java index 210e8195c..e185e8df7 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java @@ -6,7 +6,7 @@ import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.migration.ChangeSet; import io.ebeaninternal.dbmigration.model.CurrentModel; @@ -34,7 +34,7 @@ public class BaseDdlHandlerTest extends BaseTestCase { } private DdlHandler sqlserverHandler() { - return handler(new SqlServerPlatform()); + return handler(new SqlServer17Platform()); } @Test @@ -46,7 +46,7 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAddColumn()); - assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add added_to_foo varchar(20);\n\n"); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add added_to_foo nvarchar(20);\n\n"); } @Test diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java index 2f22d5c51..5cd6e6a1d 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java @@ -7,7 +7,7 @@ import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.dbmigration.migration.AlterColumn; import io.ebeaninternal.dbmigration.migration.IdentityType; import io.ebeaninternal.server.core.PlatformDdlBuilder; @@ -23,7 +23,7 @@ public class PlatformDdl_AlterColumnTest { private PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform()); private PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); private PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform()); - private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServerPlatform()); + private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform()); { ServerConfig serverConfig = Ebean.getDefaultServer().getPluginApi().getServerConfig(); @@ -76,7 +76,7 @@ public class PlatformDdl_AlterColumnTest { assertEquals("alter table mytab modify acol varchar(5) not null", sql); sql = sqlServerDdl.alterColumnBaseAttributes(alterColumn); - assertEquals("alter table mytab alter column acol varchar(5) not null", sql); + assertEquals("alter table mytab alter column acol nvarchar(5) not null", sql); alterColumn.setNotnull(Boolean.FALSE); sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java index f7fd62cbe..e68ece07c 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java @@ -1,10 +1,10 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; import io.ebean.config.dbplatform.h2.H2Platform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.server.core.PlatformDdlBuilder; import org.junit.Test; @@ -17,7 +17,7 @@ public class PlatformDdl_dropUniqueConstraintTest { private PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform()); private PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); private PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform()); - private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServerPlatform()); + private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform()); @Test public void test() throws Exception { diff --git a/src/test/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReaderTest.java b/src/test/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReaderTest.java index 440e889c0..364fa32a9 100644 --- a/src/test/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReaderTest.java +++ b/src/test/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReaderTest.java @@ -3,12 +3,14 @@ package io.ebeaninternal.extraddl.model; import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class ExtraDdlXmlReaderTest { @Test - public void read() throws Exception { + public void read(){ ExtraDdl read = ExtraDdlXmlReader.read("/extra-ddl.xml"); assertNotNull(read); @@ -44,4 +46,37 @@ public class ExtraDdlXmlReaderTest { assertThat(ddl).doesNotContain(" -- oracle only script"); } + @Test + public void matchPlatform() { + + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "h2")); + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "mysql,h2")); + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "mysql,h2,")); + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "mysql , h2 ,")); + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "mysql , h2, oracle")); + assertTrue(ExtraDdlXmlReader.matchPlatform("h2", "mysql , h2, oracle")); + + assertTrue(ExtraDdlXmlReader.matchPlatform("sqlserver17", "sqlserver17")); + assertTrue(ExtraDdlXmlReader.matchPlatform("sqlserver16", "sqlserver16")); + } + + @Test + public void matchPlatform_sqlserver17_matchAlsoToGenericName() { + + assertTrue(ExtraDdlXmlReader.matchPlatform("sqlserver17", "sqlserver")); + } + + @Test + public void matchPlatform_sqlserver16_matchAlsoToGenericName() { + + assertTrue(ExtraDdlXmlReader.matchPlatform("sqlserver16", "sqlserver")); + } + + @Test + public void matchPlatform_sqlserver_nonMatch() { + + assertFalse(ExtraDdlXmlReader.matchPlatform("sqlserver16", "sqlserver17")); + assertFalse(ExtraDdlXmlReader.matchPlatform("sqlserver17", "sqlserver16")); + } + } diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index dcbdcdf1e..3c027b662 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -351,7 +351,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(maxLastName).isNotNull(); List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select max(t0.last_name) from contact t0"); + assertThat(trimSql(sql.get(0))).contains("select max(t0.last_name) from contact t0"); } @Test @@ -370,7 +370,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(count).isNotNull(); List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select count(distinct t0.last_name) from contact t0 where not exists (select 1 from contact_note x where x.contact_id = t0.id)"); + assertThat(trimSql(sql.get(0))).contains("select count(distinct t0.last_name) from contact t0 where not exists (select 1 from contact_note x where x.contact_id = t0.id)"); } @Test @@ -391,7 +391,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(names).isNotEmpty(); List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select concat(t0.last_name,', ',t0.first_name) from contact t0 where t0.phone is null order by t0.last_name"); + assertThat(trimSql(sql.get(0))).contains("select concat(t0.last_name,', ',t0.first_name) from contact t0 where t0.phone is null order by t0.last_name"); } @Test @@ -412,7 +412,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(names).isNotEmpty(); List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select concat(t0.updtime,', ',t0.first_name) from contact t0"); + assertThat(trimSql(sql.get(0))).contains("select concat(t0.updtime,', ',t0.first_name) from contact t0"); } @Test @@ -432,7 +432,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(instant).isNotNull(); List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select max(t0.updtime) from contact t0 where t0.phone is null"); + assertThat(trimSql(sql.get(0))).contains("select max(t0.updtime) from contact t0 where t0.phone is null"); } @@ -459,7 +459,7 @@ public class TestAggregationCount extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) lastName from contact t0 where t0.phone is null order by t0.last_name; --bind()"); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) lastName from contact t0 where t0.phone is null order by t0.last_name; --bind()"); } } diff --git a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java index 59ebdd121..2d0bb7abf 100644 --- a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java +++ b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java @@ -5,6 +5,8 @@ import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; import io.ebean.Query; import io.ebean.Transaction; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import io.ebean.config.properties.PropertiesLoader; import org.avaje.datasource.DataSourceConfig; @@ -24,6 +26,7 @@ import static org.junit.Assert.assertTrue; public class TestExplicitTransactionMode extends BaseTestCase { + @ForPlatform(Platform.H2) @Test public void test() throws SQLException { @@ -56,6 +59,8 @@ public class TestExplicitTransactionMode extends BaseTestCase { EbeanServer ebeanServer = EbeanServerFactory.create(config); + System.clearProperty("ebean.ignoreExtraDdl"); + Query query = ebeanServer.find(UTMaster.class); List details = ebeanServer.findList(query, null); assertEquals(0, details.size()); diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 99522c35b..7f8ed9918 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -15,12 +15,11 @@ ebean.encryptKeyManager=org.tests.basic.encrypt.BasicEncyptKeyManager #ebean.autotune.profiling=true #ebean.autotune.profilingUpdateFrequency=5 -#ebean.sqlserver.ddl.createOnly=true ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests -datasource.default=h2 +datasource.default=sqlserver ebean.autoReadOnlyDataSource=true @@ -134,7 +133,10 @@ datasource.pg.databaseDriver=org.postgresql.Driver #datasource.pg.capturestacktrace=true datasource.pg.maxStackTraceSize=50 -ebean.sqlserver.idType=SEQUENCE +#ebean.sqlserver.idType=SEQUENCE +# Our main testing target for SqlServer is sqlserver17 +ebean.sqlserver.databasePlatformName=sqlserver17 + datasource.sqlserver.username=test_ebean datasource.sqlserver.password=SqlS3rv#r datasource.sqlserver.databaseUrl=jdbc:sqlserver://localhost:1433;databaseName=test_ebean From 5a3550e603ba7de7118188bb7a5321f06c5a7456 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:43:25 +1300 Subject: [PATCH 0163/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Unrelated - update dbmigration ddl for create index / add fk change in order (db2) --- .../dbmigration/migrationtest/db2/1.0__initial.sql | 6 +++--- .../resources/dbmigration/migrationtest/db2/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/db2/1.3.sql | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql index b21ec7c7f..2a123be20 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.0__initial.sql @@ -127,12 +127,12 @@ create table migtest_oto_master ( create index ix_mgtst__b_eu8csq on migtest_e_basic (indextest1); create index ix_mgtst__b_eu8csu on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_mgtst_fk_65kf6l foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; create index ix_mgtst_fk_mok1xj on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_mgtst_fk_65kf6l foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; -alter table migtest_fk_set_null add constraint fk_mgtst_fk_wicx8x foreign key (one_id) references migtest_fk_one (id) on delete set null; create index ix_mgtst_fk_c4p3mv on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_mgtst_fk_wicx8x foreign key (one_id) references migtest_fk_one (id) on delete set null; -alter table migtest_e_basic add constraint fk_mgtst__bsc_rf_d foreign key (eref_id) references migtest_e_ref (id) on delete restrict; create index ix_mgtst__bsc_rf_d on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_mgtst__bsc_rf_d foreign key (eref_id) references migtest_e_ref (id) on delete restrict; diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.1.sql b/src/test/resources/dbmigration/migrationtest/db2/1.1.sql index c3856edfa..776e7945f 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.1.sql @@ -81,20 +81,20 @@ create index ix_mgtst__b_eu8css on migtest_e_basic (indextest3); create index ix_mgtst__b_eu8csv on migtest_e_basic (indextest6); drop index ix_mgtst__b_eu8csq; drop index ix_mgtst__b_eu8csu; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mt_93awga foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict; create index ix_mgtst_mt_3ug4ok on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mt_93awga foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mt_93awgk foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict; create index ix_mgtst_mt_3ug4ou on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mt_93awgk foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mt_ggi34k foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict; create index ix_mgtst_mt_b7nbcu on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mt_ggi34k foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mt_ggi34a foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict; create index ix_mgtst_mt_b7nbck on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mt_ggi34a foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict; -alter table migtest_ckey_parent add constraint fk_mgtst_ck_da00mr foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict; create index ix_mgtst_ck_x45o21 on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_mgtst_ck_da00mr foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict; alter table migtest_oto_child add constraint fk_mgtst_t__csyl38 foreign key (master_id) references migtest_oto_master (id) on delete restrict; diff --git a/src/test/resources/dbmigration/migrationtest/db2/1.3.sql b/src/test/resources/dbmigration/migrationtest/db2/1.3.sql index 17e6a31d1..a9e2d7622 100644 --- a/src/test/resources/dbmigration/migrationtest/db2/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/db2/1.3.sql @@ -44,6 +44,6 @@ create index ix_mgtst__b_eu8csq on migtest_e_basic (indextest1); create index ix_mgtst__b_eu8csu on migtest_e_basic (indextest5); drop index ix_mgtst__b_eu8css; drop index ix_mgtst__b_eu8csv; -alter table migtest_e_basic add constraint fk_mgtst__bsc_rf_d foreign key (eref_id) references migtest_e_ref (id) on delete restrict; create index ix_mgtst__bsc_rf_d on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_mgtst__bsc_rf_d foreign key (eref_id) references migtest_e_ref (id) on delete restrict; From d84cdab71408b1d486f55a1f428bedfd3c59e8c8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 17:45:19 +1300 Subject: [PATCH 0164/1036] #1340 - Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Only need to run H2 based test TestAutoCommitDataSource with H2 --- .../java/org/tests/transaction/TestAutoCommitDataSource.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java b/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java index 28ab7d2f0..19db621d5 100644 --- a/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java +++ b/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java @@ -5,6 +5,8 @@ import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; import io.ebean.Query; import io.ebean.Transaction; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import io.ebean.config.properties.PropertiesLoader; import org.avaje.datasource.DataSourceConfig; @@ -24,6 +26,7 @@ import static org.junit.Assert.assertTrue; public class TestAutoCommitDataSource extends BaseTestCase { + @ForPlatform({Platform.H2, Platform.POSTGRES}) @Test public void test() throws SQLException { From 824f5e468e21487f80d0a11f79982477a9651cb5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 18:18:13 +1300 Subject: [PATCH 0165/1036] #1340 - (test only change) Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Reset Offline platform in DbMigrationSqlServerTest --- .../ebean/dbmigration/DbMigrationSqlServerTest.java | 11 +++++++++-- .../transaction/TestExplicitTransactionMode.java | 6 +++--- src/test/resources/ebean.properties | 8 +++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java b/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java index 84249a1d4..286e3525a 100644 --- a/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java +++ b/src/test/java/io/ebean/dbmigration/DbMigrationSqlServerTest.java @@ -1,6 +1,7 @@ package io.ebean.dbmigration; import io.ebean.annotation.Platform; +import io.ebeaninternal.dbmigration.DbOffline; import org.junit.Test; public class DbMigrationSqlServerTest { @@ -8,8 +9,12 @@ public class DbMigrationSqlServerTest { @Test(expected = IllegalArgumentException.class) public void need_explicitPlatform() { - DbMigration dbMigration = DbMigration.create(); - dbMigration.setPlatform(Platform.SQLSERVER); + try { + DbMigration dbMigration = DbMigration.create(); + dbMigration.setPlatform(Platform.SQLSERVER); + } finally { + DbOffline.reset(); + } } @Test @@ -17,6 +22,7 @@ public class DbMigrationSqlServerTest { DbMigration dbMigration = DbMigration.create(); dbMigration.setPlatform(Platform.SQLSERVER16); + DbOffline.reset(); } @Test @@ -24,5 +30,6 @@ public class DbMigrationSqlServerTest { DbMigration dbMigration = DbMigration.create(); dbMigration.setPlatform(Platform.SQLSERVER17); + DbOffline.reset(); } } diff --git a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java index 2d0bb7abf..e7614619b 100644 --- a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java +++ b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java @@ -33,10 +33,10 @@ public class TestExplicitTransactionMode extends BaseTestCase { Properties properties = PropertiesLoader.load(); DataSourceConfig dsConfig = new DataSourceConfig(); - dsConfig.loadSettings(properties, "h2autocommit");//"h2autocommit","pg" + dsConfig.loadSettings(properties, "h2autocommit2"); dsConfig.setAutoCommit(true); - DataSourcePool pool = new ConnectionPool("h2autocommit", dsConfig); + DataSourcePool pool = new ConnectionPool("h2autocommit2", dsConfig); Connection connection = pool.getConnection(); assertTrue(connection.getAutoCommit()); @@ -45,7 +45,7 @@ public class TestExplicitTransactionMode extends BaseTestCase { System.setProperty("ebean.ignoreExtraDdl", "true"); ServerConfig config = new ServerConfig(); - config.setName("h2autocommit"); + config.setName("h2autocommit2"); config.loadFromProperties(); config.setDataSource(pool); config.setDefaultServer(false); diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 7f8ed9918..4b6fb04e4 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -19,7 +19,7 @@ ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests -datasource.default=sqlserver +datasource.default=h2 ebean.autoReadOnlyDataSource=true @@ -80,6 +80,12 @@ datasource.h2autocommit.password= datasource.h2autocommit.databaseUrl=jdbc:h2:mem:autocommittests datasource.h2autocommit.databaseDriver=org.h2.Driver +datasource.h2autocommit2.autoCommit=true +datasource.h2autocommit2.username=sa +datasource.h2autocommit2.password= +datasource.h2autocommit2.databaseUrl=jdbc:h2:mem:autocommit2tests +datasource.h2autocommit2.databaseDriver=org.h2.Driver + datasource.h2other.username=sa datasource.h2other.password= datasource.h2other.databaseUrl=jdbc:h2:mem:h2other From ef58954af51ad608dbbd202e1564bc5703efc6da Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 18:31:12 +1300 Subject: [PATCH 0166/1036] Test only changes - related to #1336 - Change DDL generation such that it does create index before alter table add foreign key --- .../dbmigration/migrationtest/h2/1.0__initial.sql | 6 +++--- .../resources/dbmigration/migrationtest/h2/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/h2/1.3.sql | 2 +- .../dbmigration/migrationtest/hsqldb/1.0__initial.sql | 6 +++--- .../resources/dbmigration/migrationtest/hsqldb/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/hsqldb/1.3.sql | 2 +- .../dbmigration/migrationtest/mysql/1.0__initial.sql | 6 +++--- .../resources/dbmigration/migrationtest/mysql/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/mysql/1.3.sql | 2 +- .../dbmigration/migrationtest/oracle/1.0__initial.sql | 6 +++--- .../resources/dbmigration/migrationtest/oracle/1.1.sql | 10 +++++----- .../resources/dbmigration/migrationtest/oracle/1.3.sql | 2 +- .../migrationtest/postgres/1.0__initial.sql | 6 +++--- .../dbmigration/migrationtest/postgres/1.1.sql | 10 +++++----- .../dbmigration/migrationtest/postgres/1.3.sql | 2 +- 15 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql index 4b6052a9a..9d4204f43 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.0__initial.sql @@ -127,14 +127,14 @@ create table migtest_oto_master ( create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; alter table migtest_e_history2 add column sys_period_start datetime(6) default now(6); alter table migtest_e_history2 add column sys_period_end datetime(6); diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.1.sql b/src/test/resources/dbmigration/migrationtest/h2/1.1.sql index 126c0eb18..9f633b46c 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.1.sql @@ -81,20 +81,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); drop index if exists ix_migtest_e_basic_indextest1; drop index if exists ix_migtest_e_basic_indextest5; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/h2/1.3.sql b/src/test/resources/dbmigration/migrationtest/h2/1.3.sql index 233f0524b..4fc5732b4 100644 --- a/src/test/resources/dbmigration/migrationtest/h2/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/h2/1.3.sql @@ -44,6 +44,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index if exists ix_migtest_e_basic_indextest3; drop index if exists ix_migtest_e_basic_indextest6; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql index 390cf2fd3..6e8b39c42 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.0__initial.sql @@ -127,12 +127,12 @@ create table migtest_oto_master ( create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql index 02e5f135a..ec6506025 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.1.sql @@ -81,20 +81,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); drop index if exists ix_migtest_e_basic_indextest1; drop index if exists ix_migtest_e_basic_indextest5; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql b/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql index 6d0ef4b55..bff47b901 100644 --- a/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/hsqldb/1.3.sql @@ -44,6 +44,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index if exists ix_migtest_e_basic_indextest3; drop index if exists ix_migtest_e_basic_indextest6; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql index 0d8e39910..8e1c0557f 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.0__initial.sql @@ -127,14 +127,14 @@ create table migtest_oto_master ( create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; alter table migtest_e_history2 add column sys_period_start datetime(6) default now(6); alter table migtest_e_history2 add column sys_period_end datetime(6); diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql index 9b9c7a41d..b7de26f72 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.1.sql @@ -79,20 +79,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); drop index ix_migtest_e_basic_indextest1 on migtest_e_basic; drop index ix_migtest_e_basic_indextest5 on migtest_e_basic; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql index 804d8022f..4fb4d19f5 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.3.sql @@ -39,6 +39,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index ix_migtest_e_basic_indextest3 on migtest_e_basic; drop index ix_migtest_e_basic_indextest6 on migtest_e_basic; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql index c0ddc9b36..fb1f1e66e 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.0__initial.sql @@ -144,12 +144,12 @@ create sequence migtest_oto_master_seq; create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql index 3d91c4a8c..8aea49e91 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.1.sql @@ -80,20 +80,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); drop index ix_migtest_e_basic_indextest1; drop index ix_migtest_e_basic_indextest5; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mtm_c_mgtst_mt_93awga foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); create index ix_mgtst_mtm_c_mgtst_mt_3ug4ok on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mtm_c_mgtst_mt_93awga foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mtm_c_mgtst_mt_93awgk foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); create index ix_mgtst_mtm_c_mgtst_mt_3ug4ou on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_mgtst_mtm_c_mgtst_mt_93awgk foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mtm_m_mgtst_mt_ggi34k foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); create index ix_mgtst_mtm_m_mgtst_mt_b7nbcu on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mtm_m_mgtst_mt_ggi34k foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mtm_m_mgtst_mt_ggi34a foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); create index ix_mgtst_mtm_m_mgtst_mt_b7nbck on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_mgtst_mtm_m_mgtst_mt_ggi34a foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); -alter table migtest_ckey_parent add constraint fk_mgtst_cky_prnt_ssc_d foreign key (assoc_id) references migtest_ckey_assoc (id); create index ix_mgtst_cky_prnt_ssc_d on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_mgtst_cky_prnt_ssc_d foreign key (assoc_id) references migtest_ckey_assoc (id); alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id); diff --git a/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql b/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql index 128d3badf..57fbfe9b7 100644 --- a/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/oracle/1.3.sql @@ -45,6 +45,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index ix_migtest_e_basic_indextest3; drop index ix_migtest_e_basic_indextest6; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql index 83a1b08b5..b15609fdd 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.0__initial.sql @@ -127,14 +127,14 @@ create table migtest_oto_master ( create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; alter table migtest_e_history2 add column sys_period tstzrange not null default tstzrange(current_timestamp, null); create table migtest_e_history2_history(like migtest_e_history2); diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql index 86009299b..3b4d3e3b2 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.1.sql @@ -86,20 +86,20 @@ create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); drop index if exists ix_migtest_e_basic_indextest1; drop index if exists ix_migtest_e_basic_indextest5; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id) on delete restrict on update restrict; diff --git a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql index 345be4828..3353df6fa 100644 --- a/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/postgres/1.3.sql @@ -44,6 +44,6 @@ create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); drop index if exists ix_migtest_e_basic_indextest3; drop index if exists ix_migtest_e_basic_indextest6; -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; From 0cc87009d0f2da83e2e3779a277699be80da724f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 18:37:36 +1300 Subject: [PATCH 0167/1036] #1340 - (test only change) Split SQL Server Platform into SqlServer16 and SqlServer17 (where 2017 which uses UTF8 types nvarchar etc and prefers Sequences). Update DbMigrationGenerateTest ... for SqlServer17 platform --- .../dbmigration/DbMigrationGenerateTest.java | 9 +- .../migrationtest/sqlserver/1.0__initial.sql | 160 ---------------- .../migrationtest/sqlserver/1.1.sql | 104 ---------- .../sqlserver/1.2__dropsFor_1.1.sql | 43 ----- .../migrationtest/sqlserver/1.3.sql | 62 ------ .../sqlserver/1.4__dropsFor_1.3.sql | 179 ------------------ .../R__order_views_mssql.sql | 0 7 files changed, 1 insertion(+), 556 deletions(-) delete mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql delete mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql delete mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver/1.2__dropsFor_1.1.sql delete mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql delete mode 100644 src/test/resources/dbmigration/migrationtest/sqlserver/1.4__dropsFor_1.3.sql rename src/test/resources/dbmigration/migrationtest/{sqlserver => sqlserver17}/R__order_views_mssql.sql (100%) diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java index 4966011b6..602cbb7c3 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java @@ -4,9 +4,6 @@ import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; -import io.ebean.config.dbplatform.DatabasePlatform; -import io.ebean.config.dbplatform.IdType; -import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,11 +51,7 @@ public class DbMigrationGenerateTest { migration.addPlatform(Platform.POSTGRES, "postgres"); migration.addPlatform(Platform.ORACLE, "oracle"); migration.addPlatform(Platform.SQLITE, "sqlite"); - - // we need sequence here, so that migration will work properly - DatabasePlatform sqlServer = new SqlServer17Platform(); - sqlServer.getDbIdentity().setIdType(IdType.SEQUENCE); - migration.addDatabasePlatform(sqlServer, "sqlserver"); + migration.addPlatform(Platform.SQLSERVER17, "sqlserver17"); ServerConfig config = new ServerConfig(); config.setName("migrationtest"); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql deleted file mode 100644 index ea820be14..000000000 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.0__initial.sql +++ /dev/null @@ -1,160 +0,0 @@ --- Migrationscripts for ebean unittest --- apply changes -create table migtest_ckey_assoc ( - id integer not null, - assoc_one nvarchar(255), - constraint pk_migtest_ckey_assoc primary key (id) -); -create sequence migtest_ckey_assoc_seq as bigint start with 1 ; - -create table migtest_ckey_detail ( - id integer not null, - something nvarchar(255), - constraint pk_migtest_ckey_detail primary key (id) -); -create sequence migtest_ckey_detail_seq as bigint start with 1 ; - -create table migtest_ckey_parent ( - one_key integer not null, - two_key nvarchar(127) not null, - name nvarchar(255), - version integer not null, - constraint pk_migtest_ckey_parent primary key (one_key,two_key) -); - -create table migtest_fk_cascade ( - id numeric(19) not null, - one_id numeric(19), - constraint pk_migtest_fk_cascade primary key (id) -); -create sequence migtest_fk_cascade_seq as bigint start with 1 ; - -create table migtest_fk_cascade_one ( - id numeric(19) not null, - constraint pk_migtest_fk_cascade_one primary key (id) -); -create sequence migtest_fk_cascade_one_seq as bigint start with 1 ; - -create table migtest_fk_none ( - id numeric(19) not null, - one_id numeric(19), - constraint pk_migtest_fk_none primary key (id) -); -create sequence migtest_fk_none_seq as bigint start with 1 ; - -create table migtest_fk_none_via_join ( - id numeric(19) not null, - one_id numeric(19), - constraint pk_migtest_fk_none_via_join primary key (id) -); -create sequence migtest_fk_none_via_join_seq as bigint start with 1 ; - -create table migtest_fk_one ( - id numeric(19) not null, - constraint pk_migtest_fk_one primary key (id) -); -create sequence migtest_fk_one_seq as bigint start with 1 ; - -create table migtest_fk_set_null ( - id numeric(19) not null, - one_id numeric(19), - constraint pk_migtest_fk_set_null primary key (id) -); -create sequence migtest_fk_set_null_seq as bigint start with 1 ; - -create table migtest_e_basic ( - id integer not null, - status nvarchar(1), - name nvarchar(127), - description nvarchar(127), - some_date datetime2, - old_boolean bit default 0 not null, - old_boolean2 bit, - eref_id integer, - indextest1 nvarchar(127), - indextest2 nvarchar(127), - indextest3 nvarchar(127), - indextest4 nvarchar(127), - indextest5 nvarchar(127), - indextest6 nvarchar(127), - user_id integer not null, - constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), - constraint pk_migtest_e_basic primary key (id) -); -create unique nonclustered index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) where indextest2 is not null; -create unique nonclustered index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) where indextest6 is not null; -create sequence migtest_e_basic_seq as bigint start with 1 ; - -create table migtest_e_history ( - id integer not null, - test_string nvarchar(255), - constraint pk_migtest_e_history primary key (id) -); -create sequence migtest_e_history_seq as bigint start with 1 ; - -create table migtest_e_history2 ( - id integer not null, - test_string nvarchar(255), - constraint pk_migtest_e_history2 primary key (id) -); -create sequence migtest_e_history2_seq as bigint start with 1 ; - -create table migtest_e_ref ( - id integer not null, - name nvarchar(127) not null, - constraint pk_migtest_e_ref primary key (id) -); -alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); -create sequence migtest_e_ref_seq as bigint start with 1 ; - -create table migtest_e_softdelete ( - id integer not null, - test_string nvarchar(255), - constraint pk_migtest_e_softdelete primary key (id) -); -create sequence migtest_e_softdelete_seq as bigint start with 1 ; - -create table migtest_mtm_c ( - id integer not null, - name nvarchar(255), - constraint pk_migtest_mtm_c primary key (id) -); -create sequence migtest_mtm_c_seq as bigint start with 1 ; - -create table migtest_mtm_m ( - id numeric(19) not null, - name nvarchar(255), - constraint pk_migtest_mtm_m primary key (id) -); -create sequence migtest_mtm_m_seq as bigint start with 1 ; - -create table migtest_oto_child ( - id integer not null, - name nvarchar(255), - constraint pk_migtest_oto_child primary key (id) -); -create sequence migtest_oto_child_seq as bigint start with 1 ; - -create table migtest_oto_master ( - id numeric(19) not null, - name nvarchar(255), - constraint pk_migtest_oto_master primary key (id) -); -create sequence migtest_oto_master_seq as bigint start with 1 ; - -create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); -create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -create index ix_migtest_fk_cascade_one_id on migtest_fk_cascade (one_id); -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; - -create index ix_migtest_fk_set_null_one_id on migtest_fk_set_null (one_id); -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; - -create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); - -alter table migtest_e_history2 - add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), - sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', -period for system_time (sys_periodFrom, sys_periodTo); -alter table migtest_e_history2 set (system_versioning = on (history_table=dbo.migtest_e_history2_history)); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql deleted file mode 100644 index 90c1f96bf..000000000 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.1.sql +++ /dev/null @@ -1,104 +0,0 @@ --- Migrationscripts for ebean unittest --- apply changes -create table migtest_e_user ( - id integer not null, - constraint pk_migtest_e_user primary key (id) -); -create sequence migtest_e_user_seq as bigint start with 1 ; - -create table migtest_mtm_c_migtest_mtm_m ( - migtest_mtm_c_id integer not null, - migtest_mtm_m_id numeric(19) not null, - constraint pk_migtest_mtm_c_migtest_mtm_m primary key (migtest_mtm_c_id,migtest_mtm_m_id) -); - -create table migtest_mtm_m_migtest_mtm_c ( - migtest_mtm_m_id numeric(19) not null, - migtest_mtm_c_id integer not null, - constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id) -); - -alter table migtest_ckey_detail add one_key integer; -alter table migtest_ckey_detail add two_key nvarchar(127); - -alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key); -alter table migtest_ckey_parent add assoc_id integer; - -IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id); -alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id); -alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id); -IF OBJECT_ID('fk_migtest_fk_set_null_one_id', 'F') IS NOT NULL alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id); - -update migtest_e_basic set status = 'A' where status is null; -IF (OBJECT_ID('ck_migtest_e_basic_status', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; -alter table migtest_e_basic add default 'A' for status; -alter table migtest_e_basic alter column status nvarchar(1) not null; -alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?')); - --- rename all collisions; -create unique nonclustered index uq_migtest_e_basic_description on migtest_e_basic(description) where description is not null; - -update migtest_e_basic set some_date = '2000-01-01T00:00:00' where some_date is null; -alter table migtest_e_basic add default '2000-01-01T00:00:00' for some_date; -alter table migtest_e_basic alter column some_date datetime2 not null; - -insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; -alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id); -alter table migtest_e_basic alter column user_id integer; -alter table migtest_e_basic add new_string_field nvarchar(255) default 'foo''bar' not null; -alter table migtest_e_basic add new_boolean_field bit default 1 not null; -update migtest_e_basic set new_boolean_field = old_boolean; - -alter table migtest_e_basic add new_boolean_field2 bit default 1 not null; -alter table migtest_e_basic add progress integer default 0 not null; -alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); -alter table migtest_e_basic add new_integer integer default 42 not null; - -IF (OBJECT_ID('uq_migtest_e_basic_indextest2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest2') drop index uq_migtest_e_basic_indextest2 ON migtest_e_basic; -IF (OBJECT_ID('uq_migtest_e_basic_indextest6', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest6') drop index uq_migtest_e_basic_indextest6 ON migtest_e_basic; -create unique nonclustered index uq_migtest_e_basic_status_indextest1 on migtest_e_basic(status,indextest1) where indextest1 is not null; -create unique nonclustered index uq_migtest_e_basic_name on migtest_e_basic(name) where name is not null; -create unique nonclustered index uq_migtest_e_basic_indextest4 on migtest_e_basic(indextest4) where indextest4 is not null; -create unique nonclustered index uq_migtest_e_basic_indextest5 on migtest_e_basic(indextest5) where indextest5 is not null; -alter table migtest_e_history alter column test_string numeric(19); - -update migtest_e_history2 set test_string = 'unknown' where test_string is null; -alter table migtest_e_history2 add default 'unknown' for test_string; -alter table migtest_e_history2 alter column test_string nvarchar(255) not null; -alter table migtest_e_history2 add test_string2 nvarchar(255); -alter table migtest_e_history2 add test_string3 nvarchar(255) default 'unknown' not null; - -alter table migtest_e_softdelete add deleted bit default 0 not null; - -alter table migtest_oto_child add master_id numeric(19); - -create index ix_migtest_e_basic_indextest3 on migtest_e_basic (indextest3); -create index ix_migtest_e_basic_indextest6 on migtest_e_basic (indextest6); -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest1') drop index ix_migtest_e_basic_indextest1 ON migtest_e_basic; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest5') drop index ix_migtest_e_basic_indextest5 ON migtest_e_basic; -create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c on migtest_mtm_c_migtest_mtm_m (migtest_mtm_c_id); -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); - -create index ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m on migtest_mtm_c_migtest_mtm_m (migtest_mtm_m_id); -alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); - -create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m on migtest_mtm_m_migtest_mtm_c (migtest_mtm_m_id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id); - -create index ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c on migtest_mtm_m_migtest_mtm_c (migtest_mtm_c_id); -alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id); - -create index ix_migtest_ckey_parent_assoc_id on migtest_ckey_parent (assoc_id); -alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id); - -alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id); - -alter table migtest_e_history - add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), - sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', -period for system_time (sys_periodFrom, sys_periodTo); -alter table migtest_e_history set (system_versioning = on (history_table=dbo.migtest_e_history_history)); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.2__dropsFor_1.1.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.2__dropsFor_1.1.sql deleted file mode 100644 index d3a7a9a24..000000000 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.2__dropsFor_1.1.sql +++ /dev/null @@ -1,43 +0,0 @@ --- Migrationscripts for ebean unittest --- apply changes --- drop column migtest_e_basic.old_boolean; -IF (OBJECT_ID('uq_migtest_e_basic_old_boolean', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_old_boolean; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_old_boolean') drop index uq_migtest_e_basic_old_boolean ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'old_boolean'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_old_boolean', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_old_boolean; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_old_boolean') drop index ix_migtest_e_basic_old_boolean ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_old_boolean', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_old_boolean; -alter table migtest_e_basic drop column old_boolean; - --- drop column migtest_e_basic.old_boolean2; -IF (OBJECT_ID('uq_migtest_e_basic_old_boolean2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_old_boolean2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_old_boolean2') drop index uq_migtest_e_basic_old_boolean2 ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'old_boolean2'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_old_boolean2', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_old_boolean2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_old_boolean2') drop index ix_migtest_e_basic_old_boolean2 ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_old_boolean2', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_old_boolean2; -alter table migtest_e_basic drop column old_boolean2; - --- drop column migtest_e_basic.eref_id; -IF (OBJECT_ID('uq_migtest_e_basic_eref_id', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_eref_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_eref_id') drop index uq_migtest_e_basic_eref_id ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'eref_id'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_eref_id', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_eref_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_eref_id') drop index ix_migtest_e_basic_eref_id ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_eref_id', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_eref_id; -alter table migtest_e_basic drop column eref_id; - -IF OBJECT_ID('migtest_e_ref', 'U') IS NOT NULL drop table migtest_e_ref; -IF OBJECT_ID('migtest_e_ref_seq', 'SO') IS NOT NULL drop sequence migtest_e_ref_seq; diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql deleted file mode 100644 index 50c300716..000000000 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.3.sql +++ /dev/null @@ -1,62 +0,0 @@ --- Migrationscripts for ebean unittest --- apply changes -create table migtest_e_ref ( - id integer not null, - name nvarchar(127) not null, - constraint pk_migtest_e_ref primary key (id) -); -alter table migtest_e_ref add constraint uq_migtest_e_ref_name unique (name); -create sequence migtest_e_ref_seq as bigint start with 1 ; - -IF OBJECT_ID('fk_migtest_ckey_detail_parent', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_parent; -IF OBJECT_ID('fk_migtest_fk_cascade_one_id', 'F') IS NOT NULL alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; -alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; -IF OBJECT_ID('fk_migtest_fk_none_one_id', 'F') IS NOT NULL alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id; -IF OBJECT_ID('fk_migtest_fk_none_via_join_one_id', 'F') IS NOT NULL alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id; -IF OBJECT_ID('fk_migtest_fk_set_null_one_id', 'F') IS NOT NULL alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; -alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; -IF (OBJECT_ID('ck_migtest_e_basic_status', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_status; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'status'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I')); -IF (OBJECT_ID('uq_migtest_e_basic_description', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_description; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_description') drop index uq_migtest_e_basic_description ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'some_date'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; - -update migtest_e_basic set user_id = 23 where user_id is null; -IF OBJECT_ID('fk_migtest_e_basic_user_id', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; -alter table migtest_e_basic add default 23 for user_id; -alter table migtest_e_basic alter column user_id integer not null; -alter table migtest_e_basic add old_boolean bit default 0 not null; -alter table migtest_e_basic add old_boolean2 bit; -alter table migtest_e_basic add eref_id integer; - -IF (OBJECT_ID('uq_migtest_e_basic_status_indextest1', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_status_indextest1; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_status_indextest1') drop index uq_migtest_e_basic_status_indextest1 ON migtest_e_basic; -IF (OBJECT_ID('uq_migtest_e_basic_name', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_name; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_name') drop index uq_migtest_e_basic_name ON migtest_e_basic; -IF (OBJECT_ID('uq_migtest_e_basic_indextest4', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest4; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest4') drop index uq_migtest_e_basic_indextest4 ON migtest_e_basic; -IF (OBJECT_ID('uq_migtest_e_basic_indextest5', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest5; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_indextest5') drop index uq_migtest_e_basic_indextest5 ON migtest_e_basic; -create unique nonclustered index uq_migtest_e_basic_indextest2 on migtest_e_basic(indextest2) where indextest2 is not null; -create unique nonclustered index uq_migtest_e_basic_indextest6 on migtest_e_basic(indextest6) where indextest6 is not null; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string'; -if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; -create index ix_migtest_e_basic_indextest1 on migtest_e_basic (indextest1); -create index ix_migtest_e_basic_indextest5 on migtest_e_basic (indextest5); -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest3') drop index ix_migtest_e_basic_indextest3 ON migtest_e_basic; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_indextest6') drop index ix_migtest_e_basic_indextest6 ON migtest_e_basic; -create index ix_migtest_e_basic_eref_id on migtest_e_basic (eref_id); -alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id); - diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/1.4__dropsFor_1.3.sql b/src/test/resources/dbmigration/migrationtest/sqlserver/1.4__dropsFor_1.3.sql deleted file mode 100644 index 50be4368d..000000000 --- a/src/test/resources/dbmigration/migrationtest/sqlserver/1.4__dropsFor_1.3.sql +++ /dev/null @@ -1,179 +0,0 @@ --- Migrationscripts for ebean unittest --- apply changes --- drop column migtest_ckey_detail.one_key; -IF (OBJECT_ID('uq_migtest_ckey_detail_one_key', 'UQ') IS NOT NULL) alter table migtest_ckey_detail drop constraint uq_migtest_ckey_detail_one_key; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'uq_migtest_ckey_detail_one_key') drop index uq_migtest_ckey_detail_one_key ON migtest_ckey_detail; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_ckey_detail') and t2.name = 'one_key'; -if @Tmp is not null EXEC('alter table migtest_ckey_detail drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_ckey_detail_one_key', 'C') IS NOT NULL) alter table migtest_ckey_detail drop constraint ck_migtest_ckey_detail_one_key; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'ix_migtest_ckey_detail_one_key') drop index ix_migtest_ckey_detail_one_key ON migtest_ckey_detail; -IF OBJECT_ID('fk_migtest_ckey_detail_one_key', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_one_key; -alter table migtest_ckey_detail drop column one_key; - --- drop column migtest_ckey_detail.two_key; -IF (OBJECT_ID('uq_migtest_ckey_detail_two_key', 'UQ') IS NOT NULL) alter table migtest_ckey_detail drop constraint uq_migtest_ckey_detail_two_key; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'uq_migtest_ckey_detail_two_key') drop index uq_migtest_ckey_detail_two_key ON migtest_ckey_detail; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_ckey_detail') and t2.name = 'two_key'; -if @Tmp is not null EXEC('alter table migtest_ckey_detail drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_ckey_detail_two_key', 'C') IS NOT NULL) alter table migtest_ckey_detail drop constraint ck_migtest_ckey_detail_two_key; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_detail','U') AND name = 'ix_migtest_ckey_detail_two_key') drop index ix_migtest_ckey_detail_two_key ON migtest_ckey_detail; -IF OBJECT_ID('fk_migtest_ckey_detail_two_key', 'F') IS NOT NULL alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_two_key; -alter table migtest_ckey_detail drop column two_key; - --- drop column migtest_ckey_parent.assoc_id; -IF (OBJECT_ID('uq_migtest_ckey_parent_assoc_id', 'UQ') IS NOT NULL) alter table migtest_ckey_parent drop constraint uq_migtest_ckey_parent_assoc_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_parent','U') AND name = 'uq_migtest_ckey_parent_assoc_id') drop index uq_migtest_ckey_parent_assoc_id ON migtest_ckey_parent; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_ckey_parent') and t2.name = 'assoc_id'; -if @Tmp is not null EXEC('alter table migtest_ckey_parent drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_ckey_parent_assoc_id', 'C') IS NOT NULL) alter table migtest_ckey_parent drop constraint ck_migtest_ckey_parent_assoc_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_ckey_parent','U') AND name = 'ix_migtest_ckey_parent_assoc_id') drop index ix_migtest_ckey_parent_assoc_id ON migtest_ckey_parent; -IF OBJECT_ID('fk_migtest_ckey_parent_assoc_id', 'F') IS NOT NULL alter table migtest_ckey_parent drop constraint fk_migtest_ckey_parent_assoc_id; -alter table migtest_ckey_parent drop column assoc_id; - --- drop column migtest_e_basic.new_string_field; -IF (OBJECT_ID('uq_migtest_e_basic_new_string_field', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_string_field; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_string_field') drop index uq_migtest_e_basic_new_string_field ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_string_field'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_new_string_field', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_string_field; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_string_field') drop index ix_migtest_e_basic_new_string_field ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_new_string_field', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_string_field; -alter table migtest_e_basic drop column new_string_field; - --- drop column migtest_e_basic.new_boolean_field; -IF (OBJECT_ID('uq_migtest_e_basic_new_boolean_field', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_boolean_field; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_boolean_field') drop index uq_migtest_e_basic_new_boolean_field ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_boolean_field'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_new_boolean_field', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_boolean_field; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_boolean_field') drop index ix_migtest_e_basic_new_boolean_field ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_new_boolean_field', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_boolean_field; -alter table migtest_e_basic drop column new_boolean_field; - --- drop column migtest_e_basic.new_boolean_field2; -IF (OBJECT_ID('uq_migtest_e_basic_new_boolean_field2', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_boolean_field2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_boolean_field2') drop index uq_migtest_e_basic_new_boolean_field2 ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_boolean_field2'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_new_boolean_field2', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_boolean_field2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_boolean_field2') drop index ix_migtest_e_basic_new_boolean_field2 ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_new_boolean_field2', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_boolean_field2; -alter table migtest_e_basic drop column new_boolean_field2; - --- drop column migtest_e_basic.progress; -IF (OBJECT_ID('uq_migtest_e_basic_progress', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_progress; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_progress') drop index uq_migtest_e_basic_progress ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'progress'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_progress', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_progress; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_progress') drop index ix_migtest_e_basic_progress ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_progress', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_progress; -alter table migtest_e_basic drop column progress; - --- drop column migtest_e_basic.new_integer; -IF (OBJECT_ID('uq_migtest_e_basic_new_integer', 'UQ') IS NOT NULL) alter table migtest_e_basic drop constraint uq_migtest_e_basic_new_integer; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'uq_migtest_e_basic_new_integer') drop index uq_migtest_e_basic_new_integer ON migtest_e_basic; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_basic') and t2.name = 'new_integer'; -if @Tmp is not null EXEC('alter table migtest_e_basic drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_basic_new_integer', 'C') IS NOT NULL) alter table migtest_e_basic drop constraint ck_migtest_e_basic_new_integer; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_basic','U') AND name = 'ix_migtest_e_basic_new_integer') drop index ix_migtest_e_basic_new_integer ON migtest_e_basic; -IF OBJECT_ID('fk_migtest_e_basic_new_integer', 'F') IS NOT NULL alter table migtest_e_basic drop constraint fk_migtest_e_basic_new_integer; -alter table migtest_e_basic drop column new_integer; - --- drop column migtest_e_history2.test_string2; -IF (OBJECT_ID('uq_migtest_e_history2_test_string2', 'UQ') IS NOT NULL) alter table migtest_e_history2 drop constraint uq_migtest_e_history2_test_string2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'uq_migtest_e_history2_test_string2') drop index uq_migtest_e_history2_test_string2 ON migtest_e_history2; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string2'; -if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_history2_test_string2', 'C') IS NOT NULL) alter table migtest_e_history2 drop constraint ck_migtest_e_history2_test_string2; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'ix_migtest_e_history2_test_string2') drop index ix_migtest_e_history2_test_string2 ON migtest_e_history2; -IF OBJECT_ID('fk_migtest_e_history2_test_string2', 'F') IS NOT NULL alter table migtest_e_history2 drop constraint fk_migtest_e_history2_test_string2; -alter table migtest_e_history2 drop column test_string2; - --- drop column migtest_e_history2.test_string3; -IF (OBJECT_ID('uq_migtest_e_history2_test_string3', 'UQ') IS NOT NULL) alter table migtest_e_history2 drop constraint uq_migtest_e_history2_test_string3; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'uq_migtest_e_history2_test_string3') drop index uq_migtest_e_history2_test_string3 ON migtest_e_history2; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_history2') and t2.name = 'test_string3'; -if @Tmp is not null EXEC('alter table migtest_e_history2 drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_history2_test_string3', 'C') IS NOT NULL) alter table migtest_e_history2 drop constraint ck_migtest_e_history2_test_string3; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_history2','U') AND name = 'ix_migtest_e_history2_test_string3') drop index ix_migtest_e_history2_test_string3 ON migtest_e_history2; -IF OBJECT_ID('fk_migtest_e_history2_test_string3', 'F') IS NOT NULL alter table migtest_e_history2 drop constraint fk_migtest_e_history2_test_string3; -alter table migtest_e_history2 drop column test_string3; - --- drop column migtest_e_softdelete.deleted; -IF (OBJECT_ID('uq_migtest_e_softdelete_deleted', 'UQ') IS NOT NULL) alter table migtest_e_softdelete drop constraint uq_migtest_e_softdelete_deleted; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_softdelete','U') AND name = 'uq_migtest_e_softdelete_deleted') drop index uq_migtest_e_softdelete_deleted ON migtest_e_softdelete; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_softdelete') and t2.name = 'deleted'; -if @Tmp is not null EXEC('alter table migtest_e_softdelete drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_e_softdelete_deleted', 'C') IS NOT NULL) alter table migtest_e_softdelete drop constraint ck_migtest_e_softdelete_deleted; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_e_softdelete','U') AND name = 'ix_migtest_e_softdelete_deleted') drop index ix_migtest_e_softdelete_deleted ON migtest_e_softdelete; -IF OBJECT_ID('fk_migtest_e_softdelete_deleted', 'F') IS NOT NULL alter table migtest_e_softdelete drop constraint fk_migtest_e_softdelete_deleted; -alter table migtest_e_softdelete drop column deleted; - --- drop column migtest_oto_child.master_id; -IF (OBJECT_ID('uq_migtest_oto_child_master_id', 'UQ') IS NOT NULL) alter table migtest_oto_child drop constraint uq_migtest_oto_child_master_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_oto_child','U') AND name = 'uq_migtest_oto_child_master_id') drop index uq_migtest_oto_child_master_id ON migtest_oto_child; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_oto_child') and t2.name = 'master_id'; -if @Tmp is not null EXEC('alter table migtest_oto_child drop constraint ' + @Tmp)$$; -IF (OBJECT_ID('ck_migtest_oto_child_master_id', 'C') IS NOT NULL) alter table migtest_oto_child drop constraint ck_migtest_oto_child_master_id; -IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('migtest_oto_child','U') AND name = 'ix_migtest_oto_child_master_id') drop index ix_migtest_oto_child_master_id ON migtest_oto_child; -IF OBJECT_ID('fk_migtest_oto_child_master_id', 'F') IS NOT NULL alter table migtest_oto_child drop constraint fk_migtest_oto_child_master_id; -alter table migtest_oto_child drop column master_id; - -IF OBJECT_ID('migtest_e_user', 'U') IS NOT NULL drop table migtest_e_user; -IF OBJECT_ID('migtest_e_user_seq', 'SO') IS NOT NULL drop sequence migtest_e_user_seq; -IF OBJECT_ID('migtest_mtm_c_migtest_mtm_m', 'U') IS NOT NULL drop table migtest_mtm_c_migtest_mtm_m; -IF OBJECT_ID('migtest_mtm_m_migtest_mtm_c', 'U') IS NOT NULL drop table migtest_mtm_m_migtest_mtm_c; --- dropping history support for migtest_e_history; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_history') and t2.name = 'sys_periodFrom'; -if @Tmp is not null EXEC('alter table migtest_e_history drop constraint ' + @Tmp)$$; -delimiter $$ -DECLARE @Tmp nvarchar(200);select @Tmp = t1.name from sys.default_constraints t1 - join sys.columns t2 on t1.object_id = t2.default_object_id - where t1.parent_object_id = OBJECT_ID('migtest_e_history') and t2.name = 'sys_periodTo'; -if @Tmp is not null EXEC('alter table migtest_e_history drop constraint ' + @Tmp)$$; -alter table migtest_e_history set (system_versioning = off); -alter table migtest_e_history drop period for system_time; -alter table migtest_e_history drop column sys_periodFrom; -alter table migtest_e_history drop column sys_periodTo; -IF OBJECT_ID('migtest_e_history_history', 'U') IS NOT NULL drop table migtest_e_history_history; - diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver/R__order_views_mssql.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/R__order_views_mssql.sql similarity index 100% rename from src/test/resources/dbmigration/migrationtest/sqlserver/R__order_views_mssql.sql rename to src/test/resources/dbmigration/migrationtest/sqlserver17/R__order_views_mssql.sql From 5faec61cd2b90667226774fa86495d305f0d318f Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 19:34:36 +1300 Subject: [PATCH 0168/1036] #1318 - ENH: native UUID-support for SqlServer Merge branch 'native-uuid-sqlserver' of https://github.com/FOCONIS/ebean into FOCONIS-native-uuid-sqlserver # Conflicts: # src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java --- .../io/ebean/config/dbplatform/DbPlatformTypeMapping.java | 6 +++--- .../config/dbplatform/sqlserver/SqlServer17Platform.java | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java b/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java index b26576247..c1c4896e3 100644 --- a/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java +++ b/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java @@ -119,8 +119,8 @@ public class DbPlatformTypeMapping { put(DbType.JSONCLOB, JSON_CLOB_PLACEHOLDER); put(DbType.JSONBLOB, JSON_BLOB_PLACEHOLDER); put(DbType.JSONVARCHAR, JSON_VARCHAR_PLACEHOLDER); - // use reasonable default of varchar(40) - ideally set via DatabasePlatform.configure(DbTypeConfig) - put(DbType.UUID, get(DbType.VARCHAR).withLength(40)); + // default to native UUID and override on platform configure() + put(DbType.UUID, UUID_NATIVE); } } @@ -200,7 +200,7 @@ public class DbPlatformTypeMapping { */ public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) { if (nativeUuidType && dbUuid.useNativeType()) { - put(DbType.UUID, UUID_NATIVE); + // native UUID already set by default } else if (dbUuid.useBinary()) { put(DbType.UUID, get(DbType.BINARY).withLength(16)); } else { diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java index fd17bbe9f..e08de85ab 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java @@ -1,6 +1,8 @@ package io.ebean.config.dbplatform.sqlserver; import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.DbType; /** * Microsoft SQL Server platform - NVarchar UTF types and Sequence preference. @@ -11,6 +13,8 @@ public class SqlServer17Platform extends SqlServerBasePlatform { super(); this.platform = Platform.SQLSERVER17; this.columnAliasPrefix = null; + this.nativeUuidType = true; + this.dbTypeMap.put(DbType.UUID, new DbPlatformType("uniqueidentifier", false)); } } From 0aec597cf251d3ff3290f08d0b8fa30031643dac Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 19:35:48 +1300 Subject: [PATCH 0169/1036] #1318 No effective change - DDL review for ... ENH: native UUID-support for SqlServer --- src/test/ddl-review/sqlserver-create-all.sql | 3626 ++++++++++++++++++ src/test/ddl-review/sqlserver-drop-all.sql | 1549 ++++++++ 2 files changed, 5175 insertions(+) create mode 100644 src/test/ddl-review/sqlserver-create-all.sql create mode 100644 src/test/ddl-review/sqlserver-drop-all.sql diff --git a/src/test/ddl-review/sqlserver-create-all.sql b/src/test/ddl-review/sqlserver-create-all.sql new file mode 100644 index 000000000..de66ddd39 --- /dev/null +++ b/src/test/ddl-review/sqlserver-create-all.sql @@ -0,0 +1,3626 @@ +-- Generated by ebean unknown at 2018-03-08T04:43:42.126Z +create table asimple_bean ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_asimple_bean primary key (id) +); +create sequence asimple_bean_seq as bigint start with 1 increment by 50; + +create table bar ( + bar_type nvarchar(31) not null, + bar_id integer not null, + foo_id integer not null, + version integer not null, + constraint pk_bar primary key (bar_id) +); +create sequence bar_seq as bigint start with 1 increment by 50; + +create table oto_account ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_oto_account primary key (id) +); +create sequence oto_account_seq as bigint start with 1 increment by 50; + +create table addr ( + id numeric(19) not null, + employee_id numeric(19), + name nvarchar(255), + address_line1 nvarchar(255), + address_line2 nvarchar(255), + city nvarchar(255), + version numeric(19) not null, + constraint pk_addr primary key (id) +); +create sequence addr_seq as bigint start with 1 increment by 50; + +create table address ( + oid numeric(19) not null, + street nvarchar(255), + version integer not null, + constraint pk_address primary key (oid) +); +create sequence address_seq as bigint start with 1 increment by 50; + +create table o_address ( + id smallint not null, + line_1 nvarchar(100), + line_2 nvarchar(100), + city nvarchar(100), + cretime datetime2, + country_code nvarchar(2), + updtime datetime2 not null, + constraint pk_o_address primary key (id) +); +create sequence o_address_seq as bigint start with 1 increment by 50; + +create table album ( + id numeric(19) not null, + name nvarchar(255), + cover_id numeric(19), + deleted integer default 0 not null, + created_at datetime2 not null, + last_update datetime2 not null, + constraint pk_album primary key (id) +); +create unique nonclustered index uq_album_cover_id on album(cover_id) where cover_id is not null; +create sequence album_seq as bigint start with 1 increment by 50; + +create table animal ( + species nvarchar(255) not null, + id numeric(19) not null, + shelter_id numeric(19), + version numeric(19) not null, + name nvarchar(255), + registration_number nvarchar(255), + date_of_birth date, + dog_size nvarchar(255), + constraint pk_animal primary key (id) +); +create sequence animal_seq as bigint start with 1 increment by 50; + +create table animal_shelter ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_animal_shelter primary key (id) +); +create sequence animal_shelter_seq as bigint start with 1 increment by 50; + +create table article ( + id integer not null, + name nvarchar(255), + author nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_article primary key (id) +); +create sequence article_seq as bigint start with 1 increment by 50; + +create table attribute ( + option_type integer not null, + id integer not null, + attribute_holder_id integer, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_attribute primary key (id) +); +create sequence attribute_seq as bigint start with 1 increment by 50; + +create table attribute_holder ( + id integer not null, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_attribute_holder primary key (id) +); +create sequence attribute_holder_seq as bigint start with 1 increment by 50; + +create table audit_log ( + id numeric(19) not null, + description nvarchar(255), + modified_description nvarchar(255), + constraint pk_audit_log primary key (id) +); +create sequence audit_log_seq as bigint start with 1 increment by 50; + +create table bbookmark ( + id integer not null, + bookmark_reference nvarchar(255), + user_id integer, + constraint pk_bbookmark primary key (id) +); +create sequence bbookmark_seq as bigint start with 1 increment by 50; + +create table bbookmark_user ( + id integer not null, + name nvarchar(255), + password nvarchar(255), + email_address nvarchar(255), + country nvarchar(255), + constraint pk_bbookmark_user primary key (id) +); +create sequence bbookmark_user_seq as bigint start with 1 increment by 50; + +create table bsimple_with_gen ( + id integer not null, + name nvarchar(255), + constraint pk_bsimple_with_gen primary key (id) +); +create sequence bsimple_with_gen_seq as bigint start with 1 increment by 50; + +create table bsite ( + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_bsite primary key (id) +); + +create table bsite_user ( + site_id nvarchar(40) not null, + user_id nvarchar(40) not null, + access_level integer, + constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user primary key (site_id,user_id) +); + +create table bsite_user_b ( + site nvarchar(40) not null, + usr nvarchar(40) not null, + access_level integer, + constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_b primary key (site,usr) +); + +create table bsite_user_c ( + site_uid nvarchar(40) not null, + user_uid nvarchar(40) not null, + access_level integer, + constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_c primary key (site_uid,user_uid) +); + +create table buser ( + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_buser primary key (id) +); + +create table bwith_qident ( + id integer not null, + [Name] nvarchar(191), + last_updated datetime2 not null, + constraint pk_bwith_qident primary key (id) +); +create unique nonclustered index uq_bwith_qident_name on bwith_qident([Name]) where [Name] is not null; +create sequence bwith_qident_seq as bigint start with 1 increment by 50; + +create table basic_joda_entity ( + id numeric(19) not null, + name nvarchar(255), + period nvarchar(50), + created datetime2 not null, + updated datetime2 not null, + version datetime2 not null, + constraint pk_basic_joda_entity primary key (id) +); +create sequence basic_joda_entity_seq as bigint start with 1 increment by 50; + +create table bean_with_time_zone ( + id numeric(19) not null, + name nvarchar(255), + timezone nvarchar(20), + constraint pk_bean_with_time_zone primary key (id) +); +create sequence bean_with_time_zone_seq as bigint start with 1 increment by 50; + +create table drel_booking ( + id numeric(19) not null, + booking_uid numeric(19), + agent_invoice numeric(19), + client_invoice numeric(19), + version integer not null, + constraint pk_drel_booking primary key (id) +); +create unique nonclustered index uq_drel_booking_booking_uid on drel_booking(booking_uid) where booking_uid is not null; +create unique nonclustered index uq_drel_booking_agent_invoice on drel_booking(agent_invoice) where agent_invoice is not null; +create unique nonclustered index uq_drel_booking_client_invoice on drel_booking(client_invoice) where client_invoice is not null; +create sequence drel_booking_seq as bigint start with 1 increment by 50; + +create table cinh_root ( + dtype nvarchar(3) not null, + id integer not null, + license_number nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + driver nvarchar(255), + notes nvarchar(255), + action nvarchar(255), + constraint pk_cinh_root primary key (id) +); +create sequence cinh_root_seq as bigint start with 1 increment by 50; + +create table ckey_assoc ( + id integer not null, + assoc_one nvarchar(255), + constraint pk_ckey_assoc primary key (id) +); +create sequence ckey_assoc_seq as bigint start with 1 increment by 50; + +create table ckey_detail ( + id integer not null, + something nvarchar(255), + one_key integer, + two_key nvarchar(127), + constraint pk_ckey_detail primary key (id) +); +create sequence ckey_detail_seq as bigint start with 1 increment by 50; + +create table ckey_parent ( + one_key integer not null, + two_key nvarchar(127) not null, + name nvarchar(255), + assoc_id integer, + version integer not null, + constraint pk_ckey_parent primary key (one_key,two_key) +); + +create table calculation_result ( + id integer not null, + charge float(32) not null, + product_configuration_id integer, + group_configuration_id integer, + constraint pk_calculation_result primary key (id) +); +create sequence calculation_result_seq as bigint start with 1 increment by 50; + +create table cao_bean ( + x_cust_id integer not null, + x_type_id integer not null, + description nvarchar(255), + version numeric(19) not null, + constraint pk_cao_bean primary key (x_cust_id,x_type_id) +); + +create table sa_car ( + id numeric(19) not null, + version integer not null, + constraint pk_sa_car primary key (id) +); +create sequence sa_car_seq as bigint start with 1 increment by 50; + +create table sp_car_car ( + id numeric(19) not null, + version integer not null, + constraint pk_sp_car_car primary key (id) +); +create sequence sp_car_car_seq as bigint start with 1 increment by 50; + +create table sp_car_car_wheels ( + car numeric(19) not null, + wheel numeric(19) not null, + constraint pk_sp_car_car_wheels primary key (car,wheel) +); + +create table car_accessory ( + id integer not null, + name nvarchar(255), + fuse_id numeric(19) not null, + car_id integer, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_car_accessory primary key (id) +); +create sequence car_accessory_seq as bigint start with 1 increment by 50; + +create table car_fuse ( + id numeric(19) not null, + location_code nvarchar(255), + constraint pk_car_fuse primary key (id) +); +create sequence car_fuse_seq as bigint start with 1 increment by 50; + +create table category ( + id numeric(19) not null, + name nvarchar(255), + surveyobjectid numeric(19), + sequence_number integer not null, + constraint pk_category primary key (id) +); +create sequence category_seq as bigint start with 1 increment by 50; + +create table child_person ( + identifier integer not null, + name nvarchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name nvarchar(255), + address nvarchar(255), + constraint pk_child_person primary key (identifier) +); +create sequence child_person_seq as bigint start with 1 increment by 50; + +create table configuration ( + type nvarchar(21) not null, + id integer not null, + name nvarchar(255), + configurations_id integer, + group_name nvarchar(255), + product_name nvarchar(255), + constraint pk_configuration primary key (id) +); +create sequence configuration_seq as bigint start with 1 increment by 50; + +create table configurations ( + id integer not null, + name nvarchar(255), + constraint pk_configurations primary key (id) +); +create sequence configurations_seq as bigint start with 1 increment by 50; + +create table contact ( + id integer not null, + first_name nvarchar(127), + last_name nvarchar(127), + phone nvarchar(255), + mobile nvarchar(255), + email nvarchar(255), + customer_id integer not null, + group_id integer, + cretime datetime2 not null, + updtime datetime2 not null, + constraint pk_contact primary key (id) +); +create sequence contact_seq as bigint start with 1 increment by 50; + +create table contact_group ( + id integer not null, + name nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_contact_group primary key (id) +); +create sequence contact_group_seq as bigint start with 1 increment by 50; + +create table contact_note ( + id integer not null, + contact_id integer, + title nvarchar(255), + note nvarchar(max), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_contact_note primary key (id) +); +create sequence contact_note_seq as bigint start with 1 increment by 50; + +create table c_conversation ( + id numeric(19) not null, + title nvarchar(255), + isopen integer default 0 not null, + group_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_c_conversation primary key (id) +); +create sequence c_conversation_seq as bigint start with 1 increment by 50; + +create table o_country ( + code nvarchar(2) not null, + name nvarchar(60), + constraint pk_o_country primary key (code) +); + +create table cover ( + id numeric(19) not null, + s3url nvarchar(255), + deleted integer default 0 not null, + constraint pk_cover primary key (id) +); +create sequence cover_seq as bigint start with 1 increment by 50; + +create table o_customer ( + id integer not null, + status nvarchar(1), + name nvarchar(40) not null, + smallnote nvarchar(100), + anniversary date, + billing_address_id smallint, + shipping_address_id smallint, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint ck_o_customer_status check ( status in ('N','A','I')), + constraint pk_o_customer primary key (id) +); +create sequence o_customer_seq as bigint start with 1 increment by 50; + +create table dcredit ( + id numeric(19) not null, + credit nvarchar(255), + constraint pk_dcredit primary key (id) +); +create sequence dcredit_seq as bigint start with 1 increment by 50; + +create table dcredit_drol ( + dcredit_id numeric(19) not null, + drol_id numeric(19) not null, + constraint pk_dcredit_drol primary key (dcredit_id,drol_id) +); + +create table dexh_entity ( + oid numeric(19) not null, + exhange nvarchar(255), + an_enum_type nvarchar(255), + last_updated datetime2 not null, + constraint pk_dexh_entity primary key (oid) +); +create sequence dexh_entity_seq as bigint start with 1 increment by 50; + +create table dperson ( + id numeric(19) not null, + first_name nvarchar(255), + last_name nvarchar(255), + salary numeric(28), + constraint pk_dperson primary key (id) +); +create sequence dperson_seq as bigint start with 1 increment by 50; + +create table drol ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_drol primary key (id) +); +create sequence drol_seq as bigint start with 1 increment by 50; + +create table drot ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_drot primary key (id) +); +create sequence drot_seq as bigint start with 1 increment by 50; + +create table drot_drol ( + drot_id numeric(19) not null, + drol_id numeric(19) not null, + constraint pk_drot_drol primary key (drot_id,drol_id) +); + +create table rawinherit_data ( + id numeric(19) not null, + val integer, + constraint pk_rawinherit_data primary key (id) +); +create sequence rawinherit_data_seq as bigint start with 1 increment by 50; + +create table dfk_cascade ( + id numeric(19) not null, + name nvarchar(255), + one_id numeric(19), + constraint pk_dfk_cascade primary key (id) +); +create sequence dfk_cascade_seq as bigint start with 1 increment by 50; + +create table dfk_cascade_one ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_dfk_cascade_one primary key (id) +); +create sequence dfk_cascade_one_seq as bigint start with 1 increment by 50; + +create table dfk_none ( + id numeric(19) not null, + name nvarchar(255), + one_id numeric(19), + constraint pk_dfk_none primary key (id) +); +create sequence dfk_none_seq as bigint start with 1 increment by 50; + +create table dfk_none_via_join ( + id numeric(19) not null, + name nvarchar(255), + one_id numeric(19), + constraint pk_dfk_none_via_join primary key (id) +); +create sequence dfk_none_via_join_seq as bigint start with 1 increment by 50; + +create table dfk_one ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_dfk_one primary key (id) +); +create sequence dfk_one_seq as bigint start with 1 increment by 50; + +create table dfk_set_null ( + id numeric(19) not null, + name nvarchar(255), + one_id numeric(19), + constraint pk_dfk_set_null primary key (id) +); +create sequence dfk_set_null_seq as bigint start with 1 increment by 50; + +create table doc ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_doc primary key (id) +); +create sequence doc_seq as bigint start with 1 increment by 50; + +create table doc_link ( + doc_id numeric(19) not null, + link_id numeric(19) not null, + constraint pk_doc_link primary key (doc_id,link_id) +); + +create table doc_link_draft ( + doc_id numeric(19) not null, + link_id numeric(19) not null, + constraint pk_doc_link_draft primary key (doc_id,link_id) +); + +create table doc_draft ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_doc_draft primary key (id) +); +create sequence doc_draft_seq as bigint start with 1 ; + +create table document ( + id numeric(19) not null, + title nvarchar(127), + body nvarchar(255), + organisation_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_document primary key (id) +); +create unique nonclustered index uq_document_title on document(title) where title is not null; +create sequence document_seq as bigint start with 1 increment by 50; + +create table document_draft ( + id numeric(19) not null, + title nvarchar(127), + body nvarchar(255), + when_publish datetime2, + organisation_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_document_draft primary key (id) +); +create unique nonclustered index uq_document_draft_title on document_draft(title) where title is not null; +create sequence document_draft_seq as bigint start with 1 ; + +create table document_media ( + id numeric(19) not null, + document_id numeric(19), + name nvarchar(255), + description nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_document_media primary key (id) +); +create sequence document_media_seq as bigint start with 1 increment by 50; + +create table document_media_draft ( + id numeric(19) not null, + document_id numeric(19), + name nvarchar(255), + description nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_document_media_draft primary key (id) +); +create sequence document_media_draft_seq as bigint start with 1 ; + +create table earray_bean ( + id numeric(19) not null, + name nvarchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + statuses varchar(1000), + status2 varchar(1000), + version numeric(19) not null, + constraint pk_earray_bean primary key (id) +); +create sequence earray_bean_seq as bigint start with 1 increment by 50; + +create table earray_set_bean ( + id numeric(19) not null, + name nvarchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + version numeric(19) not null, + constraint pk_earray_set_bean primary key (id) +); +create sequence earray_set_bean_seq as bigint start with 1 increment by 50; + +create table e_basic ( + id integer not null, + status nvarchar(1), + name nvarchar(127), + description nvarchar(255), + some_date datetime2, + constraint ck_e_basic_status check ( status in ('N','A','I')), + constraint pk_e_basic primary key (id) +); +create sequence e_basic_seq as bigint start with 1 increment by 50; + +create table ebasic_change_log ( + id numeric(19) not null, + name nvarchar(20), + short_description nvarchar(50), + long_description nvarchar(100), + who_created nvarchar(255) not null, + who_modified nvarchar(255) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + version numeric(19) not null, + constraint pk_ebasic_change_log primary key (id) +); +create sequence ebasic_change_log_seq as bigint start with 1 increment by 50; + +create table ebasic_clob ( + id numeric(19) not null, + name nvarchar(255), + title nvarchar(255), + description nvarchar(max), + last_update datetime2 not null, + constraint pk_ebasic_clob primary key (id) +); +create sequence ebasic_clob_seq as bigint start with 1 increment by 50; + +create table ebasic_clob_fetch_eager ( + id numeric(19) not null, + name nvarchar(255), + title nvarchar(255), + description nvarchar(max), + last_update datetime2 not null, + constraint pk_ebasic_clob_fetch_eager primary key (id) +); +create sequence ebasic_clob_fetch_eager_seq as bigint start with 1 increment by 50; + +create table ebasic_clob_no_ver ( + id numeric(19) not null, + name nvarchar(255), + description nvarchar(max), + constraint pk_ebasic_clob_no_ver primary key (id) +); +create sequence ebasic_clob_no_ver_seq as bigint start with 1 increment by 50; + +create table e_basicenc ( + id integer not null, + name nvarchar(255), + description varbinary(80), + dob varbinary(20), + status varbinary(20), + last_update datetime2, + constraint pk_e_basicenc primary key (id) +); +create sequence e_basicenc_seq as bigint start with 1 increment by 50; + +create table e_basicenc_bin ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + data image, + some_time varbinary(255), + last_update datetime2 not null, + constraint pk_e_basicenc_bin primary key (id) +); +create sequence e_basicenc_bin_seq as bigint start with 1 increment by 50; + +create table e_basic_enum_id ( + status nvarchar(1) not null, + name nvarchar(255), + description nvarchar(255), + constraint ck_e_basic_enum_id_status check ( status in ('N','A','I')), + constraint pk_e_basic_enum_id primary key (status) +); + +create table e_basic_eni ( + id integer not null, + status integer, + name nvarchar(255), + description nvarchar(255), + some_date datetime2, + constraint ck_e_basic_eni_status check ( status in (1,2,3)), + constraint pk_e_basic_eni primary key (id) +); +create sequence e_basic_eni_seq as bigint start with 1 increment by 50; + +create table ebasic_hstore ( + id numeric(19) not null, + name nvarchar(255), + map nvarchar(800), + version numeric(19) not null, + constraint pk_ebasic_hstore primary key (id) +); +create sequence ebasic_hstore_seq as bigint start with 1 increment by 50; + +create table ebasic_json_list ( + id numeric(19) not null, + name nvarchar(255), + bean_set nvarchar(700), + bean_list nvarchar(max), + bean_map nvarchar(700), + plain_bean nvarchar(500), + flags nvarchar(50), + tags nvarchar(100), + version numeric(19) not null, + constraint pk_ebasic_json_list primary key (id) +); +create sequence ebasic_json_list_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_map primary key (id) +); +create sequence ebasic_json_map_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map_blob ( + id numeric(19) not null, + name nvarchar(255), + content image, + version numeric(19) not null, + constraint pk_ebasic_json_map_blob primary key (id) +); +create sequence ebasic_json_map_blob_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map_clob ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_map_clob primary key (id) +); +create sequence ebasic_json_map_clob_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map_detail ( + id numeric(19) not null, + owner_id numeric(19), + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_map_detail primary key (id) +); +create sequence ebasic_json_map_detail_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map_json_b ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_map_json_b primary key (id) +); +create sequence ebasic_json_map_json_b_seq as bigint start with 1 increment by 50; + +create table ebasic_json_map_varchar ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(3000), + version numeric(19) not null, + constraint pk_ebasic_json_map_varchar primary key (id) +); +create sequence ebasic_json_map_varchar_seq as bigint start with 1 increment by 50; + +create table ebasic_json_node ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_node primary key (id) +); +create sequence ebasic_json_node_seq as bigint start with 1 increment by 50; + +create table ebasic_json_node_blob ( + id numeric(19) not null, + name nvarchar(255), + content image, + version numeric(19) not null, + constraint pk_ebasic_json_node_blob primary key (id) +); +create sequence ebasic_json_node_blob_seq as bigint start with 1 increment by 50; + +create table ebasic_json_node_json_b ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(max), + version numeric(19) not null, + constraint pk_ebasic_json_node_json_b primary key (id) +); +create sequence ebasic_json_node_json_b_seq as bigint start with 1 increment by 50; + +create table ebasic_json_node_varchar ( + id numeric(19) not null, + name nvarchar(255), + content nvarchar(1000), + version numeric(19) not null, + constraint pk_ebasic_json_node_varchar primary key (id) +); +create sequence ebasic_json_node_varchar_seq as bigint start with 1 increment by 50; + +create table ebasic_json_unmapped ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_ebasic_json_unmapped primary key (id) +); +create sequence ebasic_json_unmapped_seq as bigint start with 1 increment by 50; + +create table e_basic_ndc ( + id integer not null, + name nvarchar(255), + constraint pk_e_basic_ndc primary key (id) +); +create sequence e_basic_ndc_seq as bigint start with 1 increment by 50; + +create table ebasic_no_sdchild ( + id numeric(19) not null, + owner_id numeric(19) not null, + child_name nvarchar(255), + amount numeric(19) not null, + version numeric(19) not null, + constraint pk_ebasic_no_sdchild primary key (id) +); +create sequence ebasic_no_sdchild_seq as bigint start with 1 increment by 50; + +create table ebasic_sdchild ( + id numeric(19) not null, + owner_id numeric(19) not null, + child_name nvarchar(255), + amount numeric(19) not null, + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_ebasic_sdchild primary key (id) +); +create sequence ebasic_sdchild_seq as bigint start with 1 increment by 50; + +create table ebasic_soft_delete ( + id numeric(19) not null, + name nvarchar(255), + description nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_ebasic_soft_delete primary key (id) +); +create sequence ebasic_soft_delete_seq as bigint start with 1 increment by 50; + +create table e_basicver ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + other nvarchar(255), + last_update datetime2 not null, + constraint pk_e_basicver primary key (id) +); +create sequence e_basicver_seq as bigint start with 1 increment by 50; + +create table e_basic_withlife ( + id numeric(19) not null, + name nvarchar(255), + deleted integer default 0 not null, + version numeric(19) not null, + constraint pk_e_basic_withlife primary key (id) +); +create sequence e_basic_withlife_seq as bigint start with 1 increment by 50; + +create table e_basicverucon ( + id integer not null, + name nvarchar(127), + other nvarchar(127), + other_one nvarchar(127), + description nvarchar(255), + last_update datetime2 not null, + constraint pk_e_basicverucon primary key (id) +); +create unique nonclustered index uq_e_basicverucon_name on e_basicverucon(name) where name is not null; +create unique nonclustered index uq_e_basicverucon_other_other_one on e_basicverucon(other,other_one) where other is not null and other_one is not null; +create sequence e_basicverucon_seq as bigint start with 1 increment by 50; + +create table e_col_ab ( + id numeric(19) not null, + column_a nvarchar(255), + column_b nvarchar(255), + constraint pk_e_col_ab primary key (id) +); +create sequence e_col_ab_seq as bigint start with 1 increment by 50; + +create table ecustom_id ( + id nvarchar(127) not null, + name nvarchar(255), + constraint pk_ecustom_id primary key (id) +); + +create table eemb_inner ( + id integer not null, + nome_inner nvarchar(255), + outer_id integer, + update_count integer not null, + constraint pk_eemb_inner primary key (id) +); +create sequence eemb_inner_seq as bigint start with 1 increment by 50; + +create table eemb_outer ( + id integer not null, + nome_outer nvarchar(255), + date1 datetime2, + date2 datetime2, + update_count integer not null, + constraint pk_eemb_outer primary key (id) +); +create sequence eemb_outer_seq as bigint start with 1 increment by 50; + +create table egen_props ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + ts_created datetime2 not null, + ts_updated datetime2 not null, + ldt_created datetime2 not null, + ldt_updated datetime2 not null, + odt_created datetime2 not null, + odt_updated datetime2 not null, + zdt_created datetime2 not null, + zdt_updated datetime2 not null, + instant_created datetime2 not null, + instant_updated datetime2 not null, + long_created numeric(19) not null, + long_updated numeric(19) not null, + constraint pk_egen_props primary key (id) +); +create sequence egen_props_seq as bigint start with 1 increment by 50; + +create table einvoice ( + id numeric(19) not null, + invoice_date datetime2, + state integer, + person_id numeric(19), + ship_street nvarchar(255), + ship_suburb nvarchar(255), + ship_city nvarchar(255), + ship_status nvarchar(3), + bill_street nvarchar(255), + bill_suburb nvarchar(255), + bill_city nvarchar(255), + bill_status nvarchar(3), + version numeric(19) not null, + constraint ck_einvoice_state check ( state in (0,1,2)), + constraint ck_einvoice_ship_status check ( ship_status in ('ONE','TWO')), + constraint ck_einvoice_bill_status check ( bill_status in ('ONE','TWO')), + constraint pk_einvoice primary key (id) +); +create sequence einvoice_seq as bigint start with 1 increment by 50; + +create table e_main ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + version numeric(19) not null, + constraint pk_e_main primary key (id) +); +create sequence e_main_seq as bigint start with 1 increment by 50; + +create table enull_collection ( + id integer not null, + name nvarchar(255), + constraint pk_enull_collection primary key (id) +); +create sequence enull_collection_seq as bigint start with 1 increment by 50; + +create table enull_collection_detail ( + id integer not null, + enull_collection_id integer not null, + something nvarchar(255), + constraint pk_enull_collection_detail primary key (id) +); +create sequence enull_collection_detail_seq as bigint start with 1 increment by 50; + +create table eopt_one_a ( + id integer not null, + name_for_a nvarchar(255), + b_id integer, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_eopt_one_a primary key (id) +); +create sequence eopt_one_a_seq as bigint start with 1 increment by 50; + +create table eopt_one_b ( + id integer not null, + name_for_b nvarchar(255), + c_id integer not null, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_eopt_one_b primary key (id) +); +create sequence eopt_one_b_seq as bigint start with 1 increment by 50; + +create table eopt_one_c ( + id integer not null, + name_for_c nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_eopt_one_c primary key (id) +); +create sequence eopt_one_c_seq as bigint start with 1 increment by 50; + +create table eperson ( + id numeric(19) not null, + name nvarchar(255), + notes nvarchar(255), + street nvarchar(255), + suburb nvarchar(255), + addr_city nvarchar(255), + addr_status nvarchar(3), + version numeric(19) not null, + constraint ck_eperson_addr_status check ( addr_status in ('ONE','TWO')), + constraint pk_eperson primary key (id) +); +create sequence eperson_seq as bigint start with 1 increment by 50; + +create table e_person_online ( + id numeric(19) not null, + email nvarchar(127), + online_status integer default 0 not null, + when_updated datetime2 not null, + constraint pk_e_person_online primary key (id) +); +create unique nonclustered index uq_e_person_online_email on e_person_online(email) where email is not null; +create sequence e_person_online_seq as bigint start with 1 increment by 50; + +create table esimple ( + usertypeid integer identity(1,1) not null, + name nvarchar(255), + constraint pk_esimple primary key (usertypeid) +); + +create table esoft_del_book ( + id numeric(19) not null, + book_title nvarchar(255), + lend_by_id numeric(19), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_book primary key (id) +); +create sequence esoft_del_book_seq as bigint start with 1 increment by 50; + +create table esoft_del_book_esoft_del_user ( + esoft_del_book_id numeric(19) not null, + esoft_del_user_id numeric(19) not null, + constraint pk_esoft_del_book_esoft_del_user primary key (esoft_del_book_id,esoft_del_user_id) +); + +create table esoft_del_down ( + id numeric(19) not null, + esoft_del_mid_id numeric(19) not null, + down nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_down primary key (id) +); +create sequence esoft_del_down_seq as bigint start with 1 increment by 50; + +create table esoft_del_mid ( + id numeric(19) not null, + top_id numeric(19), + mid nvarchar(255), + up_id numeric(19), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_mid primary key (id) +); +create sequence esoft_del_mid_seq as bigint start with 1 increment by 50; + +create table esoft_del_one_a ( + id numeric(19) not null, + name nvarchar(255), + oneb_id numeric(19), + deleted integer default 0 not null, + version numeric(19) not null, + constraint pk_esoft_del_one_a primary key (id) +); +create unique nonclustered index uq_esoft_del_one_a_oneb_id on esoft_del_one_a(oneb_id) where oneb_id is not null; +create sequence esoft_del_one_a_seq as bigint start with 1 increment by 50; + +create table esoft_del_one_b ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_esoft_del_one_b primary key (id) +); +create sequence esoft_del_one_b_seq as bigint start with 1 increment by 50; + +create table esoft_del_role ( + id numeric(19) not null, + role_name nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_role primary key (id) +); +create sequence esoft_del_role_seq as bigint start with 1 increment by 50; + +create table esoft_del_role_esoft_del_user ( + esoft_del_role_id numeric(19) not null, + esoft_del_user_id numeric(19) not null, + constraint pk_esoft_del_role_esoft_del_user primary key (esoft_del_role_id,esoft_del_user_id) +); + +create table esoft_del_top ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_top primary key (id) +); +create sequence esoft_del_top_seq as bigint start with 1 increment by 50; + +create table esoft_del_up ( + id numeric(19) not null, + up nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_up primary key (id) +); +create sequence esoft_del_up_seq as bigint start with 1 increment by 50; + +create table esoft_del_user ( + id numeric(19) not null, + user_name nvarchar(255), + version numeric(19) not null, + deleted integer default 0 not null, + constraint pk_esoft_del_user primary key (id) +); +create sequence esoft_del_user_seq as bigint start with 1 increment by 50; + +create table esoft_del_user_esoft_del_role ( + esoft_del_user_id numeric(19) not null, + esoft_del_role_id numeric(19) not null, + constraint pk_esoft_del_user_esoft_del_role primary key (esoft_del_user_id,esoft_del_role_id) +); + +create table esome_convert_type ( + id numeric(19) not null, + name nvarchar(255), + money numeric(28), + constraint pk_esome_convert_type primary key (id) +); +create sequence esome_convert_type_seq as bigint start with 1 increment by 50; + +create table esome_type ( + id integer not null, + currency nvarchar(3), + locale nvarchar(20), + time_zone nvarchar(20), + constraint pk_esome_type primary key (id) +); +create sequence esome_type_seq as bigint start with 1 increment by 50; + +create table etrans_many ( + id integer not null, + name nvarchar(255), + constraint pk_etrans_many primary key (id) +); +create sequence etrans_many_seq as bigint start with 1 increment by 50; + +create table rawinherit_uncle ( + id integer not null, + name nvarchar(255), + parent_id numeric(19) not null, + version numeric(19) not null, + constraint pk_rawinherit_uncle primary key (id) +); +create sequence rawinherit_uncle_seq as bigint start with 1 increment by 50; + +create table evanilla_collection ( + id integer not null, + name nvarchar(255), + constraint pk_evanilla_collection primary key (id) +); +create sequence evanilla_collection_seq as bigint start with 1 increment by 50; + +create table evanilla_collection_detail ( + id integer not null, + evanilla_collection_id integer not null, + something nvarchar(255), + constraint pk_evanilla_collection_detail primary key (id) +); +create sequence evanilla_collection_detail_seq as bigint start with 1 increment by 50; + +create table ewho_props ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + who_created nvarchar(255) not null, + who_modified nvarchar(255) not null, + constraint pk_ewho_props primary key (id) +); +create sequence ewho_props_seq as bigint start with 1 increment by 50; + +create table e_withinet ( + id numeric(19) not null, + name nvarchar(255), + inet_address nvarchar(50), + version numeric(19) not null, + constraint pk_e_withinet primary key (id) +); +create sequence e_withinet_seq as bigint start with 1 increment by 50; + +create table td_child ( + child_id integer not null, + child_name nvarchar(255), + parent_id integer not null, + constraint pk_td_child primary key (child_id) +); +create sequence td_child_seq as bigint start with 1 increment by 50; + +create table td_parent ( + parent_type nvarchar(31) not null, + parent_id integer not null, + parent_name nvarchar(255), + extended_name nvarchar(255), + constraint pk_td_parent primary key (parent_id) +); +create sequence td_parent_seq as bigint start with 1 increment by 50; + +create table empl ( + id numeric(19) not null, + name nvarchar(255), + age integer, + default_address_id numeric(19), + constraint pk_empl primary key (id) +); +create sequence empl_seq as bigint start with 1 increment by 50; + +create table feature_desc ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + constraint pk_feature_desc primary key (id) +); +create sequence feature_desc_seq as bigint start with 1 increment by 50; + +create table f_first ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_f_first primary key (id) +); +create sequence f_first_seq as bigint start with 1 increment by 50; + +create table foo ( + foo_id integer not null, + important_text nvarchar(255), + version integer not null, + constraint pk_foo primary key (foo_id) +); +create sequence foo_seq as bigint start with 1 increment by 50; + +create table gen_key_identity ( + id numeric(19) identity(1,1) not null, + description nvarchar(255), + constraint pk_gen_key_identity primary key (id) +); + +create table gen_key_sequence ( + id numeric(19) not null, + description nvarchar(255), + constraint pk_gen_key_sequence primary key (id) +); +create sequence SEQ as bigint start with 1 increment by 50; + +create table gen_key_table ( + id numeric(19) not null, + description nvarchar(255), + constraint pk_gen_key_table primary key (id) +); +create sequence gen_key_table_seq as bigint start with 1 increment by 50; + +create table grand_parent_person ( + identifier integer not null, + name nvarchar(255), + age integer, + some_bean_id integer, + family_name nvarchar(255), + address nvarchar(255), + constraint pk_grand_parent_person primary key (identifier) +); +create sequence grand_parent_person_seq as bigint start with 1 increment by 50; + +create table survey_group ( + id numeric(19) not null, + name nvarchar(255), + categoryobjectid numeric(19), + sequence_number integer not null, + constraint pk_survey_group primary key (id) +); +create sequence survey_group_seq as bigint start with 1 increment by 50; + +create table c_group ( + id numeric(19) not null, + inactive integer default 0 not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_c_group primary key (id) +); +create sequence c_group_seq as bigint start with 1 increment by 50; + +create table he_doc ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_he_doc primary key (id) +); +create sequence he_doc_seq as bigint start with 1 increment by 50; + +create table hx_link ( + id numeric(19) not null, + name nvarchar(255), + location nvarchar(255), + comments nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_hx_link primary key (id) +); +create sequence hx_link_seq as bigint start with 1 increment by 50; + +create table hx_link_doc ( + hx_link_id numeric(19) not null, + he_doc_id numeric(19) not null, + constraint pk_hx_link_doc primary key (hx_link_id,he_doc_id) +); + +create table hi_doc ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_hi_doc primary key (id) +); +create sequence hi_doc_seq as bigint start with 1 increment by 50; + +create table hi_link ( + id numeric(19) not null, + name nvarchar(255), + location nvarchar(255), + comments nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_hi_link primary key (id) +); +create sequence hi_link_seq as bigint start with 1 increment by 50; + +create table hi_link_doc ( + hi_link_id numeric(19) not null, + hi_doc_id numeric(19) not null, + constraint pk_hi_link_doc primary key (hi_link_id,hi_doc_id) +); + +create table imrelated ( + id numeric(19) not null, + name nvarchar(255), + owner_id numeric(19) not null, + constraint pk_imrelated primary key (id) +); +create sequence imrelated_seq as bigint start with 1 increment by 50; + +create table imroot ( + dtype nvarchar(31) not null, + id numeric(19) not null, + name nvarchar(255), + title nvarchar(255), + when_title datetime2, + constraint pk_imroot primary key (id) +); +create sequence imroot_seq as bigint start with 1 increment by 50; + +create table ixresource ( + dtype nvarchar(255), + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_ixresource primary key (id) +); + +create table info_company ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_info_company primary key (id) +); +create sequence info_company_seq as bigint start with 1 increment by 50; + +create table info_contact ( + id numeric(19) not null, + name nvarchar(255), + company_id numeric(19) not null, + version numeric(19) not null, + constraint pk_info_contact primary key (id) +); +create sequence info_contact_seq as bigint start with 1 increment by 50; + +create table info_customer ( + id numeric(19) not null, + name nvarchar(255), + company_id numeric(19), + version numeric(19) not null, + constraint pk_info_customer primary key (id) +); +create unique nonclustered index uq_info_customer_company_id on info_customer(company_id) where company_id is not null; +create sequence info_customer_seq as bigint start with 1 increment by 50; + +create table inner_report ( + id numeric(19) not null, + name nvarchar(255), + forecast_id numeric(19), + constraint pk_inner_report primary key (id) +); +create unique nonclustered index uq_inner_report_forecast_id on inner_report(forecast_id) where forecast_id is not null; +create sequence inner_report_seq as bigint start with 1 increment by 50; + +create table drel_invoice ( + id numeric(19) not null, + booking numeric(19), + version integer not null, + constraint pk_drel_invoice primary key (id) +); +create sequence drel_invoice_seq as bigint start with 1 increment by 50; + +create table item ( + customer integer not null, + itemnumber nvarchar(127) not null, + description nvarchar(255), + units nvarchar(255), + type integer not null, + region integer not null, + date_modified datetime2, + date_created datetime2, + modified_by nvarchar(255), + created_by nvarchar(255), + version numeric(19) not null, + constraint pk_item primary key (customer,itemnumber) +); + +create table monkey ( + mid numeric(19) not null, + name nvarchar(255), + food_preference nvarchar(255), + version numeric(19) not null, + constraint pk_monkey primary key (mid) +); +create sequence monkey_seq as bigint start with 1 increment by 50; + +create table trainer ( + tid numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_trainer primary key (tid) +); +create sequence trainer_seq as bigint start with 1 increment by 50; + +create table trainer_monkey ( + trainer_tid numeric(19) not null, + monkey_mid numeric(19) not null, + constraint uq_trainer_monkey_mid unique (monkey_mid), + constraint pk_trainer_monkey primary key (trainer_tid,monkey_mid) +); + +create table troop ( + pid numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_troop primary key (pid) +); +create sequence troop_seq as bigint start with 1 increment by 50; + +create table troop_monkey ( + troop_pid numeric(19) not null, + monkey_mid numeric(19) not null, + constraint uq_troop_monkey_mid unique (monkey_mid), + constraint pk_troop_monkey primary key (troop_pid,monkey_mid) +); + +create table l2_cldf_reset_bean ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_l2_cldf_reset_bean primary key (id) +); +create sequence l2_cldf_reset_bean_seq as bigint start with 1 increment by 50; + +create table l2_cldf_reset_bean_child ( + id numeric(19) not null, + parent_id numeric(19), + constraint pk_l2_cldf_reset_bean_child primary key (id) +); +create sequence l2_cldf_reset_bean_child_seq as bigint start with 1 increment by 50; + +create table level1 ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_level1 primary key (id) +); +create sequence level1_seq as bigint start with 1 increment by 50; + +create table level1_level4 ( + level1_id numeric(19) not null, + level4_id numeric(19) not null, + constraint pk_level1_level4 primary key (level1_id,level4_id) +); + +create table level1_level2 ( + level1_id numeric(19) not null, + level2_id numeric(19) not null, + constraint pk_level1_level2 primary key (level1_id,level2_id) +); + +create table level2 ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_level2 primary key (id) +); +create sequence level2_seq as bigint start with 1 increment by 50; + +create table level2_level3 ( + level2_id numeric(19) not null, + level3_id numeric(19) not null, + constraint pk_level2_level3 primary key (level2_id,level3_id) +); + +create table level3 ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_level3 primary key (id) +); +create sequence level3_seq as bigint start with 1 increment by 50; + +create table level4 ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_level4 primary key (id) +); +create sequence level4_seq as bigint start with 1 increment by 50; + +create table link ( + id numeric(19) not null, + name nvarchar(255), + location nvarchar(255), + when_publish datetime2, + link_comment nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + deleted integer default 0 not null, + constraint pk_link primary key (id) +); +create sequence link_seq as bigint start with 1 increment by 50; + +create table link_draft ( + id numeric(19) not null, + name nvarchar(255), + location nvarchar(255), + when_publish datetime2, + link_comment nvarchar(255), + dirty integer default 0 not null, + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + deleted integer default 0 not null, + constraint pk_link_draft primary key (id) +); +create sequence link_draft_seq as bigint start with 1 ; + +create table la_attr_value ( + id integer not null, + name nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_la_attr_value primary key (id) +); +create sequence la_attr_value_seq as bigint start with 1 increment by 50; + +create table la_attr_value_attribute ( + la_attr_value_id integer not null, + attribute_id integer not null, + constraint pk_la_attr_value_attribute primary key (la_attr_value_id,attribute_id) +); + +create table mmedia ( + type nvarchar(31) not null, + id numeric(19) not null, + url nvarchar(255), + note nvarchar(255), + constraint pk_mmedia primary key (id) +); +create sequence mmedia_seq as bigint start with 1 increment by 50; + +create table non_updateprop ( + id integer not null, + non_enum nvarchar(5), + name nvarchar(255), + note nvarchar(255), + constraint ck_non_updateprop_non_enum check ( non_enum in ('BEGIN','END')), + constraint pk_non_updateprop primary key (id) +); +create sequence non_updateprop_seq as bigint start with 1 increment by 50; + +create table mprinter ( + id numeric(19) not null, + name nvarchar(255), + flags numeric(19) not null, + current_state_id numeric(19), + last_swap_cyan_id numeric(19), + last_swap_magenta_id numeric(19), + last_swap_yellow_id numeric(19), + last_swap_black_id numeric(19), + version numeric(19) not null, + constraint pk_mprinter primary key (id) +); +create unique nonclustered index uq_mprinter_last_swap_cyan_id on mprinter(last_swap_cyan_id) where last_swap_cyan_id is not null; +create unique nonclustered index uq_mprinter_last_swap_magenta_id on mprinter(last_swap_magenta_id) where last_swap_magenta_id is not null; +create unique nonclustered index uq_mprinter_last_swap_yellow_id on mprinter(last_swap_yellow_id) where last_swap_yellow_id is not null; +create unique nonclustered index uq_mprinter_last_swap_black_id on mprinter(last_swap_black_id) where last_swap_black_id is not null; +create sequence mprinter_seq as bigint start with 1 increment by 50; + +create table mprinter_state ( + id numeric(19) not null, + flags numeric(19) not null, + printer_id numeric(19), + version numeric(19) not null, + constraint pk_mprinter_state primary key (id) +); +create sequence mprinter_state_seq as bigint start with 1 increment by 50; + +create table mprofile ( + id numeric(19) not null, + picture_id numeric(19), + name nvarchar(255), + constraint pk_mprofile primary key (id) +); +create sequence mprofile_seq as bigint start with 1 increment by 50; + +create table mprotected_construct_bean ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_mprotected_construct_bean primary key (id) +); +create sequence mprotected_construct_bean_seq as bigint start with 1 increment by 50; + +create table mrole ( + roleid integer not null, + role_name nvarchar(255), + constraint pk_mrole primary key (roleid) +); +create sequence mrole_seq as bigint start with 1 increment by 50; + +create table mrole_muser ( + mrole_roleid integer not null, + muser_userid integer not null, + constraint pk_mrole_muser primary key (mrole_roleid,muser_userid) +); + +create table msome_other ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_msome_other primary key (id) +); +create sequence msome_other_seq as bigint start with 1 increment by 50; + +create table muser ( + userid integer not null, + user_name nvarchar(255), + user_type_id integer, + constraint pk_muser primary key (userid) +); +create sequence muser_seq as bigint start with 1 increment by 50; + +create table muser_type ( + id integer not null, + name nvarchar(255), + constraint pk_muser_type primary key (id) +); +create sequence muser_type_seq as bigint start with 1 increment by 50; + +create table mail_box ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_mail_box primary key (id) +); +create sequence mail_box_seq as bigint start with 1 increment by 50; + +create table mail_user ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_mail_user primary key (id) +); +create sequence mail_user_seq as bigint start with 1 increment by 50; + +create table mail_user_inbox ( + mail_user_id numeric(19) not null, + mail_box_id numeric(19) not null, + constraint pk_mail_user_inbox primary key (mail_user_id,mail_box_id) +); + +create table mail_user_outbox ( + mail_user_id numeric(19) not null, + mail_box_id numeric(19) not null, + constraint pk_mail_user_outbox primary key (mail_user_id,mail_box_id) +); + +create table map_super_actual ( + id numeric(19) not null, + name nvarchar(255), + when_created datetime2 not null, + when_updated datetime2 not null, + constraint pk_map_super_actual primary key (id) +); +create sequence map_super_actual_seq as bigint start with 1 increment by 50; + +create table c_message ( + id numeric(19) not null, + title nvarchar(255), + body nvarchar(255), + conversation_id numeric(19), + user_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_c_message primary key (id) +); +create sequence c_message_seq as bigint start with 1 increment by 50; + +create table mnoc_role ( + role_id integer not null, + role_name nvarchar(255), + version integer not null, + constraint pk_mnoc_role primary key (role_id) +); +create sequence mnoc_role_seq as bigint start with 1 increment by 50; + +create table mnoc_user ( + user_id integer not null, + user_name nvarchar(255), + version integer not null, + constraint pk_mnoc_user primary key (user_id) +); +create sequence mnoc_user_seq as bigint start with 1 increment by 50; + +create table mnoc_user_mnoc_role ( + mnoc_user_user_id integer not null, + mnoc_role_role_id integer not null, + constraint pk_mnoc_user_mnoc_role primary key (mnoc_user_user_id,mnoc_role_role_id) +); + +create table mny_a ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_mny_a primary key (id) +); +create sequence mny_a_seq as bigint start with 1 increment by 50; + +create table mny_b ( + id numeric(19) not null, + name nvarchar(255), + a_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_mny_b primary key (id) +); +create sequence mny_b_seq as bigint start with 1 increment by 50; + +create table mny_b_mny_c ( + mny_b_id numeric(19) not null, + mny_c_id numeric(19) not null, + constraint pk_mny_b_mny_c primary key (mny_b_id,mny_c_id) +); + +create table mny_c ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_mny_c primary key (id) +); +create sequence mny_c_seq as bigint start with 1 increment by 50; + +create table mny_topic ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_mny_topic primary key (id) +); +create sequence mny_topic_seq as bigint start with 1 increment by 50; + +create table subtopics ( + topic numeric(19) not null, + subtopic numeric(19) not null, + constraint pk_subtopics primary key (topic,subtopic) +); + +create table mp_role ( + id numeric(19) not null, + mp_user_id numeric(19) not null, + code nvarchar(255), + organization_id numeric(19), + constraint pk_mp_role primary key (id) +); +create sequence mp_role_seq as bigint start with 1 increment by 50; + +create table mp_user ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_mp_user primary key (id) +); +create sequence mp_user_seq as bigint start with 1 increment by 50; + +create table ms_many_a ( + aid numeric(19) not null, + name nvarchar(255), + ms_many_a_many_b integer default 0 not null, + ms_many_b integer default 0 not null, + deleted integer default 0 not null, + constraint pk_ms_many_a primary key (aid) +); +create sequence ms_many_a_seq as bigint start with 1 increment by 50; + +create table ms_many_a_many_b ( + ms_many_a_aid numeric(19) not null, + ms_many_b_bid numeric(19) not null, + constraint pk_ms_many_a_many_b primary key (ms_many_a_aid,ms_many_b_bid) +); + +create table ms_many_b ( + bid numeric(19) not null, + name nvarchar(255), + deleted integer default 0 not null, + constraint pk_ms_many_b primary key (bid) +); +create sequence ms_many_b_seq as bigint start with 1 increment by 50; + +create table ms_many_b_many_a ( + ms_many_b_bid numeric(19) not null, + ms_many_a_aid numeric(19) not null, + constraint pk_ms_many_b_many_a primary key (ms_many_b_bid,ms_many_a_aid) +); + +create table my_lob_size ( + id integer not null, + name nvarchar(255), + my_count integer not null, + my_lob nvarchar(max), + constraint pk_my_lob_size primary key (id) +); +create sequence my_lob_size_seq as bigint start with 1 increment by 50; + +create table my_lob_size_join_many ( + id integer not null, + something nvarchar(255), + other nvarchar(255), + parent_id integer, + constraint pk_my_lob_size_join_many primary key (id) +); +create sequence my_lob_size_join_many_seq as bigint start with 1 increment by 50; + +create table noidbean ( + name nvarchar(255), + subject nvarchar(255), + when_created datetime2 not null +); + +create table o_cached_bean ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_o_cached_bean primary key (id) +); +create sequence o_cached_bean_seq as bigint start with 1 increment by 50; + +create table o_cached_bean_country ( + o_cached_bean_id numeric(19) not null, + o_country_code nvarchar(2) not null, + constraint pk_o_cached_bean_country primary key (o_cached_bean_id,o_country_code) +); + +create table o_cached_bean_child ( + id numeric(19) not null, + cached_bean_id numeric(19), + constraint pk_o_cached_bean_child primary key (id) +); +create sequence o_cached_bean_child_seq as bigint start with 1 increment by 50; + +create table o_cached_natkey ( + id numeric(19) not null, + store nvarchar(255), + sku nvarchar(255), + description nvarchar(255), + constraint pk_o_cached_natkey primary key (id) +); +create sequence o_cached_natkey_seq as bigint start with 1 increment by 50; + +create table o_cached_natkey3 ( + id numeric(19) not null, + store nvarchar(255), + code integer not null, + sku nvarchar(255), + description nvarchar(255), + constraint pk_o_cached_natkey3 primary key (id) +); +create sequence o_cached_natkey3_seq as bigint start with 1 increment by 50; + +create table ocar ( + id integer not null, + vin nvarchar(255), + name nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_ocar primary key (id) +); +create sequence ocar_seq as bigint start with 1 increment by 50; + +create table ocompany ( + id integer not null, + corp_id nvarchar(50), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_ocompany primary key (id) +); +create unique nonclustered index uq_ocompany_corp_id on ocompany(corp_id) where corp_id is not null; +create sequence ocompany_seq as bigint start with 1 increment by 50; + +create table oengine ( + engine_id nvarchar(40) not null, + short_desc nvarchar(255), + car_id integer, + version integer not null, + constraint pk_oengine primary key (engine_id) +); +create unique nonclustered index uq_oengine_car_id on oengine(car_id) where car_id is not null; + +create table ogear_box ( + id nvarchar(40) not null, + box_desc nvarchar(255), + box_size integer, + car_id integer, + version integer not null, + constraint pk_ogear_box primary key (id) +); +create unique nonclustered index uq_ogear_box_car_id on ogear_box(car_id) where car_id is not null; + +create table oroad_show_msg ( + id integer not null, + company_id integer not null, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint uq_oroad_show_msg_company_id unique (company_id), + constraint pk_oroad_show_msg primary key (id) +); +create sequence oroad_show_msg_seq as bigint start with 1 increment by 50; + +create table om_ordered_detail ( + id numeric(19) not null, + name nvarchar(255), + master_id numeric(19), + version numeric(19) not null, + sort_order integer, + constraint pk_om_ordered_detail primary key (id) +); +create sequence om_ordered_detail_seq as bigint start with 1 increment by 50; + +create table om_ordered_master ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_om_ordered_master primary key (id) +); +create sequence om_ordered_master_seq as bigint start with 1 increment by 50; + +create table o_order ( + id integer not null, + status integer, + order_date date, + ship_date date, + kcustomer_id integer not null, + cretime datetime2 not null, + updtime datetime2 not null, + constraint ck_o_order_status check ( status in (0,1,2,3)), + constraint pk_o_order primary key (id) +); +create sequence o_order_seq as bigint start with 1 increment by 50; + +create table o_order_detail ( + id integer not null, + order_id integer not null, + order_qty integer, + ship_qty integer, + unit_price float(32), + product_id integer, + cretime datetime2, + updtime datetime2 not null, + constraint pk_o_order_detail primary key (id) +); +create sequence o_order_detail_seq as bigint start with 1 increment by 50; + +create table s_orders ( + uuid nvarchar(40) not null, + constraint pk_s_orders primary key (uuid) +); + +create table s_order_items ( + uuid nvarchar(40) not null, + product_variant_uuid nvarchar(255), + order_uuid nvarchar(40), + quantity integer not null, + amount numeric(28), + constraint pk_s_order_items primary key (uuid) +); + +create table or_order_ship ( + id integer not null, + order_id integer, + ship_time datetime2, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_or_order_ship primary key (id) +); +create sequence or_order_ship_seq as bigint start with 1 increment by 50; + +create table organisation ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_organisation primary key (id) +); +create sequence organisation_seq as bigint start with 1 increment by 50; + +create table oto_bchild ( + master_id numeric(19) not null, + child nvarchar(255), + constraint pk_oto_bchild primary key (master_id) +); +create sequence oto_bchild_seq as bigint start with 1 increment by 50; + +create table oto_bmaster ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_oto_bmaster primary key (id) +); +create sequence oto_bmaster_seq as bigint start with 1 increment by 50; + +create table oto_child ( + id integer not null, + name nvarchar(255), + master_id numeric(19), + constraint pk_oto_child primary key (id) +); +create unique nonclustered index uq_oto_child_master_id on oto_child(master_id) where master_id is not null; +create sequence oto_child_seq as bigint start with 1 increment by 50; + +create table oto_cust ( + cid numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_oto_cust primary key (cid) +); +create sequence oto_cust_seq as bigint start with 1 increment by 50; + +create table oto_cust_address ( + aid numeric(19) not null, + line1 nvarchar(255), + line2 nvarchar(255), + line3 nvarchar(255), + customer_cid numeric(19), + version numeric(19) not null, + constraint pk_oto_cust_address primary key (aid) +); +create unique nonclustered index uq_oto_cust_address_customer_cid on oto_cust_address(customer_cid) where customer_cid is not null; +create sequence oto_cust_address_seq as bigint start with 1 increment by 50; + +create table oto_master ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_oto_master primary key (id) +); +create sequence oto_master_seq as bigint start with 1 increment by 50; + +create table oto_prime ( + pid numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_oto_prime primary key (pid) +); +create sequence oto_prime_seq as bigint start with 1 increment by 50; + +create table oto_prime_extra ( + eid numeric(19) not null, + extra nvarchar(255), + version numeric(19) not null, + constraint pk_oto_prime_extra primary key (eid) +); + +create table oto_th_many ( + id numeric(19) not null, + oto_th_top_id numeric(19) not null, + many nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_oto_th_many primary key (id) +); +create sequence oto_th_many_seq as bigint start with 1 increment by 50; + +create table oto_th_one ( + id numeric(19) not null, + one integer default 0 not null, + many_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_oto_th_one primary key (id) +); +create unique nonclustered index uq_oto_th_one_many_id on oto_th_one(many_id) where many_id is not null; +create sequence oto_th_one_seq as bigint start with 1 increment by 50; + +create table oto_th_top ( + id numeric(19) not null, + topp nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_oto_th_top primary key (id) +); +create sequence oto_th_top_seq as bigint start with 1 increment by 50; + +create table oto_ubprime ( + pid nvarchar(40) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_oto_ubprime primary key (pid) +); + +create table oto_ubprime_extra ( + eid nvarchar(40) not null, + extra nvarchar(255), + version numeric(19) not null, + constraint pk_oto_ubprime_extra primary key (eid) +); + +create table oto_uprime ( + pid nvarchar(40) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_oto_uprime primary key (pid) +); + +create table oto_uprime_extra ( + eid nvarchar(40) not null, + extra nvarchar(255), + version numeric(19) not null, + constraint pk_oto_uprime_extra primary key (eid) +); + +create table pfile ( + id integer not null, + name nvarchar(255), + file_content_id integer, + file_content2_id integer, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_pfile primary key (id) +); +create unique nonclustered index uq_pfile_file_content_id on pfile(file_content_id) where file_content_id is not null; +create unique nonclustered index uq_pfile_file_content2_id on pfile(file_content2_id) where file_content2_id is not null; +create sequence pfile_seq as bigint start with 1 increment by 50; + +create table pfile_content ( + id integer not null, + content image, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_pfile_content primary key (id) +); +create sequence pfile_content_seq as bigint start with 1 increment by 50; + +create table paggview ( + pview_id nvarchar(40), + amount integer not null +); +create unique nonclustered index uq_paggview_pview_id on paggview(pview_id) where pview_id is not null; + +create table pallet_location ( + type nvarchar(31) not null, + id integer not null, + zone_sid integer not null, + attribute nvarchar(255), + constraint pk_pallet_location primary key (id) +); +create sequence pallet_location_seq as bigint start with 1 increment by 50; + +create table parcel ( + parcelid numeric(19) not null, + description nvarchar(255), + constraint pk_parcel primary key (parcelid) +); +create sequence parcel_seq as bigint start with 1 increment by 50; + +create table parcel_location ( + parcellocid numeric(19) not null, + location nvarchar(255), + parcelid numeric(19), + constraint pk_parcel_location primary key (parcellocid) +); +create unique nonclustered index uq_parcel_location_parcelid on parcel_location(parcelId) where parcelId is not null; +create sequence parcel_location_seq as bigint start with 1 increment by 50; + +create table rawinherit_parent ( + type nvarchar(31) not null, + id numeric(19) not null, + val integer, + more nvarchar(255), + constraint pk_rawinherit_parent primary key (id) +); +create sequence rawinherit_parent_seq as bigint start with 1 increment by 50; + +create table rawinherit_parent_rawinherit_data ( + rawinherit_parent_id numeric(19) not null, + rawinherit_data_id numeric(19) not null, + constraint pk_rawinherit_parent_rawinherit_data primary key (rawinherit_parent_id,rawinherit_data_id) +); + +create table parent_person ( + identifier integer not null, + name nvarchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name nvarchar(255), + address nvarchar(255), + constraint pk_parent_person primary key (identifier) +); +create sequence parent_person_seq as bigint start with 1 increment by 50; + +create table c_participation ( + id numeric(19) not null, + rating integer, + type integer, + conversation_id numeric(19) not null, + user_id numeric(19) not null, + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint ck_c_participation_type check ( type in (0,1)), + constraint pk_c_participation primary key (id) +); +create sequence c_participation_seq as bigint start with 1 increment by 50; + +create table mt_permission ( + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_mt_permission primary key (id) +); + +create table persistent_file ( + id integer not null, + name nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_persistent_file primary key (id) +); +create sequence persistent_file_seq as bigint start with 1 increment by 50; + +create table persistent_file_content ( + id integer not null, + persistent_file_id integer, + content image, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_persistent_file_content primary key (id) +); +create unique nonclustered index uq_persistent_file_content_persistent_file_id on persistent_file_content(persistent_file_id) where persistent_file_id is not null; +create sequence persistent_file_content_seq as bigint start with 1 increment by 50; + +create table persons ( + id numeric(19) not null, + surname nvarchar(64) not null, + name nvarchar(64) not null, + constraint pk_persons primary key (id) +); +create sequence PERSONS_seq as bigint start with 1000 increment by 40; + +create table person ( + oid numeric(19) not null, + default_address_oid numeric(19), + version integer not null, + constraint pk_person primary key (oid) +); +create sequence person_seq as bigint start with 1 increment by 50; + +create table phones ( + id numeric(19) not null, + phone_number nvarchar(7) not null, + person_id numeric(19) not null, + constraint uq_phones_phone_number unique (phone_number), + constraint pk_phones primary key (id) +); +create sequence PHONES_seq as bigint start with 1 increment by 50; + +create table primary_revision ( + id numeric(19) not null, + revision integer not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_primary_revision primary key (id,revision) +); + +create table o_product ( + id integer not null, + sku nvarchar(20), + name nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + constraint pk_o_product primary key (id) +); +create sequence o_product_seq as bigint start with 1 increment by 50; + +create table pp ( + id nvarchar(40) not null, + name nvarchar(255), + value nvarchar(100) not null, + constraint pk_pp primary key (id) +); + +create table pp_to_ww ( + pp_id nvarchar(40) not null, + ww_id nvarchar(40) not null, + constraint pk_pp_to_ww primary key (pp_id,ww_id) +); + +create table question ( + id numeric(19) not null, + name nvarchar(255), + groupobjectid numeric(19), + sequence_number integer not null, + constraint pk_question primary key (id) +); +create sequence question_seq as bigint start with 1 increment by 50; + +create table rcustomer ( + company nvarchar(127) not null, + name nvarchar(127) not null, + description nvarchar(255), + constraint pk_rcustomer primary key (company,name) +); + +create table r_orders ( + company nvarchar(127) not null, + order_number integer not null, + customername nvarchar(127), + item nvarchar(255), + constraint pk_r_orders primary key (company,order_number) +); + +create table region ( + customer integer not null, + type integer not null, + description nvarchar(255), + version numeric(19) not null, + constraint pk_region primary key (customer,type) +); + +create table resourcefile ( + id nvarchar(64) not null, + parentresourcefileid nvarchar(64), + name nvarchar(128) not null, + constraint pk_resourcefile primary key (id) +); + +create table em_role ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_em_role primary key (id) +); +create sequence em_role_seq as bigint start with 1 increment by 50; + +create table mt_role ( + id nvarchar(40) not null, + name nvarchar(50), + tenant_id nvarchar(40), + version numeric(19) not null, + constraint pk_mt_role primary key (id) +); + +create table mt_role_permission ( + mt_role_id nvarchar(40) not null, + mt_permission_id nvarchar(40) not null, + constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) +); + +create table f_second ( + id numeric(19) not null, + mod_name nvarchar(255), + first numeric(19), + title nvarchar(255), + constraint pk_f_second primary key (id) +); +create unique nonclustered index uq_f_second_first on f_second(first) where first is not null; +create sequence f_second_seq as bigint start with 1 increment by 50; + +create table section ( + id integer not null, + article_id integer, + type integer, + content nvarchar(max), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint ck_section_type check ( type in (0,1)), + constraint pk_section primary key (id) +); +create sequence section_seq as bigint start with 1 increment by 50; + +create table self_parent ( + id numeric(19) not null, + name nvarchar(255), + parent_id numeric(19), + version numeric(19) not null, + constraint pk_self_parent primary key (id) +); +create sequence self_parent_seq as bigint start with 1 increment by 50; + +create table self_ref_customer ( + id numeric(19) not null, + name nvarchar(255), + referred_by_id numeric(19), + constraint pk_self_ref_customer primary key (id) +); +create sequence self_ref_customer_seq as bigint start with 1 increment by 50; + +create table self_ref_example ( + id numeric(19) not null, + name nvarchar(255) not null, + parent_id numeric(19), + constraint pk_self_ref_example primary key (id) +); +create sequence self_ref_example_seq as bigint start with 1 increment by 50; + +create table some_enum_bean ( + id numeric(19) not null, + some_enum integer, + name nvarchar(255), + constraint ck_some_enum_bean_some_enum check ( some_enum in (0,1)), + constraint pk_some_enum_bean primary key (id) +); +create sequence some_enum_bean_seq as bigint start with 1 increment by 50; + +create table some_file_bean ( + id numeric(19) not null, + name nvarchar(255), + content image, + version numeric(19) not null, + constraint pk_some_file_bean primary key (id) +); +create sequence some_file_bean_seq as bigint start with 1 increment by 50; + +create table some_new_types_bean ( + id numeric(19) not null, + dow integer, + mth integer, + yr integer, + yr_mth date, + local_date date, + local_date_time datetime2, + offset_date_time datetime2, + zoned_date_time datetime2, + instant datetime2, + zone_id nvarchar(60), + zone_offset nvarchar(60), + path nvarchar(255), + period nvarchar(20), + version numeric(19) not null, + constraint ck_some_new_types_bean_dow check ( dow in (1,2,3,4,5,6,7)), + constraint ck_some_new_types_bean_mth check ( mth in (1,2,3,4,5,6,7,8,9,10,11,12)), + constraint pk_some_new_types_bean primary key (id) +); +create sequence some_new_types_bean_seq as bigint start with 1 increment by 50; + +create table some_period_bean ( + id numeric(19) not null, + anniversary date, + version numeric(19) not null, + constraint pk_some_period_bean primary key (id) +); +create sequence some_period_bean_seq as bigint start with 1 increment by 50; + +create table stockforecast ( + type nvarchar(31) not null, + id numeric(19) not null, + inner_report_id numeric(19), + constraint pk_stockforecast primary key (id) +); +create sequence stockforecast_seq as bigint start with 1 increment by 50; + +create table sub_section ( + id integer not null, + section_id integer, + title nvarchar(255), + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_sub_section primary key (id) +); +create sequence sub_section_seq as bigint start with 1 increment by 50; + +create table sub_type ( + sub_type_id integer not null, + description nvarchar(255), + version numeric(19) not null, + constraint pk_sub_type primary key (sub_type_id) +); +create sequence sub_type_seq as bigint start with 1 increment by 50; + +create table survey ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_survey primary key (id) +); +create sequence survey_seq as bigint start with 1 increment by 50; + +create table tbytes_only ( + id integer not null, + content image, + constraint pk_tbytes_only primary key (id) +); +create sequence tbytes_only_seq as bigint start with 1 increment by 50; + +create table tcar ( + type nvarchar(31) not null, + plate_no nvarchar(32) not null, + truckload numeric(19), + constraint pk_tcar primary key (plate_no) +); + +create table tevent ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_tevent primary key (id) +); +create sequence tevent_seq as bigint start with 1 increment by 50; + +create table tevent_many ( + id numeric(19) not null, + description nvarchar(255), + event_id numeric(19), + units integer not null, + amount float(32) not null, + version numeric(19) not null, + constraint pk_tevent_many primary key (id) +); +create sequence tevent_many_seq as bigint start with 1 increment by 50; + +create table tevent_one ( + id numeric(19) not null, + name nvarchar(255), + status integer, + event_id numeric(19), + version numeric(19) not null, + constraint ck_tevent_one_status check ( status in (0,1)), + constraint pk_tevent_one primary key (id) +); +create unique nonclustered index uq_tevent_one_event_id on tevent_one(event_id) where event_id is not null; +create sequence tevent_one_seq as bigint start with 1 increment by 50; + +create table tint_root ( + my_type integer not null, + id integer not null, + name nvarchar(255), + child_property nvarchar(255), + constraint pk_tint_root primary key (id) +); +create sequence tint_root_seq as bigint start with 1 increment by 50; + +create table tjoda_entity ( + id integer not null, + local_time time, + constraint pk_tjoda_entity primary key (id) +); +create sequence tjoda_entity_seq as bigint start with 1 increment by 50; + +create table t_mapsuper1 ( + id integer not null, + something nvarchar(255), + name nvarchar(255), + version integer not null, + constraint pk_t_mapsuper1 primary key (id) +); +create sequence t_mapsuper1_seq as bigint start with 1 increment by 50; + +create table t_oneb ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + active integer default 0 not null, + constraint pk_t_oneb primary key (id) +); +create sequence t_oneb_seq as bigint start with 1 increment by 50; + +create table t_detail_with_other_namexxxyy ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + some_unique_value nvarchar(127), + active integer default 0 not null, + master_id integer, + constraint pk_t_detail_with_other_namexxxyy primary key (id) +); +create unique nonclustered index uq_t_detail_with_other_namexxxyy_some_unique_value on t_detail_with_other_namexxxyy(some_unique_value) where some_unique_value is not null; +create sequence t_atable_detail_seq as bigint start with 1 increment by 50; + +create table ts_detail_two ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + active integer default 0 not null, + master_id integer, + constraint pk_ts_detail_two primary key (id) +); +create sequence ts_detail_two_seq as bigint start with 1 increment by 50; + +create table t_atable_thatisrelatively ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + active integer default 0 not null, + constraint pk_t_atable_thatisrelatively primary key (id) +); +create sequence t_atable_master_seq as bigint start with 1 increment by 50; + +create table ts_master_two ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + active integer default 0 not null, + constraint pk_ts_master_two primary key (id) +); +create sequence ts_master_two_seq as bigint start with 1 increment by 50; + +create table tuuid_entity ( + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_tuuid_entity primary key (id) +); + +create table twheel ( + id numeric(19) not null, + owner_plate_no nvarchar(32) not null, + constraint pk_twheel primary key (id) +); +create sequence twheel_seq as bigint start with 1 increment by 50; + +create table twith_pre_insert ( + id integer not null, + name nvarchar(255) not null, + title nvarchar(255), + constraint pk_twith_pre_insert primary key (id) +); +create sequence twith_pre_insert_seq as bigint start with 1 increment by 50; + +create table mt_tenant ( + id nvarchar(40) not null, + name nvarchar(255), + version numeric(19) not null, + constraint pk_mt_tenant primary key (id) +); + +create table test_annotation_base_entity ( + direct nvarchar(255), + meta nvarchar(255), + mixed nvarchar(255), + constraint_annotation nvarchar(40), + null1 nvarchar(255) not null, + null2 nvarchar(255), + null3 nvarchar(255) +); + +create table tire ( + id numeric(19) not null, + wheel numeric(19), + version integer not null, + constraint pk_tire primary key (id) +); +create unique nonclustered index uq_tire_wheel on tire(wheel) where wheel is not null; +create sequence tire_seq as bigint start with 1 increment by 50; + +create table sa_tire ( + id numeric(19) not null, + version integer not null, + constraint pk_sa_tire primary key (id) +); +create sequence sa_tire_seq as bigint start with 1 increment by 50; + +create table trip ( + id integer not null, + vehicle_driver_id integer, + destination nvarchar(255), + address_id smallint, + star_date datetime2, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_trip primary key (id) +); +create sequence trip_seq as bigint start with 1 increment by 50; + +create table truck_ref ( + id integer not null, + something nvarchar(255), + constraint pk_truck_ref primary key (id) +); +create sequence truck_ref_seq as bigint start with 1 increment by 50; + +create table type ( + customer integer not null, + type integer not null, + description nvarchar(255), + sub_type_id integer, + version numeric(19) not null, + constraint pk_type primary key (customer,type) +); + +create table tz_bean ( + id numeric(19) not null, + moda nvarchar(255), + ts datetime2, + tstz datetime2, + constraint pk_tz_bean primary key (id) +); +create sequence tz_bean_seq as bigint start with 1 increment by 50; + +create table ut_detail ( + id integer not null, + utmaster_id integer not null, + name nvarchar(255), + qty integer, + amount float(32), + version integer not null, + constraint pk_ut_detail primary key (id) +); +create sequence ut_detail_seq as bigint start with 1 increment by 50; + +create table ut_master ( + id integer not null, + name nvarchar(255), + description nvarchar(255), + version integer not null, + constraint pk_ut_master primary key (id) +); +create sequence ut_master_seq as bigint start with 1 increment by 50; + +create table uuone ( + id nvarchar(40) not null, + name nvarchar(255), + constraint pk_uuone primary key (id) +); + +create table uutwo ( + id nvarchar(40) not null, + name nvarchar(255), + master_id nvarchar(40), + constraint pk_uutwo primary key (id) +); + +create table c_user ( + id numeric(19) not null, + inactive integer default 0 not null, + name nvarchar(255), + email nvarchar(255), + password_hash nvarchar(255), + group_id numeric(19), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint pk_c_user primary key (id) +); +create sequence c_user_seq as bigint start with 1 increment by 50; + +create table tx_user ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_tx_user primary key (id) +); +create sequence tx_user_seq as bigint start with 1 increment by 50; + +create table g_user ( + id numeric(19) not null, + username nvarchar(255), + version numeric(19) not null, + constraint pk_g_user primary key (id) +); +create sequence g_user_seq as bigint start with 1 increment by 50; + +create table em_user ( + id numeric(19) not null, + name nvarchar(255), + constraint pk_em_user primary key (id) +); +create sequence em_user_seq as bigint start with 1 increment by 50; + +create table oto_user ( + id numeric(19) not null, + name nvarchar(255), + account_id numeric(19) not null, + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + constraint uq_oto_user_account_id unique (account_id), + constraint pk_oto_user primary key (id) +); +create sequence oto_user_seq as bigint start with 1 increment by 50; + +create table em_user_role ( + user_id numeric(19) not null, + role_id numeric(19) not null, + constraint pk_em_user_role primary key (user_id,role_id) +); + +create table vehicle ( + dtype nvarchar(3) not null, + id integer not null, + license_number nvarchar(255), + registration_date datetime2, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + siz nvarchar(1), + driver nvarchar(255), + car_ref_id integer, + notes nvarchar(255), + truck_ref_id integer, + capacity float(32), + constraint ck_vehicle_siz check ( siz in ('S','M','L','H')), + constraint pk_vehicle primary key (id) +); +create sequence vehicle_seq as bigint start with 1 increment by 50; + +create table vehicle_driver ( + id integer not null, + name nvarchar(255), + vehicle_id integer, + address_id smallint, + license_issued_on datetime2, + cretime datetime2 not null, + updtime datetime2 not null, + version numeric(19) not null, + constraint pk_vehicle_driver primary key (id) +); +create sequence vehicle_driver_seq as bigint start with 1 increment by 50; + +create table warehouses ( + id integer not null, + officezoneid integer, + constraint pk_warehouses primary key (id) +); +create sequence warehouses_seq as bigint start with 1 increment by 50; + +create table warehousesshippingzones ( + warehouseid integer not null, + shippingzoneid integer not null, + constraint pk_warehousesshippingzones primary key (warehouseid,shippingzoneid) +); + +create table sa_wheel ( + id numeric(19) not null, + tire numeric(19), + car numeric(19), + version integer not null, + constraint pk_sa_wheel primary key (id) +); +create sequence sa_wheel_seq as bigint start with 1 increment by 50; + +create table wheel ( + id numeric(19) not null, + version integer not null, + constraint pk_wheel primary key (id) +); +create sequence wheel_seq as bigint start with 1 increment by 50; + +create table sp_car_wheel ( + id numeric(19) not null, + version integer not null, + constraint pk_sp_car_wheel primary key (id) +); +create sequence sp_car_wheel_seq as bigint start with 1 increment by 50; + +create table g_who_props_otm ( + id numeric(19) not null, + name nvarchar(255), + version numeric(19) not null, + when_created datetime2 not null, + when_modified datetime2 not null, + who_created_id numeric(19), + who_modified_id numeric(19), + constraint pk_g_who_props_otm primary key (id) +); +create sequence g_who_props_otm_seq as bigint start with 1 increment by 50; + +create table with_zero ( + id numeric(19) not null, + name nvarchar(255), + parent_id integer, + lang nvarchar(2) default 'en' not null, + version numeric(19) not null, + constraint pk_with_zero primary key (id) +); +create sequence with_zero_seq as bigint start with 1 increment by 50; + +create table parent ( + id integer not null, + name nvarchar(255), + constraint pk_parent primary key (id) +); +create sequence parent_seq as bigint start with 1 increment by 50; + +create table wview ( + id nvarchar(40) not null, + name nvarchar(127) not null, + constraint uq_wview_name unique (name), + constraint pk_wview primary key (id) +); + +create table zones ( + type nvarchar(31) not null, + id integer not null, + attribute nvarchar(255), + constraint pk_zones primary key (id) +); +create sequence zones_seq as bigint start with 1 increment by 50; + +create index ix_contact_last_name_first_name on contact (last_name,first_name); +create index ix_e_basic_name on e_basic (name); +create index ix_bar_foo_id on bar (foo_id); +alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id); + +create index ix_addr_employee_id on addr (employee_id); +alter table addr add constraint fk_addr_employee_id foreign key (employee_id) references empl (id); + +create index ix_o_address_country_code on o_address (country_code); +alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code); + +alter table album add constraint fk_album_cover_id foreign key (cover_id) references cover (id); + +create index ix_animal_shelter_id on animal (shelter_id); +alter table animal add constraint fk_animal_shelter_id foreign key (shelter_id) references animal_shelter (id); + +create index ix_attribute_attribute_holder_id on attribute (attribute_holder_id); +alter table attribute add constraint fk_attribute_attribute_holder_id foreign key (attribute_holder_id) references attribute_holder (id); + +create index ix_bbookmark_user_id on bbookmark (user_id); +alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id); + +create index ix_bsite_user_site_id on bsite_user (site_id); +alter table bsite_user add constraint fk_bsite_user_site_id foreign key (site_id) references bsite (id); + +create index ix_bsite_user_user_id on bsite_user (user_id); +alter table bsite_user add constraint fk_bsite_user_user_id foreign key (user_id) references buser (id); + +create index ix_bsite_user_b_site on bsite_user_b (site); +alter table bsite_user_b add constraint fk_bsite_user_b_site foreign key (site) references bsite (id); + +create index ix_bsite_user_b_usr on bsite_user_b (usr); +alter table bsite_user_b add constraint fk_bsite_user_b_usr foreign key (usr) references buser (id); + +create index ix_bsite_user_c_site_uid on bsite_user_c (site_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_site_uid foreign key (site_uid) references bsite (id); + +create index ix_bsite_user_c_user_uid on bsite_user_c (user_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_user_uid foreign key (user_uid) references buser (id); + +alter table drel_booking add constraint fk_drel_booking_agent_invoice foreign key (agent_invoice) references drel_invoice (id); + +alter table drel_booking add constraint fk_drel_booking_client_invoice foreign key (client_invoice) references drel_invoice (id); + +create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key); + +create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); +alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id); + +create index ix_calculation_result_product_configuration_id on calculation_result (product_configuration_id); +alter table calculation_result add constraint fk_calculation_result_product_configuration_id foreign key (product_configuration_id) references configuration (id); + +create index ix_calculation_result_group_configuration_id on calculation_result (group_configuration_id); +alter table calculation_result add constraint fk_calculation_result_group_configuration_id foreign key (group_configuration_id) references configuration (id); + +create index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels (car); +alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_car foreign key (car) references sp_car_car (id); + +create index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels (wheel); +alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_wheel foreign key (wheel) references sp_car_wheel (id); + +create index ix_car_accessory_fuse_id on car_accessory (fuse_id); +alter table car_accessory add constraint fk_car_accessory_fuse_id foreign key (fuse_id) references car_fuse (id); + +create index ix_car_accessory_car_id on car_accessory (car_id); +alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id); + +create index ix_category_surveyobjectid on category (surveyobjectid); +alter table category add constraint fk_category_surveyobjectid foreign key (surveyobjectid) references survey (id); + +create index ix_child_person_some_bean_id on child_person (some_bean_id); +alter table child_person add constraint fk_child_person_some_bean_id foreign key (some_bean_id) references e_basic (id); + +create index ix_child_person_parent_identifier on child_person (parent_identifier); +alter table child_person add constraint fk_child_person_parent_identifier foreign key (parent_identifier) references parent_person (identifier); + +create index ix_configuration_configurations_id on configuration (configurations_id); +alter table configuration add constraint fk_configuration_configurations_id foreign key (configurations_id) references configurations (id); + +create index ix_contact_customer_id on contact (customer_id); +alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id); + +create index ix_contact_group_id on contact (group_id); +alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id); + +create index ix_contact_note_contact_id on contact_note (contact_id); +alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id); + +create index ix_c_conversation_group_id on c_conversation (group_id); +alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id); + +create index ix_o_customer_billing_address_id on o_customer (billing_address_id); +alter table o_customer add constraint fk_o_customer_billing_address_id foreign key (billing_address_id) references o_address (id); + +create index ix_o_customer_shipping_address_id on o_customer (shipping_address_id); +alter table o_customer add constraint fk_o_customer_shipping_address_id foreign key (shipping_address_id) references o_address (id); + +create index ix_dcredit_drol_dcredit on dcredit_drol (dcredit_id); +alter table dcredit_drol add constraint fk_dcredit_drol_dcredit foreign key (dcredit_id) references dcredit (id); + +create index ix_dcredit_drol_drol on dcredit_drol (drol_id); +alter table dcredit_drol add constraint fk_dcredit_drol_drol foreign key (drol_id) references drol (id); + +create index ix_drot_drol_drot on drot_drol (drot_id); +alter table drot_drol add constraint fk_drot_drol_drot foreign key (drot_id) references drot (id); + +create index ix_drot_drol_drol on drot_drol (drol_id); +alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) references drol (id); + +create index ix_dfk_cascade_one_id on dfk_cascade (one_id); +alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade; + +create index ix_dfk_set_null_one_id on dfk_set_null (one_id); +alter table dfk_set_null add constraint fk_dfk_set_null_one_id foreign key (one_id) references dfk_one (id) on delete set null on update set null; + +alter table doc add constraint fk_doc_id foreign key (id) references doc_draft (id); + +create index ix_doc_link_doc on doc_link (doc_id); +alter table doc_link add constraint fk_doc_link_doc foreign key (doc_id) references doc (id); + +create index ix_doc_link_link on doc_link (link_id); +alter table doc_link add constraint fk_doc_link_link foreign key (link_id) references link (id); + +alter table document add constraint fk_document_id foreign key (id) references document_draft (id); + +create index ix_document_organisation_id on document (organisation_id); +alter table document add constraint fk_document_organisation_id foreign key (organisation_id) references organisation (id); + +create index ix_document_draft_organisation_id on document_draft (organisation_id); +alter table document_draft add constraint fk_document_draft_organisation_id foreign key (organisation_id) references organisation (id); + +create index ix_document_media_document_id on document_media (document_id); +alter table document_media add constraint fk_document_media_document_id foreign key (document_id) references document (id); + +create index ix_document_media_draft_document_id on document_media_draft (document_id); +alter table document_media_draft add constraint fk_document_media_draft_document_id foreign key (document_id) references document_draft (id); + +create index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail (owner_id); +alter table ebasic_json_map_detail add constraint fk_ebasic_json_map_detail_owner_id foreign key (owner_id) references ebasic_json_map (id); + +create index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild (owner_id); +alter table ebasic_no_sdchild add constraint fk_ebasic_no_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id); + +create index ix_ebasic_sdchild_owner_id on ebasic_sdchild (owner_id); +alter table ebasic_sdchild add constraint fk_ebasic_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id); + +create index ix_eemb_inner_outer_id on eemb_inner (outer_id); +alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id); + +create index ix_einvoice_person_id on einvoice (person_id); +alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id); + +create index ix_enull_collection_detail_enull_collection_id on enull_collection_detail (enull_collection_id); +alter table enull_collection_detail add constraint fk_enull_collection_detail_enull_collection_id foreign key (enull_collection_id) references enull_collection (id); + +create index ix_eopt_one_a_b_id on eopt_one_a (b_id); +alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id); + +create index ix_eopt_one_b_c_id on eopt_one_b (c_id); +alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id); + +create index ix_esoft_del_book_lend_by_id on esoft_del_book (lend_by_id); +alter table esoft_del_book add constraint fk_esoft_del_book_lend_by_id foreign key (lend_by_id) references esoft_del_user (id); + +create index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user (esoft_del_book_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_book foreign key (esoft_del_book_id) references esoft_del_book (id); + +create index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user (esoft_del_user_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id); + +create index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down (esoft_del_mid_id); +alter table esoft_del_down add constraint fk_esoft_del_down_esoft_del_mid_id foreign key (esoft_del_mid_id) references esoft_del_mid (id); + +create index ix_esoft_del_mid_top_id on esoft_del_mid (top_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_top_id foreign key (top_id) references esoft_del_top (id); + +create index ix_esoft_del_mid_up_id on esoft_del_mid (up_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_up_id foreign key (up_id) references esoft_del_up (id); + +alter table esoft_del_one_a add constraint fk_esoft_del_one_a_oneb_id foreign key (oneb_id) references esoft_del_one_b (id); + +create index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user (esoft_del_role_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id); + +create index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user (esoft_del_user_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id); + +create index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role (esoft_del_user_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id); + +create index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role (esoft_del_role_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id); + +create index ix_rawinherit_uncle_parent_id on rawinherit_uncle (parent_id); +alter table rawinherit_uncle add constraint fk_rawinherit_uncle_parent_id foreign key (parent_id) references rawinherit_parent (id); + +create index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail (evanilla_collection_id); +alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_evanilla_collection_id foreign key (evanilla_collection_id) references evanilla_collection (id); + +create index ix_td_child_parent_id on td_child (parent_id); +alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id); + +create index ix_empl_default_address_id on empl (default_address_id); +alter table empl add constraint fk_empl_default_address_id foreign key (default_address_id) references addr (id); + +create index ix_grand_parent_person_some_bean_id on grand_parent_person (some_bean_id); +alter table grand_parent_person add constraint fk_grand_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id); + +create index ix_survey_group_categoryobjectid on survey_group (categoryobjectid); +alter table survey_group add constraint fk_survey_group_categoryobjectid foreign key (categoryobjectid) references category (id); + +create index ix_hx_link_doc_hx_link on hx_link_doc (hx_link_id); +alter table hx_link_doc add constraint fk_hx_link_doc_hx_link foreign key (hx_link_id) references hx_link (id); + +create index ix_hx_link_doc_he_doc on hx_link_doc (he_doc_id); +alter table hx_link_doc add constraint fk_hx_link_doc_he_doc foreign key (he_doc_id) references he_doc (id); + +create index ix_hi_link_doc_hi_link on hi_link_doc (hi_link_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_link foreign key (hi_link_id) references hi_link (id); + +create index ix_hi_link_doc_hi_doc on hi_link_doc (hi_doc_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_doc foreign key (hi_doc_id) references hi_doc (id); + +create index ix_imrelated_owner_id on imrelated (owner_id); +alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id); + +create index ix_info_contact_company_id on info_contact (company_id); +alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id); + +alter table info_customer add constraint fk_info_customer_company_id foreign key (company_id) references info_company (id); + +alter table inner_report add constraint fk_inner_report_forecast_id foreign key (forecast_id) references stockforecast (id); + +create index ix_drel_invoice_booking on drel_invoice (booking); +alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id); + +create index ix_item_etype on item (customer,type); +alter table item add constraint fk_item_etype foreign key (customer,type) references type (customer,type); + +create index ix_item_eregion on item (customer,region); +alter table item add constraint fk_item_eregion foreign key (customer,region) references region (customer,type); + +alter table trainer_monkey add constraint fk_trainer_monkey_trainer foreign key (trainer_tid) references trainer (tid); + +alter table trainer_monkey add constraint fk_trainer_monkey_monkey foreign key (monkey_mid) references monkey (mid); + +alter table troop_monkey add constraint fk_troop_monkey_troop foreign key (troop_pid) references troop (pid); + +alter table troop_monkey add constraint fk_troop_monkey_monkey foreign key (monkey_mid) references monkey (mid); + +create index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child (parent_id); +alter table l2_cldf_reset_bean_child add constraint fk_l2_cldf_reset_bean_child_parent_id foreign key (parent_id) references l2_cldf_reset_bean (id); + +create index ix_level1_level4_level1 on level1_level4 (level1_id); +alter table level1_level4 add constraint fk_level1_level4_level1 foreign key (level1_id) references level1 (id); + +create index ix_level1_level4_level4 on level1_level4 (level4_id); +alter table level1_level4 add constraint fk_level1_level4_level4 foreign key (level4_id) references level4 (id); + +create index ix_level1_level2_level1 on level1_level2 (level1_id); +alter table level1_level2 add constraint fk_level1_level2_level1 foreign key (level1_id) references level1 (id); + +create index ix_level1_level2_level2 on level1_level2 (level2_id); +alter table level1_level2 add constraint fk_level1_level2_level2 foreign key (level2_id) references level2 (id); + +create index ix_level2_level3_level2 on level2_level3 (level2_id); +alter table level2_level3 add constraint fk_level2_level3_level2 foreign key (level2_id) references level2 (id); + +create index ix_level2_level3_level3 on level2_level3 (level3_id); +alter table level2_level3 add constraint fk_level2_level3_level3 foreign key (level3_id) references level3 (id); + +alter table link add constraint fk_link_id foreign key (id) references link_draft (id); + +create index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute (la_attr_value_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_attr_value foreign key (la_attr_value_id) references la_attr_value (id); + +create index ix_la_attr_value_attribute_attribute on la_attr_value_attribute (attribute_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_attribute foreign key (attribute_id) references attribute (id); + +create index ix_mprinter_current_state_id on mprinter (current_state_id); +alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id); + +alter table mprinter add constraint fk_mprinter_last_swap_cyan_id foreign key (last_swap_cyan_id) references mprinter_state (id); + +alter table mprinter add constraint fk_mprinter_last_swap_magenta_id foreign key (last_swap_magenta_id) references mprinter_state (id); + +alter table mprinter add constraint fk_mprinter_last_swap_yellow_id foreign key (last_swap_yellow_id) references mprinter_state (id); + +alter table mprinter add constraint fk_mprinter_last_swap_black_id foreign key (last_swap_black_id) references mprinter_state (id); + +create index ix_mprinter_state_printer_id on mprinter_state (printer_id); +alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id); + +create index ix_mprofile_picture_id on mprofile (picture_id); +alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id); + +create index ix_mrole_muser_mrole on mrole_muser (mrole_roleid); +alter table mrole_muser add constraint fk_mrole_muser_mrole foreign key (mrole_roleid) references mrole (roleid); + +create index ix_mrole_muser_muser on mrole_muser (muser_userid); +alter table mrole_muser add constraint fk_mrole_muser_muser foreign key (muser_userid) references muser (userid); + +create index ix_muser_user_type_id on muser (user_type_id); +alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id); + +create index ix_mail_user_inbox_mail_user on mail_user_inbox (mail_user_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_user foreign key (mail_user_id) references mail_user (id); + +create index ix_mail_user_inbox_mail_box on mail_user_inbox (mail_box_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_box foreign key (mail_box_id) references mail_box (id); + +create index ix_mail_user_outbox_mail_user on mail_user_outbox (mail_user_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_user foreign key (mail_user_id) references mail_user (id); + +create index ix_mail_user_outbox_mail_box on mail_user_outbox (mail_box_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_box foreign key (mail_box_id) references mail_box (id); + +create index ix_c_message_conversation_id on c_message (conversation_id); +alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id); + +create index ix_c_message_user_id on c_message (user_id); +alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id); + +create index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role (mnoc_user_user_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_user foreign key (mnoc_user_user_id) references mnoc_user (user_id); + +create index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role (mnoc_role_role_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_role foreign key (mnoc_role_role_id) references mnoc_role (role_id); + +create index ix_mny_b_a_id on mny_b (a_id); +alter table mny_b add constraint fk_mny_b_a_id foreign key (a_id) references mny_a (id); + +create index ix_mny_b_mny_c_mny_b on mny_b_mny_c (mny_b_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_b foreign key (mny_b_id) references mny_b (id); + +create index ix_mny_b_mny_c_mny_c on mny_b_mny_c (mny_c_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_c foreign key (mny_c_id) references mny_c (id); + +create index ix_subtopics_mny_topic_1 on subtopics (topic); +alter table subtopics add constraint fk_subtopics_mny_topic_1 foreign key (topic) references mny_topic (id); + +create index ix_subtopics_mny_topic_2 on subtopics (subtopic); +alter table subtopics add constraint fk_subtopics_mny_topic_2 foreign key (subtopic) references mny_topic (id); + +create index ix_mp_role_mp_user_id on mp_role (mp_user_id); +alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id); + +create index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b (ms_many_a_aid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid); + +create index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b (ms_many_b_bid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid); + +create index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a (ms_many_b_bid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid); + +create index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a (ms_many_a_aid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid); + +create index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many (parent_id); +alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_parent_id foreign key (parent_id) references my_lob_size (id); + +create index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country (o_cached_bean_id); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_cached_bean foreign key (o_cached_bean_id) references o_cached_bean (id); + +create index ix_o_cached_bean_country_o_country on o_cached_bean_country (o_country_code); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_country foreign key (o_country_code) references o_country (code); + +create index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child (cached_bean_id); +alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_bean_id foreign key (cached_bean_id) references o_cached_bean (id); + +alter table oengine add constraint fk_oengine_car_id foreign key (car_id) references ocar (id); + +alter table ogear_box add constraint fk_ogear_box_car_id foreign key (car_id) references ocar (id); + +alter table oroad_show_msg add constraint fk_oroad_show_msg_company_id foreign key (company_id) references ocompany (id); + +create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id); +alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id); + +create index ix_o_order_kcustomer_id on o_order (kcustomer_id); +alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id); + +create index ix_o_order_detail_order_id on o_order_detail (order_id); +alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id); + +create index ix_o_order_detail_product_id on o_order_detail (product_id); +alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id); + +create index ix_s_order_items_order_uuid on s_order_items (order_uuid); +alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid); + +create index ix_or_order_ship_order_id on or_order_ship (order_id); +alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id); + +alter table oto_bchild add constraint fk_oto_bchild_master_id foreign key (master_id) references oto_bmaster (id); + +alter table oto_child add constraint fk_oto_child_master_id foreign key (master_id) references oto_master (id); + +alter table oto_cust_address add constraint fk_oto_cust_address_customer_cid foreign key (customer_cid) references oto_cust (cid); + +alter table oto_prime_extra add constraint fk_oto_prime_extra_eid foreign key (eid) references oto_prime (pid); + +create index ix_oto_th_many_oto_th_top_id on oto_th_many (oto_th_top_id); +alter table oto_th_many add constraint fk_oto_th_many_oto_th_top_id foreign key (oto_th_top_id) references oto_th_top (id); + +alter table oto_th_one add constraint fk_oto_th_one_many_id foreign key (many_id) references oto_th_many (id); + +alter table oto_ubprime_extra add constraint fk_oto_ubprime_extra_eid foreign key (eid) references oto_ubprime (pid); + +alter table oto_uprime_extra add constraint fk_oto_uprime_extra_eid foreign key (eid) references oto_uprime (pid); + +alter table pfile add constraint fk_pfile_file_content_id foreign key (file_content_id) references pfile_content (id); + +alter table pfile add constraint fk_pfile_file_content2_id foreign key (file_content2_id) references pfile_content (id); + +alter table paggview add constraint fk_paggview_pview_id foreign key (pview_id) references pp (id); + +create index ix_pallet_location_zone_sid on pallet_location (zone_sid); +alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id); + +alter table parcel_location add constraint fk_parcel_location_parcelid foreign key (parcelid) references parcel (parcelid); + +create index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data (rawinherit_parent_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_parent foreign key (rawinherit_parent_id) references rawinherit_parent (id); + +create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id); + +create index ix_parent_person_some_bean_id on parent_person (some_bean_id); +alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id); + +create index ix_parent_person_parent_identifier on parent_person (parent_identifier); +alter table parent_person add constraint fk_parent_person_parent_identifier foreign key (parent_identifier) references grand_parent_person (identifier); + +create index ix_c_participation_conversation_id on c_participation (conversation_id); +alter table c_participation add constraint fk_c_participation_conversation_id foreign key (conversation_id) references c_conversation (id); + +create index ix_c_participation_user_id on c_participation (user_id); +alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id); + +alter table persistent_file_content add constraint fk_persistent_file_content_persistent_file_id foreign key (persistent_file_id) references persistent_file (id); + +create index ix_person_default_address_oid on person (default_address_oid); +alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid); + +create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id); + +create index ix_pp_to_ww_pp on pp_to_ww (pp_id); +alter table pp_to_ww add constraint fk_pp_to_ww_pp foreign key (pp_id) references pp (id); + +create index ix_pp_to_ww_wview on pp_to_ww (ww_id); +alter table pp_to_ww add constraint fk_pp_to_ww_wview foreign key (ww_id) references wview (id); + +create index ix_question_groupobjectid on question (groupobjectid); +alter table question add constraint fk_question_groupobjectid foreign key (groupobjectid) references survey_group (id); + +create index ix_r_orders_customer on r_orders (company,customername); +alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name); + +create index ix_resourcefile_parentresourcefileid on resourcefile (parentresourcefileid); +alter table resourcefile add constraint fk_resourcefile_parentresourcefileid foreign key (parentresourcefileid) references resourcefile (id); + +create index ix_mt_role_tenant_id on mt_role (tenant_id); +alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id); + +create index ix_mt_role_permission_mt_role on mt_role_permission (mt_role_id); +alter table mt_role_permission add constraint fk_mt_role_permission_mt_role foreign key (mt_role_id) references mt_role (id); + +create index ix_mt_role_permission_mt_permission on mt_role_permission (mt_permission_id); +alter table mt_role_permission add constraint fk_mt_role_permission_mt_permission foreign key (mt_permission_id) references mt_permission (id); + +alter table f_second add constraint fk_f_second_first foreign key (first) references f_first (id); + +create index ix_section_article_id on section (article_id); +alter table section add constraint fk_section_article_id foreign key (article_id) references article (id); + +create index ix_self_parent_parent_id on self_parent (parent_id); +alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id); + +create index ix_self_ref_customer_referred_by_id on self_ref_customer (referred_by_id); +alter table self_ref_customer add constraint fk_self_ref_customer_referred_by_id foreign key (referred_by_id) references self_ref_customer (id); + +create index ix_self_ref_example_parent_id on self_ref_example (parent_id); +alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id); + +create index ix_stockforecast_inner_report_id on stockforecast (inner_report_id); +alter table stockforecast add constraint fk_stockforecast_inner_report_id foreign key (inner_report_id) references inner_report (id); + +create index ix_sub_section_section_id on sub_section (section_id); +alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id); + +create index ix_tevent_many_event_id on tevent_many (event_id); +alter table tevent_many add constraint fk_tevent_many_event_id foreign key (event_id) references tevent_one (id); + +alter table tevent_one add constraint fk_tevent_one_event_id foreign key (event_id) references tevent (id); + +create index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy (master_id); +alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexxxyy_master_id foreign key (master_id) references t_atable_thatisrelatively (id); + +create index ix_ts_detail_two_master_id on ts_detail_two (master_id); +alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id); + +create index ix_twheel_owner_plate_no on twheel (owner_plate_no); +alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no); + +alter table tire add constraint fk_tire_wheel foreign key (wheel) references wheel (id); + +create index ix_trip_vehicle_driver_id on trip (vehicle_driver_id); +alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id); + +create index ix_trip_address_id on trip (address_id); +alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id); + +create index ix_type_sub_type_id on type (sub_type_id); +alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id); + +create index ix_ut_detail_utmaster_id on ut_detail (utmaster_id); +alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id); + +create index ix_uutwo_master_id on uutwo (master_id); +alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id); + +create index ix_c_user_group_id on c_user (group_id); +alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id); + +alter table oto_user add constraint fk_oto_user_account_id foreign key (account_id) references oto_account (id); + +create index ix_em_user_role_user_id on em_user_role (user_id); +alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id); + +create index ix_em_user_role_role_id on em_user_role (role_id); +alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id); + +create index ix_vehicle_car_ref_id on vehicle (car_ref_id); +alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id); + +create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); +alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id); + +create index ix_vehicle_driver_vehicle_id on vehicle_driver (vehicle_id); +alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id); + +create index ix_vehicle_driver_address_id on vehicle_driver (address_id); +alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id); + +create index ix_warehouses_officezoneid on warehouses (officezoneid); +alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id); + +create index ix_warehousesshippingzones_warehouses on warehousesshippingzones (warehouseid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_warehouses foreign key (warehouseid) references warehouses (id); + +create index ix_warehousesshippingzones_zones on warehousesshippingzones (shippingzoneid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zones foreign key (shippingzoneid) references zones (id); + +create index ix_sa_wheel_tire on sa_wheel (tire); +alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id); + +create index ix_sa_wheel_car on sa_wheel (car); +alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id); + +create index ix_g_who_props_otm_who_created_id on g_who_props_otm (who_created_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_created_id foreign key (who_created_id) references g_user (id); + +create index ix_g_who_props_otm_who_modified_id on g_who_props_otm (who_modified_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_modified_id foreign key (who_modified_id) references g_user (id); + +create index ix_with_zero_parent_id on with_zero (parent_id); +alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id); + +alter table hx_link + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table hx_link set (system_versioning = on (history_table=dbo.hx_link_history)); +alter table hi_link + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table hi_link set (system_versioning = on (history_table=dbo.hi_link_history)); +alter table hi_link_doc + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table hi_link_doc set (system_versioning = on (history_table=dbo.hi_link_doc_history)); +alter table link + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table link set (system_versioning = on (history_table=dbo.link_history)); +alter table c_user + add sys_periodFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(), + sys_periodTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT '9999-12-31T23:59:59.9999999', +period for system_time (sys_periodFrom, sys_periodTo); +alter table c_user set (system_versioning = on (history_table=dbo.c_user_history)); diff --git a/src/test/ddl-review/sqlserver-drop-all.sql b/src/test/ddl-review/sqlserver-drop-all.sql new file mode 100644 index 000000000..1669d09c8 --- /dev/null +++ b/src/test/ddl-review/sqlserver-drop-all.sql @@ -0,0 +1,1549 @@ +-- Generated by ebean unknown at 2018-03-08T04:43:42.126Z +IF OBJECT_ID('fk_bar_foo_id', 'F') IS NOT NULL alter table bar drop constraint fk_bar_foo_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bar','U') AND name = 'ix_bar_foo_id') drop index ix_bar_foo_id ON bar; + +IF OBJECT_ID('fk_addr_employee_id', 'F') IS NOT NULL alter table addr drop constraint fk_addr_employee_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('addr','U') AND name = 'ix_addr_employee_id') drop index ix_addr_employee_id ON addr; + +IF OBJECT_ID('fk_o_address_country_code', 'F') IS NOT NULL alter table o_address drop constraint fk_o_address_country_code; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_address','U') AND name = 'ix_o_address_country_code') drop index ix_o_address_country_code ON o_address; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('album','U') AND name = 'uq_album_cover_id') drop index uq_album_cover_id ON album; +IF OBJECT_ID('fk_album_cover_id', 'F') IS NOT NULL alter table album drop constraint fk_album_cover_id; + +IF OBJECT_ID('fk_animal_shelter_id', 'F') IS NOT NULL alter table animal drop constraint fk_animal_shelter_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('animal','U') AND name = 'ix_animal_shelter_id') drop index ix_animal_shelter_id ON animal; + +IF OBJECT_ID('fk_attribute_attribute_holder_id', 'F') IS NOT NULL alter table attribute drop constraint fk_attribute_attribute_holder_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('attribute','U') AND name = 'ix_attribute_attribute_holder_id') drop index ix_attribute_attribute_holder_id ON attribute; + +IF OBJECT_ID('fk_bbookmark_user_id', 'F') IS NOT NULL alter table bbookmark drop constraint fk_bbookmark_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bbookmark','U') AND name = 'ix_bbookmark_user_id') drop index ix_bbookmark_user_id ON bbookmark; + +IF OBJECT_ID('fk_bsite_user_site_id', 'F') IS NOT NULL alter table bsite_user drop constraint fk_bsite_user_site_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user','U') AND name = 'ix_bsite_user_site_id') drop index ix_bsite_user_site_id ON bsite_user; + +IF OBJECT_ID('fk_bsite_user_user_id', 'F') IS NOT NULL alter table bsite_user drop constraint fk_bsite_user_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user','U') AND name = 'ix_bsite_user_user_id') drop index ix_bsite_user_user_id ON bsite_user; + +IF OBJECT_ID('fk_bsite_user_b_site', 'F') IS NOT NULL alter table bsite_user_b drop constraint fk_bsite_user_b_site; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user_b','U') AND name = 'ix_bsite_user_b_site') drop index ix_bsite_user_b_site ON bsite_user_b; + +IF OBJECT_ID('fk_bsite_user_b_usr', 'F') IS NOT NULL alter table bsite_user_b drop constraint fk_bsite_user_b_usr; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user_b','U') AND name = 'ix_bsite_user_b_usr') drop index ix_bsite_user_b_usr ON bsite_user_b; + +IF OBJECT_ID('fk_bsite_user_c_site_uid', 'F') IS NOT NULL alter table bsite_user_c drop constraint fk_bsite_user_c_site_uid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user_c','U') AND name = 'ix_bsite_user_c_site_uid') drop index ix_bsite_user_c_site_uid ON bsite_user_c; + +IF OBJECT_ID('fk_bsite_user_c_user_uid', 'F') IS NOT NULL alter table bsite_user_c drop constraint fk_bsite_user_c_user_uid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bsite_user_c','U') AND name = 'ix_bsite_user_c_user_uid') drop index ix_bsite_user_c_user_uid ON bsite_user_c; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bwith_qident','U') AND name = 'uq_bwith_qident_name') drop index uq_bwith_qident_name ON bwith_qident; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drel_booking','U') AND name = 'uq_drel_booking_booking_uid') drop index uq_drel_booking_booking_uid ON drel_booking; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drel_booking','U') AND name = 'uq_drel_booking_agent_invoice') drop index uq_drel_booking_agent_invoice ON drel_booking; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drel_booking','U') AND name = 'uq_drel_booking_client_invoice') drop index uq_drel_booking_client_invoice ON drel_booking; +IF OBJECT_ID('fk_drel_booking_agent_invoice', 'F') IS NOT NULL alter table drel_booking drop constraint fk_drel_booking_agent_invoice; + +IF OBJECT_ID('fk_drel_booking_client_invoice', 'F') IS NOT NULL alter table drel_booking drop constraint fk_drel_booking_client_invoice; + +IF OBJECT_ID('fk_ckey_detail_parent', 'F') IS NOT NULL alter table ckey_detail drop constraint fk_ckey_detail_parent; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ckey_detail','U') AND name = 'ix_ckey_detail_parent') drop index ix_ckey_detail_parent ON ckey_detail; + +IF OBJECT_ID('fk_ckey_parent_assoc_id', 'F') IS NOT NULL alter table ckey_parent drop constraint fk_ckey_parent_assoc_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ckey_parent','U') AND name = 'ix_ckey_parent_assoc_id') drop index ix_ckey_parent_assoc_id ON ckey_parent; + +IF OBJECT_ID('fk_calculation_result_product_configuration_id', 'F') IS NOT NULL alter table calculation_result drop constraint fk_calculation_result_product_configuration_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('calculation_result','U') AND name = 'ix_calculation_result_product_configuration_id') drop index ix_calculation_result_product_configuration_id ON calculation_result; + +IF OBJECT_ID('fk_calculation_result_group_configuration_id', 'F') IS NOT NULL alter table calculation_result drop constraint fk_calculation_result_group_configuration_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('calculation_result','U') AND name = 'ix_calculation_result_group_configuration_id') drop index ix_calculation_result_group_configuration_id ON calculation_result; + +IF OBJECT_ID('fk_sp_car_car_wheels_sp_car_car', 'F') IS NOT NULL alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_car; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('sp_car_car_wheels','U') AND name = 'ix_sp_car_car_wheels_sp_car_car') drop index ix_sp_car_car_wheels_sp_car_car ON sp_car_car_wheels; + +IF OBJECT_ID('fk_sp_car_car_wheels_sp_car_wheel', 'F') IS NOT NULL alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_wheel; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('sp_car_car_wheels','U') AND name = 'ix_sp_car_car_wheels_sp_car_wheel') drop index ix_sp_car_car_wheels_sp_car_wheel ON sp_car_car_wheels; + +IF OBJECT_ID('fk_car_accessory_fuse_id', 'F') IS NOT NULL alter table car_accessory drop constraint fk_car_accessory_fuse_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('car_accessory','U') AND name = 'ix_car_accessory_fuse_id') drop index ix_car_accessory_fuse_id ON car_accessory; + +IF OBJECT_ID('fk_car_accessory_car_id', 'F') IS NOT NULL alter table car_accessory drop constraint fk_car_accessory_car_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('car_accessory','U') AND name = 'ix_car_accessory_car_id') drop index ix_car_accessory_car_id ON car_accessory; + +IF OBJECT_ID('fk_category_surveyobjectid', 'F') IS NOT NULL alter table category drop constraint fk_category_surveyobjectid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('category','U') AND name = 'ix_category_surveyobjectid') drop index ix_category_surveyobjectid ON category; + +IF OBJECT_ID('fk_child_person_some_bean_id', 'F') IS NOT NULL alter table child_person drop constraint fk_child_person_some_bean_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('child_person','U') AND name = 'ix_child_person_some_bean_id') drop index ix_child_person_some_bean_id ON child_person; + +IF OBJECT_ID('fk_child_person_parent_identifier', 'F') IS NOT NULL alter table child_person drop constraint fk_child_person_parent_identifier; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('child_person','U') AND name = 'ix_child_person_parent_identifier') drop index ix_child_person_parent_identifier ON child_person; + +IF OBJECT_ID('fk_configuration_configurations_id', 'F') IS NOT NULL alter table configuration drop constraint fk_configuration_configurations_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('configuration','U') AND name = 'ix_configuration_configurations_id') drop index ix_configuration_configurations_id ON configuration; + +IF OBJECT_ID('fk_contact_customer_id', 'F') IS NOT NULL alter table contact drop constraint fk_contact_customer_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('contact','U') AND name = 'ix_contact_customer_id') drop index ix_contact_customer_id ON contact; + +IF OBJECT_ID('fk_contact_group_id', 'F') IS NOT NULL alter table contact drop constraint fk_contact_group_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('contact','U') AND name = 'ix_contact_group_id') drop index ix_contact_group_id ON contact; + +IF OBJECT_ID('fk_contact_note_contact_id', 'F') IS NOT NULL alter table contact_note drop constraint fk_contact_note_contact_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('contact_note','U') AND name = 'ix_contact_note_contact_id') drop index ix_contact_note_contact_id ON contact_note; + +IF OBJECT_ID('fk_c_conversation_group_id', 'F') IS NOT NULL alter table c_conversation drop constraint fk_c_conversation_group_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_conversation','U') AND name = 'ix_c_conversation_group_id') drop index ix_c_conversation_group_id ON c_conversation; + +IF OBJECT_ID('fk_o_customer_billing_address_id', 'F') IS NOT NULL alter table o_customer drop constraint fk_o_customer_billing_address_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_customer','U') AND name = 'ix_o_customer_billing_address_id') drop index ix_o_customer_billing_address_id ON o_customer; + +IF OBJECT_ID('fk_o_customer_shipping_address_id', 'F') IS NOT NULL alter table o_customer drop constraint fk_o_customer_shipping_address_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_customer','U') AND name = 'ix_o_customer_shipping_address_id') drop index ix_o_customer_shipping_address_id ON o_customer; + +IF OBJECT_ID('fk_dcredit_drol_dcredit', 'F') IS NOT NULL alter table dcredit_drol drop constraint fk_dcredit_drol_dcredit; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('dcredit_drol','U') AND name = 'ix_dcredit_drol_dcredit') drop index ix_dcredit_drol_dcredit ON dcredit_drol; + +IF OBJECT_ID('fk_dcredit_drol_drol', 'F') IS NOT NULL alter table dcredit_drol drop constraint fk_dcredit_drol_drol; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('dcredit_drol','U') AND name = 'ix_dcredit_drol_drol') drop index ix_dcredit_drol_drol ON dcredit_drol; + +IF OBJECT_ID('fk_drot_drol_drot', 'F') IS NOT NULL alter table drot_drol drop constraint fk_drot_drol_drot; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drot_drol','U') AND name = 'ix_drot_drol_drot') drop index ix_drot_drol_drot ON drot_drol; + +IF OBJECT_ID('fk_drot_drol_drol', 'F') IS NOT NULL alter table drot_drol drop constraint fk_drot_drol_drol; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drot_drol','U') AND name = 'ix_drot_drol_drol') drop index ix_drot_drol_drol ON drot_drol; + +IF OBJECT_ID('fk_dfk_cascade_one_id', 'F') IS NOT NULL alter table dfk_cascade drop constraint fk_dfk_cascade_one_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('dfk_cascade','U') AND name = 'ix_dfk_cascade_one_id') drop index ix_dfk_cascade_one_id ON dfk_cascade; + +IF OBJECT_ID('fk_dfk_set_null_one_id', 'F') IS NOT NULL alter table dfk_set_null drop constraint fk_dfk_set_null_one_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('dfk_set_null','U') AND name = 'ix_dfk_set_null_one_id') drop index ix_dfk_set_null_one_id ON dfk_set_null; + +IF OBJECT_ID('fk_doc_id', 'F') IS NOT NULL alter table doc drop constraint fk_doc_id; + +IF OBJECT_ID('fk_doc_link_doc', 'F') IS NOT NULL alter table doc_link drop constraint fk_doc_link_doc; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('doc_link','U') AND name = 'ix_doc_link_doc') drop index ix_doc_link_doc ON doc_link; + +IF OBJECT_ID('fk_doc_link_link', 'F') IS NOT NULL alter table doc_link drop constraint fk_doc_link_link; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('doc_link','U') AND name = 'ix_doc_link_link') drop index ix_doc_link_link ON doc_link; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document','U') AND name = 'uq_document_title') drop index uq_document_title ON document; +IF OBJECT_ID('fk_document_id', 'F') IS NOT NULL alter table document drop constraint fk_document_id; + +IF OBJECT_ID('fk_document_organisation_id', 'F') IS NOT NULL alter table document drop constraint fk_document_organisation_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document','U') AND name = 'ix_document_organisation_id') drop index ix_document_organisation_id ON document; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document_draft','U') AND name = 'uq_document_draft_title') drop index uq_document_draft_title ON document_draft; +IF OBJECT_ID('fk_document_draft_organisation_id', 'F') IS NOT NULL alter table document_draft drop constraint fk_document_draft_organisation_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document_draft','U') AND name = 'ix_document_draft_organisation_id') drop index ix_document_draft_organisation_id ON document_draft; + +IF OBJECT_ID('fk_document_media_document_id', 'F') IS NOT NULL alter table document_media drop constraint fk_document_media_document_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document_media','U') AND name = 'ix_document_media_document_id') drop index ix_document_media_document_id ON document_media; + +IF OBJECT_ID('fk_document_media_draft_document_id', 'F') IS NOT NULL alter table document_media_draft drop constraint fk_document_media_draft_document_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('document_media_draft','U') AND name = 'ix_document_media_draft_document_id') drop index ix_document_media_draft_document_id ON document_media_draft; + +IF OBJECT_ID('fk_ebasic_json_map_detail_owner_id', 'F') IS NOT NULL alter table ebasic_json_map_detail drop constraint fk_ebasic_json_map_detail_owner_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ebasic_json_map_detail','U') AND name = 'ix_ebasic_json_map_detail_owner_id') drop index ix_ebasic_json_map_detail_owner_id ON ebasic_json_map_detail; + +IF OBJECT_ID('fk_ebasic_no_sdchild_owner_id', 'F') IS NOT NULL alter table ebasic_no_sdchild drop constraint fk_ebasic_no_sdchild_owner_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ebasic_no_sdchild','U') AND name = 'ix_ebasic_no_sdchild_owner_id') drop index ix_ebasic_no_sdchild_owner_id ON ebasic_no_sdchild; + +IF OBJECT_ID('fk_ebasic_sdchild_owner_id', 'F') IS NOT NULL alter table ebasic_sdchild drop constraint fk_ebasic_sdchild_owner_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ebasic_sdchild','U') AND name = 'ix_ebasic_sdchild_owner_id') drop index ix_ebasic_sdchild_owner_id ON ebasic_sdchild; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('e_basicverucon','U') AND name = 'uq_e_basicverucon_name') drop index uq_e_basicverucon_name ON e_basicverucon; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('e_basicverucon','U') AND name = 'uq_e_basicverucon_other_other_one') drop index uq_e_basicverucon_other_other_one ON e_basicverucon; +IF OBJECT_ID('fk_eemb_inner_outer_id', 'F') IS NOT NULL alter table eemb_inner drop constraint fk_eemb_inner_outer_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('eemb_inner','U') AND name = 'ix_eemb_inner_outer_id') drop index ix_eemb_inner_outer_id ON eemb_inner; + +IF OBJECT_ID('fk_einvoice_person_id', 'F') IS NOT NULL alter table einvoice drop constraint fk_einvoice_person_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('einvoice','U') AND name = 'ix_einvoice_person_id') drop index ix_einvoice_person_id ON einvoice; + +IF OBJECT_ID('fk_enull_collection_detail_enull_collection_id', 'F') IS NOT NULL alter table enull_collection_detail drop constraint fk_enull_collection_detail_enull_collection_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('enull_collection_detail','U') AND name = 'ix_enull_collection_detail_enull_collection_id') drop index ix_enull_collection_detail_enull_collection_id ON enull_collection_detail; + +IF OBJECT_ID('fk_eopt_one_a_b_id', 'F') IS NOT NULL alter table eopt_one_a drop constraint fk_eopt_one_a_b_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('eopt_one_a','U') AND name = 'ix_eopt_one_a_b_id') drop index ix_eopt_one_a_b_id ON eopt_one_a; + +IF OBJECT_ID('fk_eopt_one_b_c_id', 'F') IS NOT NULL alter table eopt_one_b drop constraint fk_eopt_one_b_c_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('eopt_one_b','U') AND name = 'ix_eopt_one_b_c_id') drop index ix_eopt_one_b_c_id ON eopt_one_b; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('e_person_online','U') AND name = 'uq_e_person_online_email') drop index uq_e_person_online_email ON e_person_online; +IF OBJECT_ID('fk_esoft_del_book_lend_by_id', 'F') IS NOT NULL alter table esoft_del_book drop constraint fk_esoft_del_book_lend_by_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_book','U') AND name = 'ix_esoft_del_book_lend_by_id') drop index ix_esoft_del_book_lend_by_id ON esoft_del_book; + +IF OBJECT_ID('fk_esoft_del_book_esoft_del_user_esoft_del_book', 'F') IS NOT NULL alter table esoft_del_book_esoft_del_user drop constraint fk_esoft_del_book_esoft_del_user_esoft_del_book; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_book_esoft_del_user','U') AND name = 'ix_esoft_del_book_esoft_del_user_esoft_del_book') drop index ix_esoft_del_book_esoft_del_user_esoft_del_book ON esoft_del_book_esoft_del_user; + +IF OBJECT_ID('fk_esoft_del_book_esoft_del_user_esoft_del_user', 'F') IS NOT NULL alter table esoft_del_book_esoft_del_user drop constraint fk_esoft_del_book_esoft_del_user_esoft_del_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_book_esoft_del_user','U') AND name = 'ix_esoft_del_book_esoft_del_user_esoft_del_user') drop index ix_esoft_del_book_esoft_del_user_esoft_del_user ON esoft_del_book_esoft_del_user; + +IF OBJECT_ID('fk_esoft_del_down_esoft_del_mid_id', 'F') IS NOT NULL alter table esoft_del_down drop constraint fk_esoft_del_down_esoft_del_mid_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_down','U') AND name = 'ix_esoft_del_down_esoft_del_mid_id') drop index ix_esoft_del_down_esoft_del_mid_id ON esoft_del_down; + +IF OBJECT_ID('fk_esoft_del_mid_top_id', 'F') IS NOT NULL alter table esoft_del_mid drop constraint fk_esoft_del_mid_top_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_mid','U') AND name = 'ix_esoft_del_mid_top_id') drop index ix_esoft_del_mid_top_id ON esoft_del_mid; + +IF OBJECT_ID('fk_esoft_del_mid_up_id', 'F') IS NOT NULL alter table esoft_del_mid drop constraint fk_esoft_del_mid_up_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_mid','U') AND name = 'ix_esoft_del_mid_up_id') drop index ix_esoft_del_mid_up_id ON esoft_del_mid; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_one_a','U') AND name = 'uq_esoft_del_one_a_oneb_id') drop index uq_esoft_del_one_a_oneb_id ON esoft_del_one_a; +IF OBJECT_ID('fk_esoft_del_one_a_oneb_id', 'F') IS NOT NULL alter table esoft_del_one_a drop constraint fk_esoft_del_one_a_oneb_id; + +IF OBJECT_ID('fk_esoft_del_role_esoft_del_user_esoft_del_role', 'F') IS NOT NULL alter table esoft_del_role_esoft_del_user drop constraint fk_esoft_del_role_esoft_del_user_esoft_del_role; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_role_esoft_del_user','U') AND name = 'ix_esoft_del_role_esoft_del_user_esoft_del_role') drop index ix_esoft_del_role_esoft_del_user_esoft_del_role ON esoft_del_role_esoft_del_user; + +IF OBJECT_ID('fk_esoft_del_role_esoft_del_user_esoft_del_user', 'F') IS NOT NULL alter table esoft_del_role_esoft_del_user drop constraint fk_esoft_del_role_esoft_del_user_esoft_del_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_role_esoft_del_user','U') AND name = 'ix_esoft_del_role_esoft_del_user_esoft_del_user') drop index ix_esoft_del_role_esoft_del_user_esoft_del_user ON esoft_del_role_esoft_del_user; + +IF OBJECT_ID('fk_esoft_del_user_esoft_del_role_esoft_del_user', 'F') IS NOT NULL alter table esoft_del_user_esoft_del_role drop constraint fk_esoft_del_user_esoft_del_role_esoft_del_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_user_esoft_del_role','U') AND name = 'ix_esoft_del_user_esoft_del_role_esoft_del_user') drop index ix_esoft_del_user_esoft_del_role_esoft_del_user ON esoft_del_user_esoft_del_role; + +IF OBJECT_ID('fk_esoft_del_user_esoft_del_role_esoft_del_role', 'F') IS NOT NULL alter table esoft_del_user_esoft_del_role drop constraint fk_esoft_del_user_esoft_del_role_esoft_del_role; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('esoft_del_user_esoft_del_role','U') AND name = 'ix_esoft_del_user_esoft_del_role_esoft_del_role') drop index ix_esoft_del_user_esoft_del_role_esoft_del_role ON esoft_del_user_esoft_del_role; + +IF OBJECT_ID('fk_rawinherit_uncle_parent_id', 'F') IS NOT NULL alter table rawinherit_uncle drop constraint fk_rawinherit_uncle_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('rawinherit_uncle','U') AND name = 'ix_rawinherit_uncle_parent_id') drop index ix_rawinherit_uncle_parent_id ON rawinherit_uncle; + +IF OBJECT_ID('fk_evanilla_collection_detail_evanilla_collection_id', 'F') IS NOT NULL alter table evanilla_collection_detail drop constraint fk_evanilla_collection_detail_evanilla_collection_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('evanilla_collection_detail','U') AND name = 'ix_evanilla_collection_detail_evanilla_collection_id') drop index ix_evanilla_collection_detail_evanilla_collection_id ON evanilla_collection_detail; + +IF OBJECT_ID('fk_td_child_parent_id', 'F') IS NOT NULL alter table td_child drop constraint fk_td_child_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('td_child','U') AND name = 'ix_td_child_parent_id') drop index ix_td_child_parent_id ON td_child; + +IF OBJECT_ID('fk_empl_default_address_id', 'F') IS NOT NULL alter table empl drop constraint fk_empl_default_address_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('empl','U') AND name = 'ix_empl_default_address_id') drop index ix_empl_default_address_id ON empl; + +IF OBJECT_ID('fk_grand_parent_person_some_bean_id', 'F') IS NOT NULL alter table grand_parent_person drop constraint fk_grand_parent_person_some_bean_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('grand_parent_person','U') AND name = 'ix_grand_parent_person_some_bean_id') drop index ix_grand_parent_person_some_bean_id ON grand_parent_person; + +IF OBJECT_ID('fk_survey_group_categoryobjectid', 'F') IS NOT NULL alter table survey_group drop constraint fk_survey_group_categoryobjectid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('survey_group','U') AND name = 'ix_survey_group_categoryobjectid') drop index ix_survey_group_categoryobjectid ON survey_group; + +IF OBJECT_ID('fk_hx_link_doc_hx_link', 'F') IS NOT NULL alter table hx_link_doc drop constraint fk_hx_link_doc_hx_link; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('hx_link_doc','U') AND name = 'ix_hx_link_doc_hx_link') drop index ix_hx_link_doc_hx_link ON hx_link_doc; + +IF OBJECT_ID('fk_hx_link_doc_he_doc', 'F') IS NOT NULL alter table hx_link_doc drop constraint fk_hx_link_doc_he_doc; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('hx_link_doc','U') AND name = 'ix_hx_link_doc_he_doc') drop index ix_hx_link_doc_he_doc ON hx_link_doc; + +IF OBJECT_ID('fk_hi_link_doc_hi_link', 'F') IS NOT NULL alter table hi_link_doc drop constraint fk_hi_link_doc_hi_link; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('hi_link_doc','U') AND name = 'ix_hi_link_doc_hi_link') drop index ix_hi_link_doc_hi_link ON hi_link_doc; + +IF OBJECT_ID('fk_hi_link_doc_hi_doc', 'F') IS NOT NULL alter table hi_link_doc drop constraint fk_hi_link_doc_hi_doc; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('hi_link_doc','U') AND name = 'ix_hi_link_doc_hi_doc') drop index ix_hi_link_doc_hi_doc ON hi_link_doc; + +IF OBJECT_ID('fk_imrelated_owner_id', 'F') IS NOT NULL alter table imrelated drop constraint fk_imrelated_owner_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('imrelated','U') AND name = 'ix_imrelated_owner_id') drop index ix_imrelated_owner_id ON imrelated; + +IF OBJECT_ID('fk_info_contact_company_id', 'F') IS NOT NULL alter table info_contact drop constraint fk_info_contact_company_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('info_contact','U') AND name = 'ix_info_contact_company_id') drop index ix_info_contact_company_id ON info_contact; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('info_customer','U') AND name = 'uq_info_customer_company_id') drop index uq_info_customer_company_id ON info_customer; +IF OBJECT_ID('fk_info_customer_company_id', 'F') IS NOT NULL alter table info_customer drop constraint fk_info_customer_company_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('inner_report','U') AND name = 'uq_inner_report_forecast_id') drop index uq_inner_report_forecast_id ON inner_report; +IF OBJECT_ID('fk_inner_report_forecast_id', 'F') IS NOT NULL alter table inner_report drop constraint fk_inner_report_forecast_id; + +IF OBJECT_ID('fk_drel_invoice_booking', 'F') IS NOT NULL alter table drel_invoice drop constraint fk_drel_invoice_booking; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('drel_invoice','U') AND name = 'ix_drel_invoice_booking') drop index ix_drel_invoice_booking ON drel_invoice; + +IF OBJECT_ID('fk_item_etype', 'F') IS NOT NULL alter table item drop constraint fk_item_etype; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('item','U') AND name = 'ix_item_etype') drop index ix_item_etype ON item; + +IF OBJECT_ID('fk_item_eregion', 'F') IS NOT NULL alter table item drop constraint fk_item_eregion; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('item','U') AND name = 'ix_item_eregion') drop index ix_item_eregion ON item; + +IF OBJECT_ID('fk_trainer_monkey_trainer', 'F') IS NOT NULL alter table trainer_monkey drop constraint fk_trainer_monkey_trainer; + +IF OBJECT_ID('fk_trainer_monkey_monkey', 'F') IS NOT NULL alter table trainer_monkey drop constraint fk_trainer_monkey_monkey; + +IF OBJECT_ID('fk_troop_monkey_troop', 'F') IS NOT NULL alter table troop_monkey drop constraint fk_troop_monkey_troop; + +IF OBJECT_ID('fk_troop_monkey_monkey', 'F') IS NOT NULL alter table troop_monkey drop constraint fk_troop_monkey_monkey; + +IF OBJECT_ID('fk_l2_cldf_reset_bean_child_parent_id', 'F') IS NOT NULL alter table l2_cldf_reset_bean_child drop constraint fk_l2_cldf_reset_bean_child_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('l2_cldf_reset_bean_child','U') AND name = 'ix_l2_cldf_reset_bean_child_parent_id') drop index ix_l2_cldf_reset_bean_child_parent_id ON l2_cldf_reset_bean_child; + +IF OBJECT_ID('fk_level1_level4_level1', 'F') IS NOT NULL alter table level1_level4 drop constraint fk_level1_level4_level1; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level1_level4','U') AND name = 'ix_level1_level4_level1') drop index ix_level1_level4_level1 ON level1_level4; + +IF OBJECT_ID('fk_level1_level4_level4', 'F') IS NOT NULL alter table level1_level4 drop constraint fk_level1_level4_level4; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level1_level4','U') AND name = 'ix_level1_level4_level4') drop index ix_level1_level4_level4 ON level1_level4; + +IF OBJECT_ID('fk_level1_level2_level1', 'F') IS NOT NULL alter table level1_level2 drop constraint fk_level1_level2_level1; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level1_level2','U') AND name = 'ix_level1_level2_level1') drop index ix_level1_level2_level1 ON level1_level2; + +IF OBJECT_ID('fk_level1_level2_level2', 'F') IS NOT NULL alter table level1_level2 drop constraint fk_level1_level2_level2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level1_level2','U') AND name = 'ix_level1_level2_level2') drop index ix_level1_level2_level2 ON level1_level2; + +IF OBJECT_ID('fk_level2_level3_level2', 'F') IS NOT NULL alter table level2_level3 drop constraint fk_level2_level3_level2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level2_level3','U') AND name = 'ix_level2_level3_level2') drop index ix_level2_level3_level2 ON level2_level3; + +IF OBJECT_ID('fk_level2_level3_level3', 'F') IS NOT NULL alter table level2_level3 drop constraint fk_level2_level3_level3; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('level2_level3','U') AND name = 'ix_level2_level3_level3') drop index ix_level2_level3_level3 ON level2_level3; + +IF OBJECT_ID('fk_link_id', 'F') IS NOT NULL alter table link drop constraint fk_link_id; + +IF OBJECT_ID('fk_la_attr_value_attribute_la_attr_value', 'F') IS NOT NULL alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_la_attr_value; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('la_attr_value_attribute','U') AND name = 'ix_la_attr_value_attribute_la_attr_value') drop index ix_la_attr_value_attribute_la_attr_value ON la_attr_value_attribute; + +IF OBJECT_ID('fk_la_attr_value_attribute_attribute', 'F') IS NOT NULL alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_attribute; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('la_attr_value_attribute','U') AND name = 'ix_la_attr_value_attribute_attribute') drop index ix_la_attr_value_attribute_attribute ON la_attr_value_attribute; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter','U') AND name = 'uq_mprinter_last_swap_cyan_id') drop index uq_mprinter_last_swap_cyan_id ON mprinter; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter','U') AND name = 'uq_mprinter_last_swap_magenta_id') drop index uq_mprinter_last_swap_magenta_id ON mprinter; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter','U') AND name = 'uq_mprinter_last_swap_yellow_id') drop index uq_mprinter_last_swap_yellow_id ON mprinter; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter','U') AND name = 'uq_mprinter_last_swap_black_id') drop index uq_mprinter_last_swap_black_id ON mprinter; +IF OBJECT_ID('fk_mprinter_current_state_id', 'F') IS NOT NULL alter table mprinter drop constraint fk_mprinter_current_state_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter','U') AND name = 'ix_mprinter_current_state_id') drop index ix_mprinter_current_state_id ON mprinter; + +IF OBJECT_ID('fk_mprinter_last_swap_cyan_id', 'F') IS NOT NULL alter table mprinter drop constraint fk_mprinter_last_swap_cyan_id; + +IF OBJECT_ID('fk_mprinter_last_swap_magenta_id', 'F') IS NOT NULL alter table mprinter drop constraint fk_mprinter_last_swap_magenta_id; + +IF OBJECT_ID('fk_mprinter_last_swap_yellow_id', 'F') IS NOT NULL alter table mprinter drop constraint fk_mprinter_last_swap_yellow_id; + +IF OBJECT_ID('fk_mprinter_last_swap_black_id', 'F') IS NOT NULL alter table mprinter drop constraint fk_mprinter_last_swap_black_id; + +IF OBJECT_ID('fk_mprinter_state_printer_id', 'F') IS NOT NULL alter table mprinter_state drop constraint fk_mprinter_state_printer_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprinter_state','U') AND name = 'ix_mprinter_state_printer_id') drop index ix_mprinter_state_printer_id ON mprinter_state; + +IF OBJECT_ID('fk_mprofile_picture_id', 'F') IS NOT NULL alter table mprofile drop constraint fk_mprofile_picture_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mprofile','U') AND name = 'ix_mprofile_picture_id') drop index ix_mprofile_picture_id ON mprofile; + +IF OBJECT_ID('fk_mrole_muser_mrole', 'F') IS NOT NULL alter table mrole_muser drop constraint fk_mrole_muser_mrole; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mrole_muser','U') AND name = 'ix_mrole_muser_mrole') drop index ix_mrole_muser_mrole ON mrole_muser; + +IF OBJECT_ID('fk_mrole_muser_muser', 'F') IS NOT NULL alter table mrole_muser drop constraint fk_mrole_muser_muser; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mrole_muser','U') AND name = 'ix_mrole_muser_muser') drop index ix_mrole_muser_muser ON mrole_muser; + +IF OBJECT_ID('fk_muser_user_type_id', 'F') IS NOT NULL alter table muser drop constraint fk_muser_user_type_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('muser','U') AND name = 'ix_muser_user_type_id') drop index ix_muser_user_type_id ON muser; + +IF OBJECT_ID('fk_mail_user_inbox_mail_user', 'F') IS NOT NULL alter table mail_user_inbox drop constraint fk_mail_user_inbox_mail_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mail_user_inbox','U') AND name = 'ix_mail_user_inbox_mail_user') drop index ix_mail_user_inbox_mail_user ON mail_user_inbox; + +IF OBJECT_ID('fk_mail_user_inbox_mail_box', 'F') IS NOT NULL alter table mail_user_inbox drop constraint fk_mail_user_inbox_mail_box; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mail_user_inbox','U') AND name = 'ix_mail_user_inbox_mail_box') drop index ix_mail_user_inbox_mail_box ON mail_user_inbox; + +IF OBJECT_ID('fk_mail_user_outbox_mail_user', 'F') IS NOT NULL alter table mail_user_outbox drop constraint fk_mail_user_outbox_mail_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mail_user_outbox','U') AND name = 'ix_mail_user_outbox_mail_user') drop index ix_mail_user_outbox_mail_user ON mail_user_outbox; + +IF OBJECT_ID('fk_mail_user_outbox_mail_box', 'F') IS NOT NULL alter table mail_user_outbox drop constraint fk_mail_user_outbox_mail_box; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mail_user_outbox','U') AND name = 'ix_mail_user_outbox_mail_box') drop index ix_mail_user_outbox_mail_box ON mail_user_outbox; + +IF OBJECT_ID('fk_c_message_conversation_id', 'F') IS NOT NULL alter table c_message drop constraint fk_c_message_conversation_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_message','U') AND name = 'ix_c_message_conversation_id') drop index ix_c_message_conversation_id ON c_message; + +IF OBJECT_ID('fk_c_message_user_id', 'F') IS NOT NULL alter table c_message drop constraint fk_c_message_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_message','U') AND name = 'ix_c_message_user_id') drop index ix_c_message_user_id ON c_message; + +IF OBJECT_ID('fk_mnoc_user_mnoc_role_mnoc_user', 'F') IS NOT NULL alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_user; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mnoc_user_mnoc_role','U') AND name = 'ix_mnoc_user_mnoc_role_mnoc_user') drop index ix_mnoc_user_mnoc_role_mnoc_user ON mnoc_user_mnoc_role; + +IF OBJECT_ID('fk_mnoc_user_mnoc_role_mnoc_role', 'F') IS NOT NULL alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_role; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mnoc_user_mnoc_role','U') AND name = 'ix_mnoc_user_mnoc_role_mnoc_role') drop index ix_mnoc_user_mnoc_role_mnoc_role ON mnoc_user_mnoc_role; + +IF OBJECT_ID('fk_mny_b_a_id', 'F') IS NOT NULL alter table mny_b drop constraint fk_mny_b_a_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mny_b','U') AND name = 'ix_mny_b_a_id') drop index ix_mny_b_a_id ON mny_b; + +IF OBJECT_ID('fk_mny_b_mny_c_mny_b', 'F') IS NOT NULL alter table mny_b_mny_c drop constraint fk_mny_b_mny_c_mny_b; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mny_b_mny_c','U') AND name = 'ix_mny_b_mny_c_mny_b') drop index ix_mny_b_mny_c_mny_b ON mny_b_mny_c; + +IF OBJECT_ID('fk_mny_b_mny_c_mny_c', 'F') IS NOT NULL alter table mny_b_mny_c drop constraint fk_mny_b_mny_c_mny_c; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mny_b_mny_c','U') AND name = 'ix_mny_b_mny_c_mny_c') drop index ix_mny_b_mny_c_mny_c ON mny_b_mny_c; + +IF OBJECT_ID('fk_subtopics_mny_topic_1', 'F') IS NOT NULL alter table subtopics drop constraint fk_subtopics_mny_topic_1; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('subtopics','U') AND name = 'ix_subtopics_mny_topic_1') drop index ix_subtopics_mny_topic_1 ON subtopics; + +IF OBJECT_ID('fk_subtopics_mny_topic_2', 'F') IS NOT NULL alter table subtopics drop constraint fk_subtopics_mny_topic_2; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('subtopics','U') AND name = 'ix_subtopics_mny_topic_2') drop index ix_subtopics_mny_topic_2 ON subtopics; + +IF OBJECT_ID('fk_mp_role_mp_user_id', 'F') IS NOT NULL alter table mp_role drop constraint fk_mp_role_mp_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mp_role','U') AND name = 'ix_mp_role_mp_user_id') drop index ix_mp_role_mp_user_id ON mp_role; + +IF OBJECT_ID('fk_ms_many_a_many_b_ms_many_a', 'F') IS NOT NULL alter table ms_many_a_many_b drop constraint fk_ms_many_a_many_b_ms_many_a; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ms_many_a_many_b','U') AND name = 'ix_ms_many_a_many_b_ms_many_a') drop index ix_ms_many_a_many_b_ms_many_a ON ms_many_a_many_b; + +IF OBJECT_ID('fk_ms_many_a_many_b_ms_many_b', 'F') IS NOT NULL alter table ms_many_a_many_b drop constraint fk_ms_many_a_many_b_ms_many_b; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ms_many_a_many_b','U') AND name = 'ix_ms_many_a_many_b_ms_many_b') drop index ix_ms_many_a_many_b_ms_many_b ON ms_many_a_many_b; + +IF OBJECT_ID('fk_ms_many_b_many_a_ms_many_b', 'F') IS NOT NULL alter table ms_many_b_many_a drop constraint fk_ms_many_b_many_a_ms_many_b; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ms_many_b_many_a','U') AND name = 'ix_ms_many_b_many_a_ms_many_b') drop index ix_ms_many_b_many_a_ms_many_b ON ms_many_b_many_a; + +IF OBJECT_ID('fk_ms_many_b_many_a_ms_many_a', 'F') IS NOT NULL alter table ms_many_b_many_a drop constraint fk_ms_many_b_many_a_ms_many_a; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ms_many_b_many_a','U') AND name = 'ix_ms_many_b_many_a_ms_many_a') drop index ix_ms_many_b_many_a_ms_many_a ON ms_many_b_many_a; + +IF OBJECT_ID('fk_my_lob_size_join_many_parent_id', 'F') IS NOT NULL alter table my_lob_size_join_many drop constraint fk_my_lob_size_join_many_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('my_lob_size_join_many','U') AND name = 'ix_my_lob_size_join_many_parent_id') drop index ix_my_lob_size_join_many_parent_id ON my_lob_size_join_many; + +IF OBJECT_ID('fk_o_cached_bean_country_o_cached_bean', 'F') IS NOT NULL alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_cached_bean; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_cached_bean_country','U') AND name = 'ix_o_cached_bean_country_o_cached_bean') drop index ix_o_cached_bean_country_o_cached_bean ON o_cached_bean_country; + +IF OBJECT_ID('fk_o_cached_bean_country_o_country', 'F') IS NOT NULL alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_country; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_cached_bean_country','U') AND name = 'ix_o_cached_bean_country_o_country') drop index ix_o_cached_bean_country_o_country ON o_cached_bean_country; + +IF OBJECT_ID('fk_o_cached_bean_child_cached_bean_id', 'F') IS NOT NULL alter table o_cached_bean_child drop constraint fk_o_cached_bean_child_cached_bean_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_cached_bean_child','U') AND name = 'ix_o_cached_bean_child_cached_bean_id') drop index ix_o_cached_bean_child_cached_bean_id ON o_cached_bean_child; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ocompany','U') AND name = 'uq_ocompany_corp_id') drop index uq_ocompany_corp_id ON ocompany; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('oengine','U') AND name = 'uq_oengine_car_id') drop index uq_oengine_car_id ON oengine; +IF OBJECT_ID('fk_oengine_car_id', 'F') IS NOT NULL alter table oengine drop constraint fk_oengine_car_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ogear_box','U') AND name = 'uq_ogear_box_car_id') drop index uq_ogear_box_car_id ON ogear_box; +IF OBJECT_ID('fk_ogear_box_car_id', 'F') IS NOT NULL alter table ogear_box drop constraint fk_ogear_box_car_id; + +IF OBJECT_ID('fk_oroad_show_msg_company_id', 'F') IS NOT NULL alter table oroad_show_msg drop constraint fk_oroad_show_msg_company_id; + +IF OBJECT_ID('fk_om_ordered_detail_master_id', 'F') IS NOT NULL alter table om_ordered_detail drop constraint fk_om_ordered_detail_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('om_ordered_detail','U') AND name = 'ix_om_ordered_detail_master_id') drop index ix_om_ordered_detail_master_id ON om_ordered_detail; + +IF OBJECT_ID('fk_o_order_kcustomer_id', 'F') IS NOT NULL alter table o_order drop constraint fk_o_order_kcustomer_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_order','U') AND name = 'ix_o_order_kcustomer_id') drop index ix_o_order_kcustomer_id ON o_order; + +IF OBJECT_ID('fk_o_order_detail_order_id', 'F') IS NOT NULL alter table o_order_detail drop constraint fk_o_order_detail_order_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_order_detail','U') AND name = 'ix_o_order_detail_order_id') drop index ix_o_order_detail_order_id ON o_order_detail; + +IF OBJECT_ID('fk_o_order_detail_product_id', 'F') IS NOT NULL alter table o_order_detail drop constraint fk_o_order_detail_product_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('o_order_detail','U') AND name = 'ix_o_order_detail_product_id') drop index ix_o_order_detail_product_id ON o_order_detail; + +IF OBJECT_ID('fk_s_order_items_order_uuid', 'F') IS NOT NULL alter table s_order_items drop constraint fk_s_order_items_order_uuid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('s_order_items','U') AND name = 'ix_s_order_items_order_uuid') drop index ix_s_order_items_order_uuid ON s_order_items; + +IF OBJECT_ID('fk_or_order_ship_order_id', 'F') IS NOT NULL alter table or_order_ship drop constraint fk_or_order_ship_order_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('or_order_ship','U') AND name = 'ix_or_order_ship_order_id') drop index ix_or_order_ship_order_id ON or_order_ship; + +IF OBJECT_ID('fk_oto_bchild_master_id', 'F') IS NOT NULL alter table oto_bchild drop constraint fk_oto_bchild_master_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('oto_child','U') AND name = 'uq_oto_child_master_id') drop index uq_oto_child_master_id ON oto_child; +IF OBJECT_ID('fk_oto_child_master_id', 'F') IS NOT NULL alter table oto_child drop constraint fk_oto_child_master_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('oto_cust_address','U') AND name = 'uq_oto_cust_address_customer_cid') drop index uq_oto_cust_address_customer_cid ON oto_cust_address; +IF OBJECT_ID('fk_oto_cust_address_customer_cid', 'F') IS NOT NULL alter table oto_cust_address drop constraint fk_oto_cust_address_customer_cid; + +IF OBJECT_ID('fk_oto_prime_extra_eid', 'F') IS NOT NULL alter table oto_prime_extra drop constraint fk_oto_prime_extra_eid; + +IF OBJECT_ID('fk_oto_th_many_oto_th_top_id', 'F') IS NOT NULL alter table oto_th_many drop constraint fk_oto_th_many_oto_th_top_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('oto_th_many','U') AND name = 'ix_oto_th_many_oto_th_top_id') drop index ix_oto_th_many_oto_th_top_id ON oto_th_many; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('oto_th_one','U') AND name = 'uq_oto_th_one_many_id') drop index uq_oto_th_one_many_id ON oto_th_one; +IF OBJECT_ID('fk_oto_th_one_many_id', 'F') IS NOT NULL alter table oto_th_one drop constraint fk_oto_th_one_many_id; + +IF OBJECT_ID('fk_oto_ubprime_extra_eid', 'F') IS NOT NULL alter table oto_ubprime_extra drop constraint fk_oto_ubprime_extra_eid; + +IF OBJECT_ID('fk_oto_uprime_extra_eid', 'F') IS NOT NULL alter table oto_uprime_extra drop constraint fk_oto_uprime_extra_eid; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('pfile','U') AND name = 'uq_pfile_file_content_id') drop index uq_pfile_file_content_id ON pfile; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('pfile','U') AND name = 'uq_pfile_file_content2_id') drop index uq_pfile_file_content2_id ON pfile; +IF OBJECT_ID('fk_pfile_file_content_id', 'F') IS NOT NULL alter table pfile drop constraint fk_pfile_file_content_id; + +IF OBJECT_ID('fk_pfile_file_content2_id', 'F') IS NOT NULL alter table pfile drop constraint fk_pfile_file_content2_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('paggview','U') AND name = 'uq_paggview_pview_id') drop index uq_paggview_pview_id ON paggview; +IF OBJECT_ID('fk_paggview_pview_id', 'F') IS NOT NULL alter table paggview drop constraint fk_paggview_pview_id; + +IF OBJECT_ID('fk_pallet_location_zone_sid', 'F') IS NOT NULL alter table pallet_location drop constraint fk_pallet_location_zone_sid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('pallet_location','U') AND name = 'ix_pallet_location_zone_sid') drop index ix_pallet_location_zone_sid ON pallet_location; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('parcel_location','U') AND name = 'uq_parcel_location_parcelid') drop index uq_parcel_location_parcelid ON parcel_location; +IF OBJECT_ID('fk_parcel_location_parcelid', 'F') IS NOT NULL alter table parcel_location drop constraint fk_parcel_location_parcelid; + +IF OBJECT_ID('fk_rawinherit_parent_rawinherit_data_rawinherit_parent', 'F') IS NOT NULL alter table rawinherit_parent_rawinherit_data drop constraint fk_rawinherit_parent_rawinherit_data_rawinherit_parent; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('rawinherit_parent_rawinherit_data','U') AND name = 'ix_rawinherit_parent_rawinherit_data_rawinherit_parent') drop index ix_rawinherit_parent_rawinherit_data_rawinherit_parent ON rawinherit_parent_rawinherit_data; + +IF OBJECT_ID('fk_rawinherit_parent_rawinherit_data_rawinherit_data', 'F') IS NOT NULL alter table rawinherit_parent_rawinherit_data drop constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('rawinherit_parent_rawinherit_data','U') AND name = 'ix_rawinherit_parent_rawinherit_data_rawinherit_data') drop index ix_rawinherit_parent_rawinherit_data_rawinherit_data ON rawinherit_parent_rawinherit_data; + +IF OBJECT_ID('fk_parent_person_some_bean_id', 'F') IS NOT NULL alter table parent_person drop constraint fk_parent_person_some_bean_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('parent_person','U') AND name = 'ix_parent_person_some_bean_id') drop index ix_parent_person_some_bean_id ON parent_person; + +IF OBJECT_ID('fk_parent_person_parent_identifier', 'F') IS NOT NULL alter table parent_person drop constraint fk_parent_person_parent_identifier; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('parent_person','U') AND name = 'ix_parent_person_parent_identifier') drop index ix_parent_person_parent_identifier ON parent_person; + +IF OBJECT_ID('fk_c_participation_conversation_id', 'F') IS NOT NULL alter table c_participation drop constraint fk_c_participation_conversation_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_participation','U') AND name = 'ix_c_participation_conversation_id') drop index ix_c_participation_conversation_id ON c_participation; + +IF OBJECT_ID('fk_c_participation_user_id', 'F') IS NOT NULL alter table c_participation drop constraint fk_c_participation_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_participation','U') AND name = 'ix_c_participation_user_id') drop index ix_c_participation_user_id ON c_participation; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('persistent_file_content','U') AND name = 'uq_persistent_file_content_persistent_file_id') drop index uq_persistent_file_content_persistent_file_id ON persistent_file_content; +IF OBJECT_ID('fk_persistent_file_content_persistent_file_id', 'F') IS NOT NULL alter table persistent_file_content drop constraint fk_persistent_file_content_persistent_file_id; + +IF OBJECT_ID('fk_person_default_address_oid', 'F') IS NOT NULL alter table person drop constraint fk_person_default_address_oid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('person','U') AND name = 'ix_person_default_address_oid') drop index ix_person_default_address_oid ON person; + +IF OBJECT_ID('fk_phones_person_id', 'F') IS NOT NULL alter table phones drop constraint fk_phones_person_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('phones','U') AND name = 'ix_phones_person_id') drop index ix_phones_person_id ON phones; + +IF OBJECT_ID('fk_pp_to_ww_pp', 'F') IS NOT NULL alter table pp_to_ww drop constraint fk_pp_to_ww_pp; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('pp_to_ww','U') AND name = 'ix_pp_to_ww_pp') drop index ix_pp_to_ww_pp ON pp_to_ww; + +IF OBJECT_ID('fk_pp_to_ww_wview', 'F') IS NOT NULL alter table pp_to_ww drop constraint fk_pp_to_ww_wview; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('pp_to_ww','U') AND name = 'ix_pp_to_ww_wview') drop index ix_pp_to_ww_wview ON pp_to_ww; + +IF OBJECT_ID('fk_question_groupobjectid', 'F') IS NOT NULL alter table question drop constraint fk_question_groupobjectid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('question','U') AND name = 'ix_question_groupobjectid') drop index ix_question_groupobjectid ON question; + +IF OBJECT_ID('fk_r_orders_customer', 'F') IS NOT NULL alter table r_orders drop constraint fk_r_orders_customer; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('r_orders','U') AND name = 'ix_r_orders_customer') drop index ix_r_orders_customer ON r_orders; + +IF OBJECT_ID('fk_resourcefile_parentresourcefileid', 'F') IS NOT NULL alter table resourcefile drop constraint fk_resourcefile_parentresourcefileid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('resourcefile','U') AND name = 'ix_resourcefile_parentresourcefileid') drop index ix_resourcefile_parentresourcefileid ON resourcefile; + +IF OBJECT_ID('fk_mt_role_tenant_id', 'F') IS NOT NULL alter table mt_role drop constraint fk_mt_role_tenant_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mt_role','U') AND name = 'ix_mt_role_tenant_id') drop index ix_mt_role_tenant_id ON mt_role; + +IF OBJECT_ID('fk_mt_role_permission_mt_role', 'F') IS NOT NULL alter table mt_role_permission drop constraint fk_mt_role_permission_mt_role; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mt_role_permission','U') AND name = 'ix_mt_role_permission_mt_role') drop index ix_mt_role_permission_mt_role ON mt_role_permission; + +IF OBJECT_ID('fk_mt_role_permission_mt_permission', 'F') IS NOT NULL alter table mt_role_permission drop constraint fk_mt_role_permission_mt_permission; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mt_role_permission','U') AND name = 'ix_mt_role_permission_mt_permission') drop index ix_mt_role_permission_mt_permission ON mt_role_permission; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('f_second','U') AND name = 'uq_f_second_first') drop index uq_f_second_first ON f_second; +IF OBJECT_ID('fk_f_second_first', 'F') IS NOT NULL alter table f_second drop constraint fk_f_second_first; + +IF OBJECT_ID('fk_section_article_id', 'F') IS NOT NULL alter table section drop constraint fk_section_article_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('section','U') AND name = 'ix_section_article_id') drop index ix_section_article_id ON section; + +IF OBJECT_ID('fk_self_parent_parent_id', 'F') IS NOT NULL alter table self_parent drop constraint fk_self_parent_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('self_parent','U') AND name = 'ix_self_parent_parent_id') drop index ix_self_parent_parent_id ON self_parent; + +IF OBJECT_ID('fk_self_ref_customer_referred_by_id', 'F') IS NOT NULL alter table self_ref_customer drop constraint fk_self_ref_customer_referred_by_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('self_ref_customer','U') AND name = 'ix_self_ref_customer_referred_by_id') drop index ix_self_ref_customer_referred_by_id ON self_ref_customer; + +IF OBJECT_ID('fk_self_ref_example_parent_id', 'F') IS NOT NULL alter table self_ref_example drop constraint fk_self_ref_example_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('self_ref_example','U') AND name = 'ix_self_ref_example_parent_id') drop index ix_self_ref_example_parent_id ON self_ref_example; + +IF OBJECT_ID('fk_stockforecast_inner_report_id', 'F') IS NOT NULL alter table stockforecast drop constraint fk_stockforecast_inner_report_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('stockforecast','U') AND name = 'ix_stockforecast_inner_report_id') drop index ix_stockforecast_inner_report_id ON stockforecast; + +IF OBJECT_ID('fk_sub_section_section_id', 'F') IS NOT NULL alter table sub_section drop constraint fk_sub_section_section_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('sub_section','U') AND name = 'ix_sub_section_section_id') drop index ix_sub_section_section_id ON sub_section; + +IF OBJECT_ID('fk_tevent_many_event_id', 'F') IS NOT NULL alter table tevent_many drop constraint fk_tevent_many_event_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('tevent_many','U') AND name = 'ix_tevent_many_event_id') drop index ix_tevent_many_event_id ON tevent_many; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('tevent_one','U') AND name = 'uq_tevent_one_event_id') drop index uq_tevent_one_event_id ON tevent_one; +IF OBJECT_ID('fk_tevent_one_event_id', 'F') IS NOT NULL alter table tevent_one drop constraint fk_tevent_one_event_id; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('t_detail_with_other_namexxxyy','U') AND name = 'uq_t_detail_with_other_namexxxyy_some_unique_value') drop index uq_t_detail_with_other_namexxxyy_some_unique_value ON t_detail_with_other_namexxxyy; +IF OBJECT_ID('fk_t_detail_with_other_namexxxyy_master_id', 'F') IS NOT NULL alter table t_detail_with_other_namexxxyy drop constraint fk_t_detail_with_other_namexxxyy_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('t_detail_with_other_namexxxyy','U') AND name = 'ix_t_detail_with_other_namexxxyy_master_id') drop index ix_t_detail_with_other_namexxxyy_master_id ON t_detail_with_other_namexxxyy; + +IF OBJECT_ID('fk_ts_detail_two_master_id', 'F') IS NOT NULL alter table ts_detail_two drop constraint fk_ts_detail_two_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ts_detail_two','U') AND name = 'ix_ts_detail_two_master_id') drop index ix_ts_detail_two_master_id ON ts_detail_two; + +IF OBJECT_ID('fk_twheel_owner_plate_no', 'F') IS NOT NULL alter table twheel drop constraint fk_twheel_owner_plate_no; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('twheel','U') AND name = 'ix_twheel_owner_plate_no') drop index ix_twheel_owner_plate_no ON twheel; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('tire','U') AND name = 'uq_tire_wheel') drop index uq_tire_wheel ON tire; +IF OBJECT_ID('fk_tire_wheel', 'F') IS NOT NULL alter table tire drop constraint fk_tire_wheel; + +IF OBJECT_ID('fk_trip_vehicle_driver_id', 'F') IS NOT NULL alter table trip drop constraint fk_trip_vehicle_driver_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('trip','U') AND name = 'ix_trip_vehicle_driver_id') drop index ix_trip_vehicle_driver_id ON trip; + +IF OBJECT_ID('fk_trip_address_id', 'F') IS NOT NULL alter table trip drop constraint fk_trip_address_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('trip','U') AND name = 'ix_trip_address_id') drop index ix_trip_address_id ON trip; + +IF OBJECT_ID('fk_type_sub_type_id', 'F') IS NOT NULL alter table type drop constraint fk_type_sub_type_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('type','U') AND name = 'ix_type_sub_type_id') drop index ix_type_sub_type_id ON type; + +IF OBJECT_ID('fk_ut_detail_utmaster_id', 'F') IS NOT NULL alter table ut_detail drop constraint fk_ut_detail_utmaster_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('ut_detail','U') AND name = 'ix_ut_detail_utmaster_id') drop index ix_ut_detail_utmaster_id ON ut_detail; + +IF OBJECT_ID('fk_uutwo_master_id', 'F') IS NOT NULL alter table uutwo drop constraint fk_uutwo_master_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('uutwo','U') AND name = 'ix_uutwo_master_id') drop index ix_uutwo_master_id ON uutwo; + +IF OBJECT_ID('fk_c_user_group_id', 'F') IS NOT NULL alter table c_user drop constraint fk_c_user_group_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('c_user','U') AND name = 'ix_c_user_group_id') drop index ix_c_user_group_id ON c_user; + +IF OBJECT_ID('fk_oto_user_account_id', 'F') IS NOT NULL alter table oto_user drop constraint fk_oto_user_account_id; + +IF OBJECT_ID('fk_em_user_role_user_id', 'F') IS NOT NULL alter table em_user_role drop constraint fk_em_user_role_user_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('em_user_role','U') AND name = 'ix_em_user_role_user_id') drop index ix_em_user_role_user_id ON em_user_role; + +IF OBJECT_ID('fk_em_user_role_role_id', 'F') IS NOT NULL alter table em_user_role drop constraint fk_em_user_role_role_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('em_user_role','U') AND name = 'ix_em_user_role_role_id') drop index ix_em_user_role_role_id ON em_user_role; + +IF OBJECT_ID('fk_vehicle_car_ref_id', 'F') IS NOT NULL alter table vehicle drop constraint fk_vehicle_car_ref_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('vehicle','U') AND name = 'ix_vehicle_car_ref_id') drop index ix_vehicle_car_ref_id ON vehicle; + +IF OBJECT_ID('fk_vehicle_truck_ref_id', 'F') IS NOT NULL alter table vehicle drop constraint fk_vehicle_truck_ref_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('vehicle','U') AND name = 'ix_vehicle_truck_ref_id') drop index ix_vehicle_truck_ref_id ON vehicle; + +IF OBJECT_ID('fk_vehicle_driver_vehicle_id', 'F') IS NOT NULL alter table vehicle_driver drop constraint fk_vehicle_driver_vehicle_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('vehicle_driver','U') AND name = 'ix_vehicle_driver_vehicle_id') drop index ix_vehicle_driver_vehicle_id ON vehicle_driver; + +IF OBJECT_ID('fk_vehicle_driver_address_id', 'F') IS NOT NULL alter table vehicle_driver drop constraint fk_vehicle_driver_address_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('vehicle_driver','U') AND name = 'ix_vehicle_driver_address_id') drop index ix_vehicle_driver_address_id ON vehicle_driver; + +IF OBJECT_ID('fk_warehouses_officezoneid', 'F') IS NOT NULL alter table warehouses drop constraint fk_warehouses_officezoneid; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('warehouses','U') AND name = 'ix_warehouses_officezoneid') drop index ix_warehouses_officezoneid ON warehouses; + +IF OBJECT_ID('fk_warehousesshippingzones_warehouses', 'F') IS NOT NULL alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_warehouses; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('warehousesshippingzones','U') AND name = 'ix_warehousesshippingzones_warehouses') drop index ix_warehousesshippingzones_warehouses ON warehousesshippingzones; + +IF OBJECT_ID('fk_warehousesshippingzones_zones', 'F') IS NOT NULL alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_zones; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('warehousesshippingzones','U') AND name = 'ix_warehousesshippingzones_zones') drop index ix_warehousesshippingzones_zones ON warehousesshippingzones; + +IF OBJECT_ID('fk_sa_wheel_tire', 'F') IS NOT NULL alter table sa_wheel drop constraint fk_sa_wheel_tire; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('sa_wheel','U') AND name = 'ix_sa_wheel_tire') drop index ix_sa_wheel_tire ON sa_wheel; + +IF OBJECT_ID('fk_sa_wheel_car', 'F') IS NOT NULL alter table sa_wheel drop constraint fk_sa_wheel_car; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('sa_wheel','U') AND name = 'ix_sa_wheel_car') drop index ix_sa_wheel_car ON sa_wheel; + +IF OBJECT_ID('fk_g_who_props_otm_who_created_id', 'F') IS NOT NULL alter table g_who_props_otm drop constraint fk_g_who_props_otm_who_created_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('g_who_props_otm','U') AND name = 'ix_g_who_props_otm_who_created_id') drop index ix_g_who_props_otm_who_created_id ON g_who_props_otm; + +IF OBJECT_ID('fk_g_who_props_otm_who_modified_id', 'F') IS NOT NULL alter table g_who_props_otm drop constraint fk_g_who_props_otm_who_modified_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('g_who_props_otm','U') AND name = 'ix_g_who_props_otm_who_modified_id') drop index ix_g_who_props_otm_who_modified_id ON g_who_props_otm; + +IF OBJECT_ID('fk_with_zero_parent_id', 'F') IS NOT NULL alter table with_zero drop constraint fk_with_zero_parent_id; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('with_zero','U') AND name = 'ix_with_zero_parent_id') drop index ix_with_zero_parent_id ON with_zero; + +IF OBJECT_ID('asimple_bean', 'U') IS NOT NULL drop table asimple_bean; +IF OBJECT_ID('asimple_bean_seq', 'SO') IS NOT NULL drop sequence asimple_bean_seq; + +IF OBJECT_ID('bar', 'U') IS NOT NULL drop table bar; +IF OBJECT_ID('bar_seq', 'SO') IS NOT NULL drop sequence bar_seq; + +IF OBJECT_ID('oto_account', 'U') IS NOT NULL drop table oto_account; +IF OBJECT_ID('oto_account_seq', 'SO') IS NOT NULL drop sequence oto_account_seq; + +IF OBJECT_ID('addr', 'U') IS NOT NULL drop table addr; +IF OBJECT_ID('addr_seq', 'SO') IS NOT NULL drop sequence addr_seq; + +IF OBJECT_ID('address', 'U') IS NOT NULL drop table address; +IF OBJECT_ID('address_seq', 'SO') IS NOT NULL drop sequence address_seq; + +IF OBJECT_ID('o_address', 'U') IS NOT NULL drop table o_address; +IF OBJECT_ID('o_address_seq', 'SO') IS NOT NULL drop sequence o_address_seq; + +IF OBJECT_ID('album', 'U') IS NOT NULL drop table album; +IF OBJECT_ID('album_seq', 'SO') IS NOT NULL drop sequence album_seq; + +IF OBJECT_ID('animal', 'U') IS NOT NULL drop table animal; +IF OBJECT_ID('animal_seq', 'SO') IS NOT NULL drop sequence animal_seq; + +IF OBJECT_ID('animal_shelter', 'U') IS NOT NULL drop table animal_shelter; +IF OBJECT_ID('animal_shelter_seq', 'SO') IS NOT NULL drop sequence animal_shelter_seq; + +IF OBJECT_ID('article', 'U') IS NOT NULL drop table article; +IF OBJECT_ID('article_seq', 'SO') IS NOT NULL drop sequence article_seq; + +IF OBJECT_ID('attribute', 'U') IS NOT NULL drop table attribute; +IF OBJECT_ID('attribute_seq', 'SO') IS NOT NULL drop sequence attribute_seq; + +IF OBJECT_ID('attribute_holder', 'U') IS NOT NULL drop table attribute_holder; +IF OBJECT_ID('attribute_holder_seq', 'SO') IS NOT NULL drop sequence attribute_holder_seq; + +IF OBJECT_ID('audit_log', 'U') IS NOT NULL drop table audit_log; +IF OBJECT_ID('audit_log_seq', 'SO') IS NOT NULL drop sequence audit_log_seq; + +IF OBJECT_ID('bbookmark', 'U') IS NOT NULL drop table bbookmark; +IF OBJECT_ID('bbookmark_seq', 'SO') IS NOT NULL drop sequence bbookmark_seq; + +IF OBJECT_ID('bbookmark_user', 'U') IS NOT NULL drop table bbookmark_user; +IF OBJECT_ID('bbookmark_user_seq', 'SO') IS NOT NULL drop sequence bbookmark_user_seq; + +IF OBJECT_ID('bsimple_with_gen', 'U') IS NOT NULL drop table bsimple_with_gen; +IF OBJECT_ID('bsimple_with_gen_seq', 'SO') IS NOT NULL drop sequence bsimple_with_gen_seq; + +IF OBJECT_ID('bsite', 'U') IS NOT NULL drop table bsite; + +IF OBJECT_ID('bsite_user', 'U') IS NOT NULL drop table bsite_user; + +IF OBJECT_ID('bsite_user_b', 'U') IS NOT NULL drop table bsite_user_b; + +IF OBJECT_ID('bsite_user_c', 'U') IS NOT NULL drop table bsite_user_c; + +IF OBJECT_ID('buser', 'U') IS NOT NULL drop table buser; + +IF OBJECT_ID('bwith_qident', 'U') IS NOT NULL drop table bwith_qident; +IF OBJECT_ID('bwith_qident_seq', 'SO') IS NOT NULL drop sequence bwith_qident_seq; + +IF OBJECT_ID('basic_joda_entity', 'U') IS NOT NULL drop table basic_joda_entity; +IF OBJECT_ID('basic_joda_entity_seq', 'SO') IS NOT NULL drop sequence basic_joda_entity_seq; + +IF OBJECT_ID('bean_with_time_zone', 'U') IS NOT NULL drop table bean_with_time_zone; +IF OBJECT_ID('bean_with_time_zone_seq', 'SO') IS NOT NULL drop sequence bean_with_time_zone_seq; + +IF OBJECT_ID('drel_booking', 'U') IS NOT NULL drop table drel_booking; +IF OBJECT_ID('drel_booking_seq', 'SO') IS NOT NULL drop sequence drel_booking_seq; + +IF OBJECT_ID('cinh_root', 'U') IS NOT NULL drop table cinh_root; +IF OBJECT_ID('cinh_root_seq', 'SO') IS NOT NULL drop sequence cinh_root_seq; + +IF OBJECT_ID('ckey_assoc', 'U') IS NOT NULL drop table ckey_assoc; +IF OBJECT_ID('ckey_assoc_seq', 'SO') IS NOT NULL drop sequence ckey_assoc_seq; + +IF OBJECT_ID('ckey_detail', 'U') IS NOT NULL drop table ckey_detail; +IF OBJECT_ID('ckey_detail_seq', 'SO') IS NOT NULL drop sequence ckey_detail_seq; + +IF OBJECT_ID('ckey_parent', 'U') IS NOT NULL drop table ckey_parent; + +IF OBJECT_ID('calculation_result', 'U') IS NOT NULL drop table calculation_result; +IF OBJECT_ID('calculation_result_seq', 'SO') IS NOT NULL drop sequence calculation_result_seq; + +IF OBJECT_ID('cao_bean', 'U') IS NOT NULL drop table cao_bean; + +IF OBJECT_ID('sa_car', 'U') IS NOT NULL drop table sa_car; +IF OBJECT_ID('sa_car_seq', 'SO') IS NOT NULL drop sequence sa_car_seq; + +IF OBJECT_ID('sp_car_car', 'U') IS NOT NULL drop table sp_car_car; +IF OBJECT_ID('sp_car_car_seq', 'SO') IS NOT NULL drop sequence sp_car_car_seq; + +IF OBJECT_ID('sp_car_car_wheels', 'U') IS NOT NULL drop table sp_car_car_wheels; + +IF OBJECT_ID('car_accessory', 'U') IS NOT NULL drop table car_accessory; +IF OBJECT_ID('car_accessory_seq', 'SO') IS NOT NULL drop sequence car_accessory_seq; + +IF OBJECT_ID('car_fuse', 'U') IS NOT NULL drop table car_fuse; +IF OBJECT_ID('car_fuse_seq', 'SO') IS NOT NULL drop sequence car_fuse_seq; + +IF OBJECT_ID('category', 'U') IS NOT NULL drop table category; +IF OBJECT_ID('category_seq', 'SO') IS NOT NULL drop sequence category_seq; + +IF OBJECT_ID('child_person', 'U') IS NOT NULL drop table child_person; +IF OBJECT_ID('child_person_seq', 'SO') IS NOT NULL drop sequence child_person_seq; + +IF OBJECT_ID('configuration', 'U') IS NOT NULL drop table configuration; +IF OBJECT_ID('configuration_seq', 'SO') IS NOT NULL drop sequence configuration_seq; + +IF OBJECT_ID('configurations', 'U') IS NOT NULL drop table configurations; +IF OBJECT_ID('configurations_seq', 'SO') IS NOT NULL drop sequence configurations_seq; + +IF OBJECT_ID('contact', 'U') IS NOT NULL drop table contact; +IF OBJECT_ID('contact_seq', 'SO') IS NOT NULL drop sequence contact_seq; + +IF OBJECT_ID('contact_group', 'U') IS NOT NULL drop table contact_group; +IF OBJECT_ID('contact_group_seq', 'SO') IS NOT NULL drop sequence contact_group_seq; + +IF OBJECT_ID('contact_note', 'U') IS NOT NULL drop table contact_note; +IF OBJECT_ID('contact_note_seq', 'SO') IS NOT NULL drop sequence contact_note_seq; + +IF OBJECT_ID('c_conversation', 'U') IS NOT NULL drop table c_conversation; +IF OBJECT_ID('c_conversation_seq', 'SO') IS NOT NULL drop sequence c_conversation_seq; + +IF OBJECT_ID('o_country', 'U') IS NOT NULL drop table o_country; + +IF OBJECT_ID('cover', 'U') IS NOT NULL drop table cover; +IF OBJECT_ID('cover_seq', 'SO') IS NOT NULL drop sequence cover_seq; + +IF OBJECT_ID('o_customer', 'U') IS NOT NULL drop table o_customer; +IF OBJECT_ID('o_customer_seq', 'SO') IS NOT NULL drop sequence o_customer_seq; + +IF OBJECT_ID('dcredit', 'U') IS NOT NULL drop table dcredit; +IF OBJECT_ID('dcredit_seq', 'SO') IS NOT NULL drop sequence dcredit_seq; + +IF OBJECT_ID('dcredit_drol', 'U') IS NOT NULL drop table dcredit_drol; + +IF OBJECT_ID('dexh_entity', 'U') IS NOT NULL drop table dexh_entity; +IF OBJECT_ID('dexh_entity_seq', 'SO') IS NOT NULL drop sequence dexh_entity_seq; + +IF OBJECT_ID('dperson', 'U') IS NOT NULL drop table dperson; +IF OBJECT_ID('dperson_seq', 'SO') IS NOT NULL drop sequence dperson_seq; + +IF OBJECT_ID('drol', 'U') IS NOT NULL drop table drol; +IF OBJECT_ID('drol_seq', 'SO') IS NOT NULL drop sequence drol_seq; + +IF OBJECT_ID('drot', 'U') IS NOT NULL drop table drot; +IF OBJECT_ID('drot_seq', 'SO') IS NOT NULL drop sequence drot_seq; + +IF OBJECT_ID('drot_drol', 'U') IS NOT NULL drop table drot_drol; + +IF OBJECT_ID('rawinherit_data', 'U') IS NOT NULL drop table rawinherit_data; +IF OBJECT_ID('rawinherit_data_seq', 'SO') IS NOT NULL drop sequence rawinherit_data_seq; + +IF OBJECT_ID('dfk_cascade', 'U') IS NOT NULL drop table dfk_cascade; +IF OBJECT_ID('dfk_cascade_seq', 'SO') IS NOT NULL drop sequence dfk_cascade_seq; + +IF OBJECT_ID('dfk_cascade_one', 'U') IS NOT NULL drop table dfk_cascade_one; +IF OBJECT_ID('dfk_cascade_one_seq', 'SO') IS NOT NULL drop sequence dfk_cascade_one_seq; + +IF OBJECT_ID('dfk_none', 'U') IS NOT NULL drop table dfk_none; +IF OBJECT_ID('dfk_none_seq', 'SO') IS NOT NULL drop sequence dfk_none_seq; + +IF OBJECT_ID('dfk_none_via_join', 'U') IS NOT NULL drop table dfk_none_via_join; +IF OBJECT_ID('dfk_none_via_join_seq', 'SO') IS NOT NULL drop sequence dfk_none_via_join_seq; + +IF OBJECT_ID('dfk_one', 'U') IS NOT NULL drop table dfk_one; +IF OBJECT_ID('dfk_one_seq', 'SO') IS NOT NULL drop sequence dfk_one_seq; + +IF OBJECT_ID('dfk_set_null', 'U') IS NOT NULL drop table dfk_set_null; +IF OBJECT_ID('dfk_set_null_seq', 'SO') IS NOT NULL drop sequence dfk_set_null_seq; + +IF OBJECT_ID('doc', 'U') IS NOT NULL drop table doc; +IF OBJECT_ID('doc_seq', 'SO') IS NOT NULL drop sequence doc_seq; + +IF OBJECT_ID('doc_link', 'U') IS NOT NULL drop table doc_link; + +IF OBJECT_ID('doc_link_draft', 'U') IS NOT NULL drop table doc_link_draft; + +IF OBJECT_ID('doc_draft', 'U') IS NOT NULL drop table doc_draft; +IF OBJECT_ID('doc_draft_seq', 'SO') IS NOT NULL drop sequence doc_draft_seq; + +IF OBJECT_ID('document', 'U') IS NOT NULL drop table document; +IF OBJECT_ID('document_seq', 'SO') IS NOT NULL drop sequence document_seq; + +IF OBJECT_ID('document_draft', 'U') IS NOT NULL drop table document_draft; +IF OBJECT_ID('document_draft_seq', 'SO') IS NOT NULL drop sequence document_draft_seq; + +IF OBJECT_ID('document_media', 'U') IS NOT NULL drop table document_media; +IF OBJECT_ID('document_media_seq', 'SO') IS NOT NULL drop sequence document_media_seq; + +IF OBJECT_ID('document_media_draft', 'U') IS NOT NULL drop table document_media_draft; +IF OBJECT_ID('document_media_draft_seq', 'SO') IS NOT NULL drop sequence document_media_draft_seq; + +IF OBJECT_ID('earray_bean', 'U') IS NOT NULL drop table earray_bean; +IF OBJECT_ID('earray_bean_seq', 'SO') IS NOT NULL drop sequence earray_bean_seq; + +IF OBJECT_ID('earray_set_bean', 'U') IS NOT NULL drop table earray_set_bean; +IF OBJECT_ID('earray_set_bean_seq', 'SO') IS NOT NULL drop sequence earray_set_bean_seq; + +IF OBJECT_ID('e_basic', 'U') IS NOT NULL drop table e_basic; +IF OBJECT_ID('e_basic_seq', 'SO') IS NOT NULL drop sequence e_basic_seq; + +IF OBJECT_ID('ebasic_change_log', 'U') IS NOT NULL drop table ebasic_change_log; +IF OBJECT_ID('ebasic_change_log_seq', 'SO') IS NOT NULL drop sequence ebasic_change_log_seq; + +IF OBJECT_ID('ebasic_clob', 'U') IS NOT NULL drop table ebasic_clob; +IF OBJECT_ID('ebasic_clob_seq', 'SO') IS NOT NULL drop sequence ebasic_clob_seq; + +IF OBJECT_ID('ebasic_clob_fetch_eager', 'U') IS NOT NULL drop table ebasic_clob_fetch_eager; +IF OBJECT_ID('ebasic_clob_fetch_eager_seq', 'SO') IS NOT NULL drop sequence ebasic_clob_fetch_eager_seq; + +IF OBJECT_ID('ebasic_clob_no_ver', 'U') IS NOT NULL drop table ebasic_clob_no_ver; +IF OBJECT_ID('ebasic_clob_no_ver_seq', 'SO') IS NOT NULL drop sequence ebasic_clob_no_ver_seq; + +IF OBJECT_ID('e_basicenc', 'U') IS NOT NULL drop table e_basicenc; +IF OBJECT_ID('e_basicenc_seq', 'SO') IS NOT NULL drop sequence e_basicenc_seq; + +IF OBJECT_ID('e_basicenc_bin', 'U') IS NOT NULL drop table e_basicenc_bin; +IF OBJECT_ID('e_basicenc_bin_seq', 'SO') IS NOT NULL drop sequence e_basicenc_bin_seq; + +IF OBJECT_ID('e_basic_enum_id', 'U') IS NOT NULL drop table e_basic_enum_id; + +IF OBJECT_ID('e_basic_eni', 'U') IS NOT NULL drop table e_basic_eni; +IF OBJECT_ID('e_basic_eni_seq', 'SO') IS NOT NULL drop sequence e_basic_eni_seq; + +IF OBJECT_ID('ebasic_hstore', 'U') IS NOT NULL drop table ebasic_hstore; +IF OBJECT_ID('ebasic_hstore_seq', 'SO') IS NOT NULL drop sequence ebasic_hstore_seq; + +IF OBJECT_ID('ebasic_json_list', 'U') IS NOT NULL drop table ebasic_json_list; +IF OBJECT_ID('ebasic_json_list_seq', 'SO') IS NOT NULL drop sequence ebasic_json_list_seq; + +IF OBJECT_ID('ebasic_json_map', 'U') IS NOT NULL drop table ebasic_json_map; +IF OBJECT_ID('ebasic_json_map_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_seq; + +IF OBJECT_ID('ebasic_json_map_blob', 'U') IS NOT NULL drop table ebasic_json_map_blob; +IF OBJECT_ID('ebasic_json_map_blob_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_blob_seq; + +IF OBJECT_ID('ebasic_json_map_clob', 'U') IS NOT NULL drop table ebasic_json_map_clob; +IF OBJECT_ID('ebasic_json_map_clob_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_clob_seq; + +IF OBJECT_ID('ebasic_json_map_detail', 'U') IS NOT NULL drop table ebasic_json_map_detail; +IF OBJECT_ID('ebasic_json_map_detail_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_detail_seq; + +IF OBJECT_ID('ebasic_json_map_json_b', 'U') IS NOT NULL drop table ebasic_json_map_json_b; +IF OBJECT_ID('ebasic_json_map_json_b_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_json_b_seq; + +IF OBJECT_ID('ebasic_json_map_varchar', 'U') IS NOT NULL drop table ebasic_json_map_varchar; +IF OBJECT_ID('ebasic_json_map_varchar_seq', 'SO') IS NOT NULL drop sequence ebasic_json_map_varchar_seq; + +IF OBJECT_ID('ebasic_json_node', 'U') IS NOT NULL drop table ebasic_json_node; +IF OBJECT_ID('ebasic_json_node_seq', 'SO') IS NOT NULL drop sequence ebasic_json_node_seq; + +IF OBJECT_ID('ebasic_json_node_blob', 'U') IS NOT NULL drop table ebasic_json_node_blob; +IF OBJECT_ID('ebasic_json_node_blob_seq', 'SO') IS NOT NULL drop sequence ebasic_json_node_blob_seq; + +IF OBJECT_ID('ebasic_json_node_json_b', 'U') IS NOT NULL drop table ebasic_json_node_json_b; +IF OBJECT_ID('ebasic_json_node_json_b_seq', 'SO') IS NOT NULL drop sequence ebasic_json_node_json_b_seq; + +IF OBJECT_ID('ebasic_json_node_varchar', 'U') IS NOT NULL drop table ebasic_json_node_varchar; +IF OBJECT_ID('ebasic_json_node_varchar_seq', 'SO') IS NOT NULL drop sequence ebasic_json_node_varchar_seq; + +IF OBJECT_ID('ebasic_json_unmapped', 'U') IS NOT NULL drop table ebasic_json_unmapped; +IF OBJECT_ID('ebasic_json_unmapped_seq', 'SO') IS NOT NULL drop sequence ebasic_json_unmapped_seq; + +IF OBJECT_ID('e_basic_ndc', 'U') IS NOT NULL drop table e_basic_ndc; +IF OBJECT_ID('e_basic_ndc_seq', 'SO') IS NOT NULL drop sequence e_basic_ndc_seq; + +IF OBJECT_ID('ebasic_no_sdchild', 'U') IS NOT NULL drop table ebasic_no_sdchild; +IF OBJECT_ID('ebasic_no_sdchild_seq', 'SO') IS NOT NULL drop sequence ebasic_no_sdchild_seq; + +IF OBJECT_ID('ebasic_sdchild', 'U') IS NOT NULL drop table ebasic_sdchild; +IF OBJECT_ID('ebasic_sdchild_seq', 'SO') IS NOT NULL drop sequence ebasic_sdchild_seq; + +IF OBJECT_ID('ebasic_soft_delete', 'U') IS NOT NULL drop table ebasic_soft_delete; +IF OBJECT_ID('ebasic_soft_delete_seq', 'SO') IS NOT NULL drop sequence ebasic_soft_delete_seq; + +IF OBJECT_ID('e_basicver', 'U') IS NOT NULL drop table e_basicver; +IF OBJECT_ID('e_basicver_seq', 'SO') IS NOT NULL drop sequence e_basicver_seq; + +IF OBJECT_ID('e_basic_withlife', 'U') IS NOT NULL drop table e_basic_withlife; +IF OBJECT_ID('e_basic_withlife_seq', 'SO') IS NOT NULL drop sequence e_basic_withlife_seq; + +IF OBJECT_ID('e_basicverucon', 'U') IS NOT NULL drop table e_basicverucon; +IF OBJECT_ID('e_basicverucon_seq', 'SO') IS NOT NULL drop sequence e_basicverucon_seq; + +IF OBJECT_ID('e_col_ab', 'U') IS NOT NULL drop table e_col_ab; +IF OBJECT_ID('e_col_ab_seq', 'SO') IS NOT NULL drop sequence e_col_ab_seq; + +IF OBJECT_ID('ecustom_id', 'U') IS NOT NULL drop table ecustom_id; + +IF OBJECT_ID('eemb_inner', 'U') IS NOT NULL drop table eemb_inner; +IF OBJECT_ID('eemb_inner_seq', 'SO') IS NOT NULL drop sequence eemb_inner_seq; + +IF OBJECT_ID('eemb_outer', 'U') IS NOT NULL drop table eemb_outer; +IF OBJECT_ID('eemb_outer_seq', 'SO') IS NOT NULL drop sequence eemb_outer_seq; + +IF OBJECT_ID('egen_props', 'U') IS NOT NULL drop table egen_props; +IF OBJECT_ID('egen_props_seq', 'SO') IS NOT NULL drop sequence egen_props_seq; + +IF OBJECT_ID('einvoice', 'U') IS NOT NULL drop table einvoice; +IF OBJECT_ID('einvoice_seq', 'SO') IS NOT NULL drop sequence einvoice_seq; + +IF OBJECT_ID('e_main', 'U') IS NOT NULL drop table e_main; +IF OBJECT_ID('e_main_seq', 'SO') IS NOT NULL drop sequence e_main_seq; + +IF OBJECT_ID('enull_collection', 'U') IS NOT NULL drop table enull_collection; +IF OBJECT_ID('enull_collection_seq', 'SO') IS NOT NULL drop sequence enull_collection_seq; + +IF OBJECT_ID('enull_collection_detail', 'U') IS NOT NULL drop table enull_collection_detail; +IF OBJECT_ID('enull_collection_detail_seq', 'SO') IS NOT NULL drop sequence enull_collection_detail_seq; + +IF OBJECT_ID('eopt_one_a', 'U') IS NOT NULL drop table eopt_one_a; +IF OBJECT_ID('eopt_one_a_seq', 'SO') IS NOT NULL drop sequence eopt_one_a_seq; + +IF OBJECT_ID('eopt_one_b', 'U') IS NOT NULL drop table eopt_one_b; +IF OBJECT_ID('eopt_one_b_seq', 'SO') IS NOT NULL drop sequence eopt_one_b_seq; + +IF OBJECT_ID('eopt_one_c', 'U') IS NOT NULL drop table eopt_one_c; +IF OBJECT_ID('eopt_one_c_seq', 'SO') IS NOT NULL drop sequence eopt_one_c_seq; + +IF OBJECT_ID('eperson', 'U') IS NOT NULL drop table eperson; +IF OBJECT_ID('eperson_seq', 'SO') IS NOT NULL drop sequence eperson_seq; + +IF OBJECT_ID('e_person_online', 'U') IS NOT NULL drop table e_person_online; +IF OBJECT_ID('e_person_online_seq', 'SO') IS NOT NULL drop sequence e_person_online_seq; + +IF OBJECT_ID('esimple', 'U') IS NOT NULL drop table esimple; + +IF OBJECT_ID('esoft_del_book', 'U') IS NOT NULL drop table esoft_del_book; +IF OBJECT_ID('esoft_del_book_seq', 'SO') IS NOT NULL drop sequence esoft_del_book_seq; + +IF OBJECT_ID('esoft_del_book_esoft_del_user', 'U') IS NOT NULL drop table esoft_del_book_esoft_del_user; + +IF OBJECT_ID('esoft_del_down', 'U') IS NOT NULL drop table esoft_del_down; +IF OBJECT_ID('esoft_del_down_seq', 'SO') IS NOT NULL drop sequence esoft_del_down_seq; + +IF OBJECT_ID('esoft_del_mid', 'U') IS NOT NULL drop table esoft_del_mid; +IF OBJECT_ID('esoft_del_mid_seq', 'SO') IS NOT NULL drop sequence esoft_del_mid_seq; + +IF OBJECT_ID('esoft_del_one_a', 'U') IS NOT NULL drop table esoft_del_one_a; +IF OBJECT_ID('esoft_del_one_a_seq', 'SO') IS NOT NULL drop sequence esoft_del_one_a_seq; + +IF OBJECT_ID('esoft_del_one_b', 'U') IS NOT NULL drop table esoft_del_one_b; +IF OBJECT_ID('esoft_del_one_b_seq', 'SO') IS NOT NULL drop sequence esoft_del_one_b_seq; + +IF OBJECT_ID('esoft_del_role', 'U') IS NOT NULL drop table esoft_del_role; +IF OBJECT_ID('esoft_del_role_seq', 'SO') IS NOT NULL drop sequence esoft_del_role_seq; + +IF OBJECT_ID('esoft_del_role_esoft_del_user', 'U') IS NOT NULL drop table esoft_del_role_esoft_del_user; + +IF OBJECT_ID('esoft_del_top', 'U') IS NOT NULL drop table esoft_del_top; +IF OBJECT_ID('esoft_del_top_seq', 'SO') IS NOT NULL drop sequence esoft_del_top_seq; + +IF OBJECT_ID('esoft_del_up', 'U') IS NOT NULL drop table esoft_del_up; +IF OBJECT_ID('esoft_del_up_seq', 'SO') IS NOT NULL drop sequence esoft_del_up_seq; + +IF OBJECT_ID('esoft_del_user', 'U') IS NOT NULL drop table esoft_del_user; +IF OBJECT_ID('esoft_del_user_seq', 'SO') IS NOT NULL drop sequence esoft_del_user_seq; + +IF OBJECT_ID('esoft_del_user_esoft_del_role', 'U') IS NOT NULL drop table esoft_del_user_esoft_del_role; + +IF OBJECT_ID('esome_convert_type', 'U') IS NOT NULL drop table esome_convert_type; +IF OBJECT_ID('esome_convert_type_seq', 'SO') IS NOT NULL drop sequence esome_convert_type_seq; + +IF OBJECT_ID('esome_type', 'U') IS NOT NULL drop table esome_type; +IF OBJECT_ID('esome_type_seq', 'SO') IS NOT NULL drop sequence esome_type_seq; + +IF OBJECT_ID('etrans_many', 'U') IS NOT NULL drop table etrans_many; +IF OBJECT_ID('etrans_many_seq', 'SO') IS NOT NULL drop sequence etrans_many_seq; + +IF OBJECT_ID('rawinherit_uncle', 'U') IS NOT NULL drop table rawinherit_uncle; +IF OBJECT_ID('rawinherit_uncle_seq', 'SO') IS NOT NULL drop sequence rawinherit_uncle_seq; + +IF OBJECT_ID('evanilla_collection', 'U') IS NOT NULL drop table evanilla_collection; +IF OBJECT_ID('evanilla_collection_seq', 'SO') IS NOT NULL drop sequence evanilla_collection_seq; + +IF OBJECT_ID('evanilla_collection_detail', 'U') IS NOT NULL drop table evanilla_collection_detail; +IF OBJECT_ID('evanilla_collection_detail_seq', 'SO') IS NOT NULL drop sequence evanilla_collection_detail_seq; + +IF OBJECT_ID('ewho_props', 'U') IS NOT NULL drop table ewho_props; +IF OBJECT_ID('ewho_props_seq', 'SO') IS NOT NULL drop sequence ewho_props_seq; + +IF OBJECT_ID('e_withinet', 'U') IS NOT NULL drop table e_withinet; +IF OBJECT_ID('e_withinet_seq', 'SO') IS NOT NULL drop sequence e_withinet_seq; + +IF OBJECT_ID('td_child', 'U') IS NOT NULL drop table td_child; +IF OBJECT_ID('td_child_seq', 'SO') IS NOT NULL drop sequence td_child_seq; + +IF OBJECT_ID('td_parent', 'U') IS NOT NULL drop table td_parent; +IF OBJECT_ID('td_parent_seq', 'SO') IS NOT NULL drop sequence td_parent_seq; + +IF OBJECT_ID('empl', 'U') IS NOT NULL drop table empl; +IF OBJECT_ID('empl_seq', 'SO') IS NOT NULL drop sequence empl_seq; + +IF OBJECT_ID('feature_desc', 'U') IS NOT NULL drop table feature_desc; +IF OBJECT_ID('feature_desc_seq', 'SO') IS NOT NULL drop sequence feature_desc_seq; + +IF OBJECT_ID('f_first', 'U') IS NOT NULL drop table f_first; +IF OBJECT_ID('f_first_seq', 'SO') IS NOT NULL drop sequence f_first_seq; + +IF OBJECT_ID('foo', 'U') IS NOT NULL drop table foo; +IF OBJECT_ID('foo_seq', 'SO') IS NOT NULL drop sequence foo_seq; + +IF OBJECT_ID('gen_key_identity', 'U') IS NOT NULL drop table gen_key_identity; + +IF OBJECT_ID('gen_key_sequence', 'U') IS NOT NULL drop table gen_key_sequence; +IF OBJECT_ID('SEQ', 'SO') IS NOT NULL drop sequence SEQ; + +IF OBJECT_ID('gen_key_table', 'U') IS NOT NULL drop table gen_key_table; +IF OBJECT_ID('gen_key_table_seq', 'SO') IS NOT NULL drop sequence gen_key_table_seq; + +IF OBJECT_ID('grand_parent_person', 'U') IS NOT NULL drop table grand_parent_person; +IF OBJECT_ID('grand_parent_person_seq', 'SO') IS NOT NULL drop sequence grand_parent_person_seq; + +IF OBJECT_ID('survey_group', 'U') IS NOT NULL drop table survey_group; +IF OBJECT_ID('survey_group_seq', 'SO') IS NOT NULL drop sequence survey_group_seq; + +IF OBJECT_ID('c_group', 'U') IS NOT NULL drop table c_group; +IF OBJECT_ID('c_group_seq', 'SO') IS NOT NULL drop sequence c_group_seq; + +IF OBJECT_ID('he_doc', 'U') IS NOT NULL drop table he_doc; +IF OBJECT_ID('he_doc_seq', 'SO') IS NOT NULL drop sequence he_doc_seq; + +IF OBJECT_ID('hx_link', 'U') IS NOT NULL alter table hx_link set (system_versioning = off); +IF OBJECT_ID('hx_link_history', 'U') IS NOT NULL drop table hx_link_history; +IF OBJECT_ID('hx_link', 'U') IS NOT NULL drop table hx_link; +IF OBJECT_ID('hx_link_seq', 'SO') IS NOT NULL drop sequence hx_link_seq; + +IF OBJECT_ID('hx_link_doc', 'U') IS NOT NULL drop table hx_link_doc; + +IF OBJECT_ID('hi_doc', 'U') IS NOT NULL drop table hi_doc; +IF OBJECT_ID('hi_doc_seq', 'SO') IS NOT NULL drop sequence hi_doc_seq; + +IF OBJECT_ID('hi_link', 'U') IS NOT NULL alter table hi_link set (system_versioning = off); +IF OBJECT_ID('hi_link_history', 'U') IS NOT NULL drop table hi_link_history; +IF OBJECT_ID('hi_link', 'U') IS NOT NULL drop table hi_link; +IF OBJECT_ID('hi_link_seq', 'SO') IS NOT NULL drop sequence hi_link_seq; + +IF OBJECT_ID('hi_link_doc', 'U') IS NOT NULL alter table hi_link_doc set (system_versioning = off); +IF OBJECT_ID('hi_link_doc_history', 'U') IS NOT NULL drop table hi_link_doc_history; +IF OBJECT_ID('hi_link_doc', 'U') IS NOT NULL drop table hi_link_doc; + +IF OBJECT_ID('imrelated', 'U') IS NOT NULL drop table imrelated; +IF OBJECT_ID('imrelated_seq', 'SO') IS NOT NULL drop sequence imrelated_seq; + +IF OBJECT_ID('imroot', 'U') IS NOT NULL drop table imroot; +IF OBJECT_ID('imroot_seq', 'SO') IS NOT NULL drop sequence imroot_seq; + +IF OBJECT_ID('ixresource', 'U') IS NOT NULL drop table ixresource; + +IF OBJECT_ID('info_company', 'U') IS NOT NULL drop table info_company; +IF OBJECT_ID('info_company_seq', 'SO') IS NOT NULL drop sequence info_company_seq; + +IF OBJECT_ID('info_contact', 'U') IS NOT NULL drop table info_contact; +IF OBJECT_ID('info_contact_seq', 'SO') IS NOT NULL drop sequence info_contact_seq; + +IF OBJECT_ID('info_customer', 'U') IS NOT NULL drop table info_customer; +IF OBJECT_ID('info_customer_seq', 'SO') IS NOT NULL drop sequence info_customer_seq; + +IF OBJECT_ID('inner_report', 'U') IS NOT NULL drop table inner_report; +IF OBJECT_ID('inner_report_seq', 'SO') IS NOT NULL drop sequence inner_report_seq; + +IF OBJECT_ID('drel_invoice', 'U') IS NOT NULL drop table drel_invoice; +IF OBJECT_ID('drel_invoice_seq', 'SO') IS NOT NULL drop sequence drel_invoice_seq; + +IF OBJECT_ID('item', 'U') IS NOT NULL drop table item; + +IF OBJECT_ID('monkey', 'U') IS NOT NULL drop table monkey; +IF OBJECT_ID('monkey_seq', 'SO') IS NOT NULL drop sequence monkey_seq; + +IF OBJECT_ID('trainer', 'U') IS NOT NULL drop table trainer; +IF OBJECT_ID('trainer_seq', 'SO') IS NOT NULL drop sequence trainer_seq; + +IF OBJECT_ID('trainer_monkey', 'U') IS NOT NULL drop table trainer_monkey; + +IF OBJECT_ID('troop', 'U') IS NOT NULL drop table troop; +IF OBJECT_ID('troop_seq', 'SO') IS NOT NULL drop sequence troop_seq; + +IF OBJECT_ID('troop_monkey', 'U') IS NOT NULL drop table troop_monkey; + +IF OBJECT_ID('l2_cldf_reset_bean', 'U') IS NOT NULL drop table l2_cldf_reset_bean; +IF OBJECT_ID('l2_cldf_reset_bean_seq', 'SO') IS NOT NULL drop sequence l2_cldf_reset_bean_seq; + +IF OBJECT_ID('l2_cldf_reset_bean_child', 'U') IS NOT NULL drop table l2_cldf_reset_bean_child; +IF OBJECT_ID('l2_cldf_reset_bean_child_seq', 'SO') IS NOT NULL drop sequence l2_cldf_reset_bean_child_seq; + +IF OBJECT_ID('level1', 'U') IS NOT NULL drop table level1; +IF OBJECT_ID('level1_seq', 'SO') IS NOT NULL drop sequence level1_seq; + +IF OBJECT_ID('level1_level4', 'U') IS NOT NULL drop table level1_level4; + +IF OBJECT_ID('level1_level2', 'U') IS NOT NULL drop table level1_level2; + +IF OBJECT_ID('level2', 'U') IS NOT NULL drop table level2; +IF OBJECT_ID('level2_seq', 'SO') IS NOT NULL drop sequence level2_seq; + +IF OBJECT_ID('level2_level3', 'U') IS NOT NULL drop table level2_level3; + +IF OBJECT_ID('level3', 'U') IS NOT NULL drop table level3; +IF OBJECT_ID('level3_seq', 'SO') IS NOT NULL drop sequence level3_seq; + +IF OBJECT_ID('level4', 'U') IS NOT NULL drop table level4; +IF OBJECT_ID('level4_seq', 'SO') IS NOT NULL drop sequence level4_seq; + +IF OBJECT_ID('link', 'U') IS NOT NULL alter table link set (system_versioning = off); +IF OBJECT_ID('link_history', 'U') IS NOT NULL drop table link_history; +IF OBJECT_ID('link', 'U') IS NOT NULL drop table link; +IF OBJECT_ID('link_seq', 'SO') IS NOT NULL drop sequence link_seq; + +IF OBJECT_ID('link_draft', 'U') IS NOT NULL drop table link_draft; +IF OBJECT_ID('link_draft_seq', 'SO') IS NOT NULL drop sequence link_draft_seq; + +IF OBJECT_ID('la_attr_value', 'U') IS NOT NULL drop table la_attr_value; +IF OBJECT_ID('la_attr_value_seq', 'SO') IS NOT NULL drop sequence la_attr_value_seq; + +IF OBJECT_ID('la_attr_value_attribute', 'U') IS NOT NULL drop table la_attr_value_attribute; + +IF OBJECT_ID('mmedia', 'U') IS NOT NULL drop table mmedia; +IF OBJECT_ID('mmedia_seq', 'SO') IS NOT NULL drop sequence mmedia_seq; + +IF OBJECT_ID('non_updateprop', 'U') IS NOT NULL drop table non_updateprop; +IF OBJECT_ID('non_updateprop_seq', 'SO') IS NOT NULL drop sequence non_updateprop_seq; + +IF OBJECT_ID('mprinter', 'U') IS NOT NULL drop table mprinter; +IF OBJECT_ID('mprinter_seq', 'SO') IS NOT NULL drop sequence mprinter_seq; + +IF OBJECT_ID('mprinter_state', 'U') IS NOT NULL drop table mprinter_state; +IF OBJECT_ID('mprinter_state_seq', 'SO') IS NOT NULL drop sequence mprinter_state_seq; + +IF OBJECT_ID('mprofile', 'U') IS NOT NULL drop table mprofile; +IF OBJECT_ID('mprofile_seq', 'SO') IS NOT NULL drop sequence mprofile_seq; + +IF OBJECT_ID('mprotected_construct_bean', 'U') IS NOT NULL drop table mprotected_construct_bean; +IF OBJECT_ID('mprotected_construct_bean_seq', 'SO') IS NOT NULL drop sequence mprotected_construct_bean_seq; + +IF OBJECT_ID('mrole', 'U') IS NOT NULL drop table mrole; +IF OBJECT_ID('mrole_seq', 'SO') IS NOT NULL drop sequence mrole_seq; + +IF OBJECT_ID('mrole_muser', 'U') IS NOT NULL drop table mrole_muser; + +IF OBJECT_ID('msome_other', 'U') IS NOT NULL drop table msome_other; +IF OBJECT_ID('msome_other_seq', 'SO') IS NOT NULL drop sequence msome_other_seq; + +IF OBJECT_ID('muser', 'U') IS NOT NULL drop table muser; +IF OBJECT_ID('muser_seq', 'SO') IS NOT NULL drop sequence muser_seq; + +IF OBJECT_ID('muser_type', 'U') IS NOT NULL drop table muser_type; +IF OBJECT_ID('muser_type_seq', 'SO') IS NOT NULL drop sequence muser_type_seq; + +IF OBJECT_ID('mail_box', 'U') IS NOT NULL drop table mail_box; +IF OBJECT_ID('mail_box_seq', 'SO') IS NOT NULL drop sequence mail_box_seq; + +IF OBJECT_ID('mail_user', 'U') IS NOT NULL drop table mail_user; +IF OBJECT_ID('mail_user_seq', 'SO') IS NOT NULL drop sequence mail_user_seq; + +IF OBJECT_ID('mail_user_inbox', 'U') IS NOT NULL drop table mail_user_inbox; + +IF OBJECT_ID('mail_user_outbox', 'U') IS NOT NULL drop table mail_user_outbox; + +IF OBJECT_ID('map_super_actual', 'U') IS NOT NULL drop table map_super_actual; +IF OBJECT_ID('map_super_actual_seq', 'SO') IS NOT NULL drop sequence map_super_actual_seq; + +IF OBJECT_ID('c_message', 'U') IS NOT NULL drop table c_message; +IF OBJECT_ID('c_message_seq', 'SO') IS NOT NULL drop sequence c_message_seq; + +IF OBJECT_ID('mnoc_role', 'U') IS NOT NULL drop table mnoc_role; +IF OBJECT_ID('mnoc_role_seq', 'SO') IS NOT NULL drop sequence mnoc_role_seq; + +IF OBJECT_ID('mnoc_user', 'U') IS NOT NULL drop table mnoc_user; +IF OBJECT_ID('mnoc_user_seq', 'SO') IS NOT NULL drop sequence mnoc_user_seq; + +IF OBJECT_ID('mnoc_user_mnoc_role', 'U') IS NOT NULL drop table mnoc_user_mnoc_role; + +IF OBJECT_ID('mny_a', 'U') IS NOT NULL drop table mny_a; +IF OBJECT_ID('mny_a_seq', 'SO') IS NOT NULL drop sequence mny_a_seq; + +IF OBJECT_ID('mny_b', 'U') IS NOT NULL drop table mny_b; +IF OBJECT_ID('mny_b_seq', 'SO') IS NOT NULL drop sequence mny_b_seq; + +IF OBJECT_ID('mny_b_mny_c', 'U') IS NOT NULL drop table mny_b_mny_c; + +IF OBJECT_ID('mny_c', 'U') IS NOT NULL drop table mny_c; +IF OBJECT_ID('mny_c_seq', 'SO') IS NOT NULL drop sequence mny_c_seq; + +IF OBJECT_ID('mny_topic', 'U') IS NOT NULL drop table mny_topic; +IF OBJECT_ID('mny_topic_seq', 'SO') IS NOT NULL drop sequence mny_topic_seq; + +IF OBJECT_ID('subtopics', 'U') IS NOT NULL drop table subtopics; + +IF OBJECT_ID('mp_role', 'U') IS NOT NULL drop table mp_role; +IF OBJECT_ID('mp_role_seq', 'SO') IS NOT NULL drop sequence mp_role_seq; + +IF OBJECT_ID('mp_user', 'U') IS NOT NULL drop table mp_user; +IF OBJECT_ID('mp_user_seq', 'SO') IS NOT NULL drop sequence mp_user_seq; + +IF OBJECT_ID('ms_many_a', 'U') IS NOT NULL drop table ms_many_a; +IF OBJECT_ID('ms_many_a_seq', 'SO') IS NOT NULL drop sequence ms_many_a_seq; + +IF OBJECT_ID('ms_many_a_many_b', 'U') IS NOT NULL drop table ms_many_a_many_b; + +IF OBJECT_ID('ms_many_b', 'U') IS NOT NULL drop table ms_many_b; +IF OBJECT_ID('ms_many_b_seq', 'SO') IS NOT NULL drop sequence ms_many_b_seq; + +IF OBJECT_ID('ms_many_b_many_a', 'U') IS NOT NULL drop table ms_many_b_many_a; + +IF OBJECT_ID('my_lob_size', 'U') IS NOT NULL drop table my_lob_size; +IF OBJECT_ID('my_lob_size_seq', 'SO') IS NOT NULL drop sequence my_lob_size_seq; + +IF OBJECT_ID('my_lob_size_join_many', 'U') IS NOT NULL drop table my_lob_size_join_many; +IF OBJECT_ID('my_lob_size_join_many_seq', 'SO') IS NOT NULL drop sequence my_lob_size_join_many_seq; + +IF OBJECT_ID('noidbean', 'U') IS NOT NULL drop table noidbean; + +IF OBJECT_ID('o_cached_bean', 'U') IS NOT NULL drop table o_cached_bean; +IF OBJECT_ID('o_cached_bean_seq', 'SO') IS NOT NULL drop sequence o_cached_bean_seq; + +IF OBJECT_ID('o_cached_bean_country', 'U') IS NOT NULL drop table o_cached_bean_country; + +IF OBJECT_ID('o_cached_bean_child', 'U') IS NOT NULL drop table o_cached_bean_child; +IF OBJECT_ID('o_cached_bean_child_seq', 'SO') IS NOT NULL drop sequence o_cached_bean_child_seq; + +IF OBJECT_ID('o_cached_natkey', 'U') IS NOT NULL drop table o_cached_natkey; +IF OBJECT_ID('o_cached_natkey_seq', 'SO') IS NOT NULL drop sequence o_cached_natkey_seq; + +IF OBJECT_ID('o_cached_natkey3', 'U') IS NOT NULL drop table o_cached_natkey3; +IF OBJECT_ID('o_cached_natkey3_seq', 'SO') IS NOT NULL drop sequence o_cached_natkey3_seq; + +IF OBJECT_ID('ocar', 'U') IS NOT NULL drop table ocar; +IF OBJECT_ID('ocar_seq', 'SO') IS NOT NULL drop sequence ocar_seq; + +IF OBJECT_ID('ocompany', 'U') IS NOT NULL drop table ocompany; +IF OBJECT_ID('ocompany_seq', 'SO') IS NOT NULL drop sequence ocompany_seq; + +IF OBJECT_ID('oengine', 'U') IS NOT NULL drop table oengine; + +IF OBJECT_ID('ogear_box', 'U') IS NOT NULL drop table ogear_box; + +IF OBJECT_ID('oroad_show_msg', 'U') IS NOT NULL drop table oroad_show_msg; +IF OBJECT_ID('oroad_show_msg_seq', 'SO') IS NOT NULL drop sequence oroad_show_msg_seq; + +IF OBJECT_ID('om_ordered_detail', 'U') IS NOT NULL drop table om_ordered_detail; +IF OBJECT_ID('om_ordered_detail_seq', 'SO') IS NOT NULL drop sequence om_ordered_detail_seq; + +IF OBJECT_ID('om_ordered_master', 'U') IS NOT NULL drop table om_ordered_master; +IF OBJECT_ID('om_ordered_master_seq', 'SO') IS NOT NULL drop sequence om_ordered_master_seq; + +IF OBJECT_ID('o_order', 'U') IS NOT NULL drop table o_order; +IF OBJECT_ID('o_order_seq', 'SO') IS NOT NULL drop sequence o_order_seq; + +IF OBJECT_ID('o_order_detail', 'U') IS NOT NULL drop table o_order_detail; +IF OBJECT_ID('o_order_detail_seq', 'SO') IS NOT NULL drop sequence o_order_detail_seq; + +IF OBJECT_ID('s_orders', 'U') IS NOT NULL drop table s_orders; + +IF OBJECT_ID('s_order_items', 'U') IS NOT NULL drop table s_order_items; + +IF OBJECT_ID('or_order_ship', 'U') IS NOT NULL drop table or_order_ship; +IF OBJECT_ID('or_order_ship_seq', 'SO') IS NOT NULL drop sequence or_order_ship_seq; + +IF OBJECT_ID('organisation', 'U') IS NOT NULL drop table organisation; +IF OBJECT_ID('organisation_seq', 'SO') IS NOT NULL drop sequence organisation_seq; + +IF OBJECT_ID('oto_bchild', 'U') IS NOT NULL drop table oto_bchild; +IF OBJECT_ID('oto_bchild_seq', 'SO') IS NOT NULL drop sequence oto_bchild_seq; + +IF OBJECT_ID('oto_bmaster', 'U') IS NOT NULL drop table oto_bmaster; +IF OBJECT_ID('oto_bmaster_seq', 'SO') IS NOT NULL drop sequence oto_bmaster_seq; + +IF OBJECT_ID('oto_child', 'U') IS NOT NULL drop table oto_child; +IF OBJECT_ID('oto_child_seq', 'SO') IS NOT NULL drop sequence oto_child_seq; + +IF OBJECT_ID('oto_cust', 'U') IS NOT NULL drop table oto_cust; +IF OBJECT_ID('oto_cust_seq', 'SO') IS NOT NULL drop sequence oto_cust_seq; + +IF OBJECT_ID('oto_cust_address', 'U') IS NOT NULL drop table oto_cust_address; +IF OBJECT_ID('oto_cust_address_seq', 'SO') IS NOT NULL drop sequence oto_cust_address_seq; + +IF OBJECT_ID('oto_master', 'U') IS NOT NULL drop table oto_master; +IF OBJECT_ID('oto_master_seq', 'SO') IS NOT NULL drop sequence oto_master_seq; + +IF OBJECT_ID('oto_prime', 'U') IS NOT NULL drop table oto_prime; +IF OBJECT_ID('oto_prime_seq', 'SO') IS NOT NULL drop sequence oto_prime_seq; + +IF OBJECT_ID('oto_prime_extra', 'U') IS NOT NULL drop table oto_prime_extra; + +IF OBJECT_ID('oto_th_many', 'U') IS NOT NULL drop table oto_th_many; +IF OBJECT_ID('oto_th_many_seq', 'SO') IS NOT NULL drop sequence oto_th_many_seq; + +IF OBJECT_ID('oto_th_one', 'U') IS NOT NULL drop table oto_th_one; +IF OBJECT_ID('oto_th_one_seq', 'SO') IS NOT NULL drop sequence oto_th_one_seq; + +IF OBJECT_ID('oto_th_top', 'U') IS NOT NULL drop table oto_th_top; +IF OBJECT_ID('oto_th_top_seq', 'SO') IS NOT NULL drop sequence oto_th_top_seq; + +IF OBJECT_ID('oto_ubprime', 'U') IS NOT NULL drop table oto_ubprime; + +IF OBJECT_ID('oto_ubprime_extra', 'U') IS NOT NULL drop table oto_ubprime_extra; + +IF OBJECT_ID('oto_uprime', 'U') IS NOT NULL drop table oto_uprime; + +IF OBJECT_ID('oto_uprime_extra', 'U') IS NOT NULL drop table oto_uprime_extra; + +IF OBJECT_ID('pfile', 'U') IS NOT NULL drop table pfile; +IF OBJECT_ID('pfile_seq', 'SO') IS NOT NULL drop sequence pfile_seq; + +IF OBJECT_ID('pfile_content', 'U') IS NOT NULL drop table pfile_content; +IF OBJECT_ID('pfile_content_seq', 'SO') IS NOT NULL drop sequence pfile_content_seq; + +IF OBJECT_ID('paggview', 'U') IS NOT NULL drop table paggview; + +IF OBJECT_ID('pallet_location', 'U') IS NOT NULL drop table pallet_location; +IF OBJECT_ID('pallet_location_seq', 'SO') IS NOT NULL drop sequence pallet_location_seq; + +IF OBJECT_ID('parcel', 'U') IS NOT NULL drop table parcel; +IF OBJECT_ID('parcel_seq', 'SO') IS NOT NULL drop sequence parcel_seq; + +IF OBJECT_ID('parcel_location', 'U') IS NOT NULL drop table parcel_location; +IF OBJECT_ID('parcel_location_seq', 'SO') IS NOT NULL drop sequence parcel_location_seq; + +IF OBJECT_ID('rawinherit_parent', 'U') IS NOT NULL drop table rawinherit_parent; +IF OBJECT_ID('rawinherit_parent_seq', 'SO') IS NOT NULL drop sequence rawinherit_parent_seq; + +IF OBJECT_ID('rawinherit_parent_rawinherit_data', 'U') IS NOT NULL drop table rawinherit_parent_rawinherit_data; + +IF OBJECT_ID('parent_person', 'U') IS NOT NULL drop table parent_person; +IF OBJECT_ID('parent_person_seq', 'SO') IS NOT NULL drop sequence parent_person_seq; + +IF OBJECT_ID('c_participation', 'U') IS NOT NULL drop table c_participation; +IF OBJECT_ID('c_participation_seq', 'SO') IS NOT NULL drop sequence c_participation_seq; + +IF OBJECT_ID('mt_permission', 'U') IS NOT NULL drop table mt_permission; + +IF OBJECT_ID('persistent_file', 'U') IS NOT NULL drop table persistent_file; +IF OBJECT_ID('persistent_file_seq', 'SO') IS NOT NULL drop sequence persistent_file_seq; + +IF OBJECT_ID('persistent_file_content', 'U') IS NOT NULL drop table persistent_file_content; +IF OBJECT_ID('persistent_file_content_seq', 'SO') IS NOT NULL drop sequence persistent_file_content_seq; + +IF OBJECT_ID('persons', 'U') IS NOT NULL drop table persons; +IF OBJECT_ID('PERSONS_seq', 'SO') IS NOT NULL drop sequence PERSONS_seq; + +IF OBJECT_ID('person', 'U') IS NOT NULL drop table person; +IF OBJECT_ID('person_seq', 'SO') IS NOT NULL drop sequence person_seq; + +IF OBJECT_ID('phones', 'U') IS NOT NULL drop table phones; +IF OBJECT_ID('PHONES_seq', 'SO') IS NOT NULL drop sequence PHONES_seq; + +IF OBJECT_ID('primary_revision', 'U') IS NOT NULL drop table primary_revision; + +IF OBJECT_ID('o_product', 'U') IS NOT NULL drop table o_product; +IF OBJECT_ID('o_product_seq', 'SO') IS NOT NULL drop sequence o_product_seq; + +IF OBJECT_ID('pp', 'U') IS NOT NULL drop table pp; + +IF OBJECT_ID('pp_to_ww', 'U') IS NOT NULL drop table pp_to_ww; + +IF OBJECT_ID('question', 'U') IS NOT NULL drop table question; +IF OBJECT_ID('question_seq', 'SO') IS NOT NULL drop sequence question_seq; + +IF OBJECT_ID('rcustomer', 'U') IS NOT NULL drop table rcustomer; + +IF OBJECT_ID('r_orders', 'U') IS NOT NULL drop table r_orders; + +IF OBJECT_ID('region', 'U') IS NOT NULL drop table region; + +IF OBJECT_ID('resourcefile', 'U') IS NOT NULL drop table resourcefile; + +IF OBJECT_ID('em_role', 'U') IS NOT NULL drop table em_role; +IF OBJECT_ID('em_role_seq', 'SO') IS NOT NULL drop sequence em_role_seq; + +IF OBJECT_ID('mt_role', 'U') IS NOT NULL drop table mt_role; + +IF OBJECT_ID('mt_role_permission', 'U') IS NOT NULL drop table mt_role_permission; + +IF OBJECT_ID('f_second', 'U') IS NOT NULL drop table f_second; +IF OBJECT_ID('f_second_seq', 'SO') IS NOT NULL drop sequence f_second_seq; + +IF OBJECT_ID('section', 'U') IS NOT NULL drop table section; +IF OBJECT_ID('section_seq', 'SO') IS NOT NULL drop sequence section_seq; + +IF OBJECT_ID('self_parent', 'U') IS NOT NULL drop table self_parent; +IF OBJECT_ID('self_parent_seq', 'SO') IS NOT NULL drop sequence self_parent_seq; + +IF OBJECT_ID('self_ref_customer', 'U') IS NOT NULL drop table self_ref_customer; +IF OBJECT_ID('self_ref_customer_seq', 'SO') IS NOT NULL drop sequence self_ref_customer_seq; + +IF OBJECT_ID('self_ref_example', 'U') IS NOT NULL drop table self_ref_example; +IF OBJECT_ID('self_ref_example_seq', 'SO') IS NOT NULL drop sequence self_ref_example_seq; + +IF OBJECT_ID('some_enum_bean', 'U') IS NOT NULL drop table some_enum_bean; +IF OBJECT_ID('some_enum_bean_seq', 'SO') IS NOT NULL drop sequence some_enum_bean_seq; + +IF OBJECT_ID('some_file_bean', 'U') IS NOT NULL drop table some_file_bean; +IF OBJECT_ID('some_file_bean_seq', 'SO') IS NOT NULL drop sequence some_file_bean_seq; + +IF OBJECT_ID('some_new_types_bean', 'U') IS NOT NULL drop table some_new_types_bean; +IF OBJECT_ID('some_new_types_bean_seq', 'SO') IS NOT NULL drop sequence some_new_types_bean_seq; + +IF OBJECT_ID('some_period_bean', 'U') IS NOT NULL drop table some_period_bean; +IF OBJECT_ID('some_period_bean_seq', 'SO') IS NOT NULL drop sequence some_period_bean_seq; + +IF OBJECT_ID('stockforecast', 'U') IS NOT NULL drop table stockforecast; +IF OBJECT_ID('stockforecast_seq', 'SO') IS NOT NULL drop sequence stockforecast_seq; + +IF OBJECT_ID('sub_section', 'U') IS NOT NULL drop table sub_section; +IF OBJECT_ID('sub_section_seq', 'SO') IS NOT NULL drop sequence sub_section_seq; + +IF OBJECT_ID('sub_type', 'U') IS NOT NULL drop table sub_type; +IF OBJECT_ID('sub_type_seq', 'SO') IS NOT NULL drop sequence sub_type_seq; + +IF OBJECT_ID('survey', 'U') IS NOT NULL drop table survey; +IF OBJECT_ID('survey_seq', 'SO') IS NOT NULL drop sequence survey_seq; + +IF OBJECT_ID('tbytes_only', 'U') IS NOT NULL drop table tbytes_only; +IF OBJECT_ID('tbytes_only_seq', 'SO') IS NOT NULL drop sequence tbytes_only_seq; + +IF OBJECT_ID('tcar', 'U') IS NOT NULL drop table tcar; + +IF OBJECT_ID('tevent', 'U') IS NOT NULL drop table tevent; +IF OBJECT_ID('tevent_seq', 'SO') IS NOT NULL drop sequence tevent_seq; + +IF OBJECT_ID('tevent_many', 'U') IS NOT NULL drop table tevent_many; +IF OBJECT_ID('tevent_many_seq', 'SO') IS NOT NULL drop sequence tevent_many_seq; + +IF OBJECT_ID('tevent_one', 'U') IS NOT NULL drop table tevent_one; +IF OBJECT_ID('tevent_one_seq', 'SO') IS NOT NULL drop sequence tevent_one_seq; + +IF OBJECT_ID('tint_root', 'U') IS NOT NULL drop table tint_root; +IF OBJECT_ID('tint_root_seq', 'SO') IS NOT NULL drop sequence tint_root_seq; + +IF OBJECT_ID('tjoda_entity', 'U') IS NOT NULL drop table tjoda_entity; +IF OBJECT_ID('tjoda_entity_seq', 'SO') IS NOT NULL drop sequence tjoda_entity_seq; + +IF OBJECT_ID('t_mapsuper1', 'U') IS NOT NULL drop table t_mapsuper1; +IF OBJECT_ID('t_mapsuper1_seq', 'SO') IS NOT NULL drop sequence t_mapsuper1_seq; + +IF OBJECT_ID('t_oneb', 'U') IS NOT NULL drop table t_oneb; +IF OBJECT_ID('t_oneb_seq', 'SO') IS NOT NULL drop sequence t_oneb_seq; + +IF OBJECT_ID('t_detail_with_other_namexxxyy', 'U') IS NOT NULL drop table t_detail_with_other_namexxxyy; +IF OBJECT_ID('t_atable_detail_seq', 'SO') IS NOT NULL drop sequence t_atable_detail_seq; + +IF OBJECT_ID('ts_detail_two', 'U') IS NOT NULL drop table ts_detail_two; +IF OBJECT_ID('ts_detail_two_seq', 'SO') IS NOT NULL drop sequence ts_detail_two_seq; + +IF OBJECT_ID('t_atable_thatisrelatively', 'U') IS NOT NULL drop table t_atable_thatisrelatively; +IF OBJECT_ID('t_atable_master_seq', 'SO') IS NOT NULL drop sequence t_atable_master_seq; + +IF OBJECT_ID('ts_master_two', 'U') IS NOT NULL drop table ts_master_two; +IF OBJECT_ID('ts_master_two_seq', 'SO') IS NOT NULL drop sequence ts_master_two_seq; + +IF OBJECT_ID('tuuid_entity', 'U') IS NOT NULL drop table tuuid_entity; + +IF OBJECT_ID('twheel', 'U') IS NOT NULL drop table twheel; +IF OBJECT_ID('twheel_seq', 'SO') IS NOT NULL drop sequence twheel_seq; + +IF OBJECT_ID('twith_pre_insert', 'U') IS NOT NULL drop table twith_pre_insert; +IF OBJECT_ID('twith_pre_insert_seq', 'SO') IS NOT NULL drop sequence twith_pre_insert_seq; + +IF OBJECT_ID('mt_tenant', 'U') IS NOT NULL drop table mt_tenant; + +IF OBJECT_ID('test_annotation_base_entity', 'U') IS NOT NULL drop table test_annotation_base_entity; + +IF OBJECT_ID('tire', 'U') IS NOT NULL drop table tire; +IF OBJECT_ID('tire_seq', 'SO') IS NOT NULL drop sequence tire_seq; + +IF OBJECT_ID('sa_tire', 'U') IS NOT NULL drop table sa_tire; +IF OBJECT_ID('sa_tire_seq', 'SO') IS NOT NULL drop sequence sa_tire_seq; + +IF OBJECT_ID('trip', 'U') IS NOT NULL drop table trip; +IF OBJECT_ID('trip_seq', 'SO') IS NOT NULL drop sequence trip_seq; + +IF OBJECT_ID('truck_ref', 'U') IS NOT NULL drop table truck_ref; +IF OBJECT_ID('truck_ref_seq', 'SO') IS NOT NULL drop sequence truck_ref_seq; + +IF OBJECT_ID('type', 'U') IS NOT NULL drop table type; + +IF OBJECT_ID('tz_bean', 'U') IS NOT NULL drop table tz_bean; +IF OBJECT_ID('tz_bean_seq', 'SO') IS NOT NULL drop sequence tz_bean_seq; + +IF OBJECT_ID('ut_detail', 'U') IS NOT NULL drop table ut_detail; +IF OBJECT_ID('ut_detail_seq', 'SO') IS NOT NULL drop sequence ut_detail_seq; + +IF OBJECT_ID('ut_master', 'U') IS NOT NULL drop table ut_master; +IF OBJECT_ID('ut_master_seq', 'SO') IS NOT NULL drop sequence ut_master_seq; + +IF OBJECT_ID('uuone', 'U') IS NOT NULL drop table uuone; + +IF OBJECT_ID('uutwo', 'U') IS NOT NULL drop table uutwo; + +IF OBJECT_ID('c_user', 'U') IS NOT NULL alter table c_user set (system_versioning = off); +IF OBJECT_ID('c_user_history', 'U') IS NOT NULL drop table c_user_history; +IF OBJECT_ID('c_user', 'U') IS NOT NULL drop table c_user; +IF OBJECT_ID('c_user_seq', 'SO') IS NOT NULL drop sequence c_user_seq; + +IF OBJECT_ID('tx_user', 'U') IS NOT NULL drop table tx_user; +IF OBJECT_ID('tx_user_seq', 'SO') IS NOT NULL drop sequence tx_user_seq; + +IF OBJECT_ID('g_user', 'U') IS NOT NULL drop table g_user; +IF OBJECT_ID('g_user_seq', 'SO') IS NOT NULL drop sequence g_user_seq; + +IF OBJECT_ID('em_user', 'U') IS NOT NULL drop table em_user; +IF OBJECT_ID('em_user_seq', 'SO') IS NOT NULL drop sequence em_user_seq; + +IF OBJECT_ID('oto_user', 'U') IS NOT NULL drop table oto_user; +IF OBJECT_ID('oto_user_seq', 'SO') IS NOT NULL drop sequence oto_user_seq; + +IF OBJECT_ID('em_user_role', 'U') IS NOT NULL drop table em_user_role; + +IF OBJECT_ID('vehicle', 'U') IS NOT NULL drop table vehicle; +IF OBJECT_ID('vehicle_seq', 'SO') IS NOT NULL drop sequence vehicle_seq; + +IF OBJECT_ID('vehicle_driver', 'U') IS NOT NULL drop table vehicle_driver; +IF OBJECT_ID('vehicle_driver_seq', 'SO') IS NOT NULL drop sequence vehicle_driver_seq; + +IF OBJECT_ID('warehouses', 'U') IS NOT NULL drop table warehouses; +IF OBJECT_ID('warehouses_seq', 'SO') IS NOT NULL drop sequence warehouses_seq; + +IF OBJECT_ID('warehousesshippingzones', 'U') IS NOT NULL drop table warehousesshippingzones; + +IF OBJECT_ID('sa_wheel', 'U') IS NOT NULL drop table sa_wheel; +IF OBJECT_ID('sa_wheel_seq', 'SO') IS NOT NULL drop sequence sa_wheel_seq; + +IF OBJECT_ID('wheel', 'U') IS NOT NULL drop table wheel; +IF OBJECT_ID('wheel_seq', 'SO') IS NOT NULL drop sequence wheel_seq; + +IF OBJECT_ID('sp_car_wheel', 'U') IS NOT NULL drop table sp_car_wheel; +IF OBJECT_ID('sp_car_wheel_seq', 'SO') IS NOT NULL drop sequence sp_car_wheel_seq; + +IF OBJECT_ID('g_who_props_otm', 'U') IS NOT NULL drop table g_who_props_otm; +IF OBJECT_ID('g_who_props_otm_seq', 'SO') IS NOT NULL drop sequence g_who_props_otm_seq; + +IF OBJECT_ID('with_zero', 'U') IS NOT NULL drop table with_zero; +IF OBJECT_ID('with_zero_seq', 'SO') IS NOT NULL drop sequence with_zero_seq; + +IF OBJECT_ID('parent', 'U') IS NOT NULL drop table parent; +IF OBJECT_ID('parent_seq', 'SO') IS NOT NULL drop sequence parent_seq; + +IF OBJECT_ID('wview', 'U') IS NOT NULL drop table wview; + +IF OBJECT_ID('zones', 'U') IS NOT NULL drop table zones; +IF OBJECT_ID('zones_seq', 'SO') IS NOT NULL drop sequence zones_seq; + +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('contact','U') AND name = 'ix_contact_last_name_first_name') drop index ix_contact_last_name_first_name ON contact; +IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('e_basic','U') AND name = 'ix_e_basic_name') drop index ix_e_basic_name ON e_basic; From 2f349ff054cc85ed2f083cbc859abae88bd33160 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 19:37:30 +1300 Subject: [PATCH 0170/1036] #1318 No effective change - DDL review for ... ENH: native UUID-support for SqlServer Shows the use of uniqueidentifier DB column type for UUID with sql server. --- src/test/ddl-review/sqlserver-create-all.sql | 62 ++++++++++---------- src/test/ddl-review/sqlserver-drop-all.sql | 2 +- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/test/ddl-review/sqlserver-create-all.sql b/src/test/ddl-review/sqlserver-create-all.sql index de66ddd39..166eb009d 100644 --- a/src/test/ddl-review/sqlserver-create-all.sql +++ b/src/test/ddl-review/sqlserver-create-all.sql @@ -1,4 +1,4 @@ --- Generated by ebean unknown at 2018-03-08T04:43:42.126Z +-- Generated by ebean unknown at 2018-03-08T06:24:28.188Z create table asimple_bean ( id numeric(19) not null, name nvarchar(255), @@ -155,37 +155,37 @@ create table bsimple_with_gen ( create sequence bsimple_with_gen_seq as bigint start with 1 increment by 50; create table bsite ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_bsite primary key (id) ); create table bsite_user ( - site_id nvarchar(40) not null, - user_id nvarchar(40) not null, + site_id uniqueidentifier not null, + user_id uniqueidentifier not null, access_level integer, constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), constraint pk_bsite_user primary key (site_id,user_id) ); create table bsite_user_b ( - site nvarchar(40) not null, - usr nvarchar(40) not null, + site uniqueidentifier not null, + usr uniqueidentifier not null, access_level integer, constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), constraint pk_bsite_user_b primary key (site,usr) ); create table bsite_user_c ( - site_uid nvarchar(40) not null, - user_uid nvarchar(40) not null, + site_uid uniqueidentifier not null, + user_uid uniqueidentifier not null, access_level integer, constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), constraint pk_bsite_user_c primary key (site_uid,user_uid) ); create table buser ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_buser primary key (id) ); @@ -1454,7 +1454,7 @@ create sequence imroot_seq as bigint start with 1 increment by 50; create table ixresource ( dtype nvarchar(255), - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_ixresource primary key (id) ); @@ -2013,7 +2013,7 @@ create unique nonclustered index uq_ocompany_corp_id on ocompany(corp_id) where create sequence ocompany_seq as bigint start with 1 increment by 50; create table oengine ( - engine_id nvarchar(40) not null, + engine_id uniqueidentifier not null, short_desc nvarchar(255), car_id integer, version integer not null, @@ -2022,7 +2022,7 @@ create table oengine ( create unique nonclustered index uq_oengine_car_id on oengine(car_id) where car_id is not null; create table ogear_box ( - id nvarchar(40) not null, + id uniqueidentifier not null, box_desc nvarchar(255), box_size integer, car_id integer, @@ -2220,28 +2220,28 @@ create table oto_th_top ( create sequence oto_th_top_seq as bigint start with 1 increment by 50; create table oto_ubprime ( - pid nvarchar(40) not null, + pid uniqueidentifier not null, name nvarchar(255), version numeric(19) not null, constraint pk_oto_ubprime primary key (pid) ); create table oto_ubprime_extra ( - eid nvarchar(40) not null, + eid uniqueidentifier not null, extra nvarchar(255), version numeric(19) not null, constraint pk_oto_ubprime_extra primary key (eid) ); create table oto_uprime ( - pid nvarchar(40) not null, + pid uniqueidentifier not null, name nvarchar(255), version numeric(19) not null, constraint pk_oto_uprime primary key (pid) ); create table oto_uprime_extra ( - eid nvarchar(40) not null, + eid uniqueidentifier not null, extra nvarchar(255), version numeric(19) not null, constraint pk_oto_uprime_extra primary key (eid) @@ -2272,7 +2272,7 @@ create table pfile_content ( create sequence pfile_content_seq as bigint start with 1 increment by 50; create table paggview ( - pview_id nvarchar(40), + pview_id uniqueidentifier, amount integer not null ); create unique nonclustered index uq_paggview_pview_id on paggview(pview_id) where pview_id is not null; @@ -2344,7 +2344,7 @@ create table c_participation ( create sequence c_participation_seq as bigint start with 1 increment by 50; create table mt_permission ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_mt_permission primary key (id) ); @@ -2415,15 +2415,15 @@ create table o_product ( create sequence o_product_seq as bigint start with 1 increment by 50; create table pp ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), value nvarchar(100) not null, constraint pk_pp primary key (id) ); create table pp_to_ww ( - pp_id nvarchar(40) not null, - ww_id nvarchar(40) not null, + pp_id uniqueidentifier not null, + ww_id uniqueidentifier not null, constraint pk_pp_to_ww primary key (pp_id,ww_id) ); @@ -2474,16 +2474,16 @@ create table em_role ( create sequence em_role_seq as bigint start with 1 increment by 50; create table mt_role ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(50), - tenant_id nvarchar(40), + tenant_id uniqueidentifier, version numeric(19) not null, constraint pk_mt_role primary key (id) ); create table mt_role_permission ( - mt_role_id nvarchar(40) not null, - mt_permission_id nvarchar(40) not null, + mt_role_id uniqueidentifier not null, + mt_permission_id uniqueidentifier not null, constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) ); @@ -2737,7 +2737,7 @@ create table ts_master_two ( create sequence ts_master_two_seq as bigint start with 1 increment by 50; create table tuuid_entity ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_tuuid_entity primary key (id) ); @@ -2758,7 +2758,7 @@ create table twith_pre_insert ( create sequence twith_pre_insert_seq as bigint start with 1 increment by 50; create table mt_tenant ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), version numeric(19) not null, constraint pk_mt_tenant primary key (id) @@ -2849,15 +2849,15 @@ create table ut_master ( create sequence ut_master_seq as bigint start with 1 increment by 50; create table uuone ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), constraint pk_uuone primary key (id) ); create table uutwo ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(255), - master_id nvarchar(40), + master_id uniqueidentifier, constraint pk_uutwo primary key (id) ); @@ -3013,7 +3013,7 @@ create table parent ( create sequence parent_seq as bigint start with 1 increment by 50; create table wview ( - id nvarchar(40) not null, + id uniqueidentifier not null, name nvarchar(127) not null, constraint uq_wview_name unique (name), constraint pk_wview primary key (id) diff --git a/src/test/ddl-review/sqlserver-drop-all.sql b/src/test/ddl-review/sqlserver-drop-all.sql index 1669d09c8..15e5b3bf9 100644 --- a/src/test/ddl-review/sqlserver-drop-all.sql +++ b/src/test/ddl-review/sqlserver-drop-all.sql @@ -1,4 +1,4 @@ --- Generated by ebean unknown at 2018-03-08T04:43:42.126Z +-- Generated by ebean unknown at 2018-03-08T06:24:28.188Z IF OBJECT_ID('fk_bar_foo_id', 'F') IS NOT NULL alter table bar drop constraint fk_bar_foo_id; IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('bar','U') AND name = 'ix_bar_foo_id') drop index ix_bar_foo_id ON bar; From 2520837f5e9e1e3c9f7c9d87f001b0f477039d46 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 20:42:36 +1300 Subject: [PATCH 0171/1036] No effective change - Test on rename of DDL review files for oracle --- src/test/ddl-review/{ora-create.sql => oracle-create.sql} | 0 src/test/ddl-review/{ora-drop.sql => oracle-drop.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ddl-review/{ora-create.sql => oracle-create.sql} (100%) rename src/test/ddl-review/{ora-drop.sql => oracle-drop.sql} (100%) diff --git a/src/test/ddl-review/ora-create.sql b/src/test/ddl-review/oracle-create.sql similarity index 100% rename from src/test/ddl-review/ora-create.sql rename to src/test/ddl-review/oracle-create.sql diff --git a/src/test/ddl-review/ora-drop.sql b/src/test/ddl-review/oracle-drop.sql similarity index 100% rename from src/test/ddl-review/ora-drop.sql rename to src/test/ddl-review/oracle-drop.sql From 93d659050b066c181ce35588a58407378affe56e Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 20:44:15 +1300 Subject: [PATCH 0172/1036] No effective change - Test on rename of DDL review files --- src/test/ddl-review/{h2-create.sql => h2-create-all.sql} | 0 src/test/ddl-review/{h2-drop.sql => h2-drop-all.sql} | 0 src/test/ddl-review/{mysql-create.sql => mysql-create-all.sql} | 0 src/test/ddl-review/{mysql-drop.sql => mysql-drop-all.sql} | 0 src/test/ddl-review/{oracle-create.sql => oracle-create-all.sql} | 0 src/test/ddl-review/{oracle-drop.sql => oracle-drop-all.sql} | 0 src/test/ddl-review/{pg-create.sql => pg-create-all.sql} | 0 src/test/ddl-review/{pg-drop.sql => pg-drop-all.sql} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ddl-review/{h2-create.sql => h2-create-all.sql} (100%) rename src/test/ddl-review/{h2-drop.sql => h2-drop-all.sql} (100%) rename src/test/ddl-review/{mysql-create.sql => mysql-create-all.sql} (100%) rename src/test/ddl-review/{mysql-drop.sql => mysql-drop-all.sql} (100%) rename src/test/ddl-review/{oracle-create.sql => oracle-create-all.sql} (100%) rename src/test/ddl-review/{oracle-drop.sql => oracle-drop-all.sql} (100%) rename src/test/ddl-review/{pg-create.sql => pg-create-all.sql} (100%) rename src/test/ddl-review/{pg-drop.sql => pg-drop-all.sql} (100%) diff --git a/src/test/ddl-review/h2-create.sql b/src/test/ddl-review/h2-create-all.sql similarity index 100% rename from src/test/ddl-review/h2-create.sql rename to src/test/ddl-review/h2-create-all.sql diff --git a/src/test/ddl-review/h2-drop.sql b/src/test/ddl-review/h2-drop-all.sql similarity index 100% rename from src/test/ddl-review/h2-drop.sql rename to src/test/ddl-review/h2-drop-all.sql diff --git a/src/test/ddl-review/mysql-create.sql b/src/test/ddl-review/mysql-create-all.sql similarity index 100% rename from src/test/ddl-review/mysql-create.sql rename to src/test/ddl-review/mysql-create-all.sql diff --git a/src/test/ddl-review/mysql-drop.sql b/src/test/ddl-review/mysql-drop-all.sql similarity index 100% rename from src/test/ddl-review/mysql-drop.sql rename to src/test/ddl-review/mysql-drop-all.sql diff --git a/src/test/ddl-review/oracle-create.sql b/src/test/ddl-review/oracle-create-all.sql similarity index 100% rename from src/test/ddl-review/oracle-create.sql rename to src/test/ddl-review/oracle-create-all.sql diff --git a/src/test/ddl-review/oracle-drop.sql b/src/test/ddl-review/oracle-drop-all.sql similarity index 100% rename from src/test/ddl-review/oracle-drop.sql rename to src/test/ddl-review/oracle-drop-all.sql diff --git a/src/test/ddl-review/pg-create.sql b/src/test/ddl-review/pg-create-all.sql similarity index 100% rename from src/test/ddl-review/pg-create.sql rename to src/test/ddl-review/pg-create-all.sql diff --git a/src/test/ddl-review/pg-drop.sql b/src/test/ddl-review/pg-drop-all.sql similarity index 100% rename from src/test/ddl-review/pg-drop.sql rename to src/test/ddl-review/pg-drop-all.sql From fbc2ba3912f6ca1978c7d00d99670e179c94f840 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 20:47:28 +1300 Subject: [PATCH 0173/1036] No effective change - Test update DDL review files --- src/test/ddl-review/h2-create-all.sql | 2672 +++++++++++++++------ src/test/ddl-review/h2-drop-all.sql | 1146 +++++---- src/test/ddl-review/mysql-create-all.sql | 1846 ++++++++++++-- src/test/ddl-review/mysql-drop-all.sql | 604 ++++- src/test/ddl-review/oracle-create-all.sql | 1780 ++++++++++++-- src/test/ddl-review/oracle-drop-all.sql | 770 +++++- src/test/ddl-review/pg-create-all.sql | 2120 +++++++++++++--- src/test/ddl-review/pg-drop-all.sql | 976 ++++++-- 8 files changed, 9575 insertions(+), 2339 deletions(-) diff --git a/src/test/ddl-review/h2-create-all.sql b/src/test/ddl-review/h2-create-all.sql index af29ea19d..207d6b517 100644 --- a/src/test/ddl-review/h2-create-all.sql +++ b/src/test/ddl-review/h2-create-all.sql @@ -1,186 +1,242 @@ +-- Generated by ebean unknown at 2018-03-08T06:41:41.155Z create table asimple_bean ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_asimple_bean primary key (id) ); -create sequence asimple_bean_seq; create table bar ( bar_type varchar(31) not null, - bar_id integer not null, + bar_id integer auto_increment not null, foo_id integer not null, version integer not null, constraint pk_bar primary key (bar_id) ); -create sequence bar_seq; create table oto_account ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, constraint pk_oto_account primary key (id) ); -create sequence oto_account_seq; -create table o_address ( - id smallint not null, - line_1 varchar(100), - line_2 varchar(100), - city varchar(100), - cretime timestamp, - country_code varchar(2), - updtime timestamp not null, - constraint pk_o_address primary key (id) +create table addr ( + id bigint auto_increment not null, + employee_id bigint, + name varchar(255), + address_line1 varchar(255), + address_line2 varchar(255), + city varchar(255), + version bigint not null, + constraint pk_addr primary key (id) ); -create sequence o_address_seq; create table address ( - oid bigint not null, + oid bigint auto_increment not null, street varchar(255), version integer not null, constraint pk_address primary key (oid) ); -create sequence address_seq; -create table animals ( - species varchar(31) not null, - id bigint not null, +create table o_address ( + id smallint auto_increment not null, + line_1 varchar(100), + line_2 varchar(100), + city varchar(100), + cretime datetime(6), + country_code varchar(2), + updtime datetime(6) not null, + constraint pk_o_address primary key (id) +); + +create table album ( + id bigint auto_increment not null, + name varchar(255), + cover_id bigint, + deleted tinyint(1) default 0 not null, + created_at datetime(6) not null, + last_update datetime(6) not null, + constraint uq_album_cover_id unique (cover_id), + constraint pk_album primary key (id) +); + +create table animal ( + species varchar(255) not null, + id bigint auto_increment not null, shelter_id bigint, version bigint not null, name varchar(255), registration_number varchar(255), date_of_birth date, - constraint pk_animals primary key (id) + dog_size varchar(255), + constraint pk_animal primary key (id) ); -create sequence animals_seq; create table animal_shelter ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), version bigint not null, constraint pk_animal_shelter primary key (id) ); -create sequence animal_shelter_seq; create table article ( - id integer not null, + id integer auto_increment not null, name varchar(255), author varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_article primary key (id) ); -create sequence article_seq; create table attribute ( option_type integer(31) not null, - id integer not null, + id integer auto_increment not null, attribute_holder_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_attribute primary key (id) ); -create sequence attribute_seq; create table attribute_holder ( - id integer not null, - cretime timestamp not null, - updtime timestamp not null, + id integer auto_increment not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_attribute_holder primary key (id) ); -create sequence attribute_holder_seq; create table audit_log ( - id bigint not null, + id bigint auto_increment not null, description varchar(255), modified_description varchar(255), constraint pk_audit_log primary key (id) ); -create sequence audit_log_seq; create table bbookmark ( - id integer not null, + id integer auto_increment not null, bookmark_reference varchar(255), user_id integer, constraint pk_bbookmark primary key (id) ); -create sequence bbookmark_seq; create table bbookmark_user ( - id integer not null, + id integer auto_increment not null, name varchar(255), password varchar(255), email_address varchar(255), country varchar(255), constraint pk_bbookmark_user primary key (id) ); -create sequence bbookmark_user_seq; create table bsimple_with_gen ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_bsimple_with_gen primary key (id) ); -create sequence bsimple_with_gen_seq; + +create table bsite ( + id varchar(40) not null, + name varchar(255), + constraint pk_bsite primary key (id) +); + +create table bsite_user ( + site_id varchar(40) not null, + user_id varchar(40) not null, + access_level integer, + constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user primary key (site_id,user_id) +); + +create table bsite_user_b ( + site varchar(40) not null, + usr varchar(40) not null, + access_level integer, + constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_b primary key (site,usr) +); + +create table bsite_user_c ( + site_uid varchar(40) not null, + user_uid varchar(40) not null, + access_level integer, + constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_c primary key (site_uid,user_uid) +); + +create table buser ( + id varchar(40) not null, + name varchar(255), + constraint pk_buser primary key (id) +); create table bwith_qident ( - id integer not null, - "Name" varchar(255), - last_updated timestamp not null, - constraint uq_bwith_qident_name unique ("Name"), + id integer auto_increment not null, + `Name` varchar(191), + last_updated datetime(6) not null, + constraint uq_bwith_qident_name unique (`Name`), constraint pk_bwith_qident primary key (id) ); -create sequence bwith_qident_seq; create table basic_joda_entity ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - created timestamp not null, - updated timestamp not null, - version timestamp not null, + period varchar(50), + created datetime(6) not null, + updated datetime(6) not null, + version datetime(6) not null, constraint pk_basic_joda_entity primary key (id) ); -create sequence basic_joda_entity_seq; create table bean_with_time_zone ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), timezone varchar(20), constraint pk_bean_with_time_zone primary key (id) ); -create sequence bean_with_time_zone_seq; create table drel_booking ( - id bigint not null, + id bigint auto_increment not null, + booking_uid bigint, agent_invoice bigint, client_invoice bigint, version integer not null, + constraint uq_drel_booking_booking_uid unique (booking_uid), constraint uq_drel_booking_agent_invoice unique (agent_invoice), constraint uq_drel_booking_client_invoice unique (client_invoice), constraint pk_drel_booking primary key (id) ); -create sequence drel_booking_seq; + +create table cinh_root ( + dtype varchar(3) not null, + id integer auto_increment not null, + license_number varchar(255), + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + driver varchar(255), + notes varchar(255), + action varchar(255), + constraint pk_cinh_root primary key (id) +); create table ckey_assoc ( - id integer not null, + id integer auto_increment not null, assoc_one varchar(255), constraint pk_ckey_assoc primary key (id) ); -create sequence ckey_assoc_seq; create table ckey_detail ( - id integer not null, + id integer auto_increment not null, something varchar(255), one_key integer, two_key varchar(127), constraint pk_ckey_detail primary key (id) ); -create sequence ckey_detail_seq; create table ckey_parent ( one_key integer not null, @@ -192,13 +248,12 @@ create table ckey_parent ( ); create table calculation_result ( - id integer not null, - charge double, + id integer auto_increment not null, + charge double not null, product_configuration_id integer, group_configuration_id integer, constraint pk_calculation_result primary key (id) ); -create sequence calculation_result_seq; create table cao_bean ( x_cust_id integer not null, @@ -209,18 +264,16 @@ create table cao_bean ( ); create table sa_car ( - id bigint not null, + id bigint auto_increment not null, version integer not null, constraint pk_sa_car primary key (id) ); -create sequence sa_car_seq; create table sp_car_car ( - id bigint not null, + id bigint auto_increment not null, version integer not null, constraint pk_sp_car_car primary key (id) ); -create sequence sp_car_car_seq; create table sp_car_car_wheels ( car bigint not null, @@ -229,82 +282,101 @@ create table sp_car_car_wheels ( ); create table car_accessory ( - id integer not null, + id integer auto_increment not null, name varchar(255), + fuse_id bigint not null, car_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_car_accessory primary key (id) ); -create sequence car_accessory_seq; + +create table car_fuse ( + id bigint auto_increment not null, + location_code varchar(255), + constraint pk_car_fuse primary key (id) +); + +create table category ( + id bigint auto_increment not null, + name varchar(255), + surveyobjectid bigint, + sequence_number integer not null, + constraint pk_category primary key (id) +); + +create table child_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_child_person primary key (identifier) +); create table configuration ( - type varchar(31) not null, - id integer not null, + type varchar(21) not null, + id integer auto_increment not null, name varchar(255), configurations_id integer, group_name varchar(255), product_name varchar(255), constraint pk_configuration primary key (id) ); -create sequence configuration_seq; create table configurations ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_configurations primary key (id) ); -create sequence configurations_seq; create table contact ( - id integer not null, - first_name varchar(255), - last_name varchar(255), + id integer auto_increment not null, + first_name varchar(127), + last_name varchar(127), phone varchar(255), mobile varchar(255), email varchar(255), customer_id integer not null, group_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, constraint pk_contact primary key (id) ); -create sequence contact_seq; create table contact_group ( - id integer not null, + id integer auto_increment not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_contact_group primary key (id) ); -create sequence contact_group_seq; create table contact_note ( - id integer not null, + id integer auto_increment not null, contact_id integer, title varchar(255), - note clob, - cretime timestamp not null, - updtime timestamp not null, + note longtext, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_contact_note primary key (id) ); -create sequence contact_note_seq; create table c_conversation ( - id bigint not null, + id bigint auto_increment not null, title varchar(255), - isopen boolean, + isopen tinyint(1) default 0 not null, group_id bigint, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, constraint pk_c_conversation primary key (id) ); -create sequence c_conversation_seq; create table o_country ( code varchar(2) not null, @@ -312,361 +384,621 @@ create table o_country ( constraint pk_o_country primary key (code) ); +create table cover ( + id bigint auto_increment not null, + s3url varchar(255), + deleted tinyint(1) default 0 not null, + constraint pk_cover primary key (id) +); + create table o_customer ( - id integer not null, - status varchar(1), + id integer auto_increment not null, + status varchar(1) comment 'status of the customer', name varchar(40) not null, - smallnote varchar(100), - anniversary date, + smallnote varchar(100) comment 'Short notes regarding the customer', + anniversary date comment 'Join date of the customer', billing_address_id smallint, shipping_address_id smallint, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, - constraint ck_o_customer_status check (status in ('N','A','I')), + constraint ck_o_customer_status check ( status in ('N','A','I')), constraint pk_o_customer primary key (id) +) comment='Holds external customers'; + +create table dcredit ( + id bigint auto_increment not null, + credit varchar(255), + constraint pk_dcredit primary key (id) +); + +create table dcredit_drol ( + dcredit_id bigint not null, + drol_id bigint not null, + constraint pk_dcredit_drol primary key (dcredit_id,drol_id) ); -create sequence o_customer_seq; create table dexh_entity ( - oid bigint not null, - exhange_rate decimal(38), - exhange_cmoney_amount decimal(38), - exhange_cmoney_currency varchar(3), - last_updated timestamp not null, + oid bigint auto_increment not null, + exhange varchar(255), + an_enum_type varchar(255), + last_updated datetime(6) not null, constraint pk_dexh_entity primary key (oid) ); -create sequence dexh_entity_seq; create table dperson ( - id bigint not null, + id bigint auto_increment not null, first_name varchar(255), last_name varchar(255), salary decimal(38), - a_amt decimal(38), - a_curr varchar(3), - i_start timestamp, - i_end timestamp, constraint pk_dperson primary key (id) ); -create sequence dperson_seq; + +create table drol ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_drol primary key (id) +); + +create table drot ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_drot primary key (id) +); + +create table drot_drol ( + drot_id bigint not null, + drol_id bigint not null, + constraint pk_drot_drol primary key (drot_id,drol_id) +); create table rawinherit_data ( - id bigint not null, + id bigint auto_increment not null, val integer, constraint pk_rawinherit_data primary key (id) ); -create sequence rawinherit_data_seq; -create table e_basic ( - id integer not null, - status varchar(1), +create table dfk_cascade ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_cascade primary key (id) +); + +create table dfk_cascade_one ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_dfk_cascade_one primary key (id) +); + +create table dfk_none ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none primary key (id) +); + +create table dfk_none_via_join ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none_via_join primary key (id) +); + +create table dfk_one ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_dfk_one primary key (id) +); + +create table dfk_set_null ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_set_null primary key (id) +); + +create table doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_doc primary key (id) +); + +create table doc_link ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link primary key (doc_id,link_id) +); + +create table doc_link_draft ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link_draft primary key (doc_id,link_id) +); + +create table doc_draft ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_doc_draft primary key (id) +); + +create table document ( + id bigint auto_increment not null, + title varchar(127), + body varchar(255), + organisation_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_document_title unique (title), + constraint pk_document primary key (id) +); + +create table document_draft ( + id bigint auto_increment not null, + title varchar(127), + body varchar(255), + when_publish datetime(6), + organisation_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_document_draft_title unique (title), + constraint pk_document_draft primary key (id) +); + +create table document_media ( + id bigint auto_increment not null, + document_id bigint, name varchar(255), description varchar(255), - some_date timestamp, - constraint ck_e_basic_status check (status in ('N','A','I')), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_document_media primary key (id) +); + +create table document_media_draft ( + id bigint auto_increment not null, + document_id bigint, + name varchar(255), + description varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_document_media_draft primary key (id) +); + +create table earray_bean ( + id bigint auto_increment not null, + name varchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + statuses varchar(1000), + status2 varchar(1000), + version bigint not null, + constraint pk_earray_bean primary key (id) +); + +create table earray_set_bean ( + id bigint auto_increment not null, + name varchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + version bigint not null, + constraint pk_earray_set_bean primary key (id) +); + +create table e_basic ( + id integer auto_increment not null, + status varchar(1), + name varchar(127), + description varchar(255), + some_date datetime(6), + constraint ck_e_basic_status check ( status in ('N','A','I')), constraint pk_e_basic primary key (id) ); -create sequence e_basic_seq; + +create table ebasic_change_log ( + id bigint auto_increment not null, + name varchar(20), + short_description varchar(50), + long_description varchar(100), + who_created varchar(255) not null, + who_modified varchar(255) not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + version bigint not null, + constraint pk_ebasic_change_log primary key (id) +); create table ebasic_clob ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), title varchar(255), - description clob, - last_update timestamp not null, + description longtext, + last_update datetime(6) not null, constraint pk_ebasic_clob primary key (id) ); -create sequence ebasic_clob_seq; create table ebasic_clob_fetch_eager ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), title varchar(255), - description clob, - last_update timestamp not null, + description longtext, + last_update datetime(6) not null, constraint pk_ebasic_clob_fetch_eager primary key (id) ); -create sequence ebasic_clob_fetch_eager_seq; create table ebasic_clob_no_ver ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - description clob, + description longtext, constraint pk_ebasic_clob_no_ver primary key (id) ); -create sequence ebasic_clob_no_ver_seq; create table e_basicenc ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varbinary(80), dob varbinary(20), - last_update timestamp, + status varbinary(20), + last_update datetime(6), constraint pk_e_basicenc primary key (id) ); -create sequence e_basicenc_seq; create table e_basicenc_bin ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - data blob, + data longblob, some_time varbinary(255), - last_update timestamp not null, + last_update datetime(6) not null, constraint pk_e_basicenc_bin primary key (id) ); -create sequence e_basicenc_bin_seq; create table e_basic_enum_id ( status varchar(1) not null, name varchar(255), description varchar(255), - constraint ck_e_basic_enum_id_status check (status in ('N','A','I')), + constraint ck_e_basic_enum_id_status check ( status in ('N','A','I')), constraint pk_e_basic_enum_id primary key (status) ); -create table ebasic_json_map ( - id bigint not null, +create table e_basic_eni ( + id integer auto_increment not null, + status integer, name varchar(255), - content clob, + description varchar(255), + some_date datetime(6), + constraint ck_e_basic_eni_status check ( status in (1,2,3)), + constraint pk_e_basic_eni primary key (id) +); + +create table ebasic_hstore ( + id bigint auto_increment not null, + name varchar(255), + map varchar(800), + version bigint not null, + constraint pk_ebasic_hstore primary key (id) +); + +create table ebasic_json_list ( + id bigint auto_increment not null, + name varchar(255), + bean_set varchar(700), + bean_list longtext, + bean_map varchar(700), + plain_bean varchar(500), + flags varchar(50), + tags varchar(100), + version bigint not null, + constraint pk_ebasic_json_list primary key (id) +); + +create table ebasic_json_map ( + id bigint auto_increment not null, + name varchar(255), + content longtext, version bigint not null, constraint pk_ebasic_json_map primary key (id) ); -create sequence ebasic_json_map_seq; create table ebasic_json_map_blob ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content blob, + content longblob, version bigint not null, constraint pk_ebasic_json_map_blob primary key (id) ); -create sequence ebasic_json_map_blob_seq; create table ebasic_json_map_clob ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content clob, + content longtext, version bigint not null, constraint pk_ebasic_json_map_clob primary key (id) ); -create sequence ebasic_json_map_clob_seq; + +create table ebasic_json_map_detail ( + id bigint auto_increment not null, + owner_id bigint, + name varchar(255), + content longtext, + version bigint not null, + constraint pk_ebasic_json_map_detail primary key (id) +); create table ebasic_json_map_json_b ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content clob, + content longtext, version bigint not null, constraint pk_ebasic_json_map_json_b primary key (id) ); -create sequence ebasic_json_map_json_b_seq; create table ebasic_json_map_varchar ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), content varchar(3000), version bigint not null, constraint pk_ebasic_json_map_varchar primary key (id) ); -create sequence ebasic_json_map_varchar_seq; create table ebasic_json_node ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content clob, + content longtext, version bigint not null, constraint pk_ebasic_json_node primary key (id) ); -create sequence ebasic_json_node_seq; create table ebasic_json_node_blob ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content blob, + content longblob, version bigint not null, constraint pk_ebasic_json_node_blob primary key (id) ); -create sequence ebasic_json_node_blob_seq; create table ebasic_json_node_json_b ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content clob, + content longtext, version bigint not null, constraint pk_ebasic_json_node_json_b primary key (id) ); -create sequence ebasic_json_node_json_b_seq; create table ebasic_json_node_varchar ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), content varchar(1000), version bigint not null, constraint pk_ebasic_json_node_varchar primary key (id) ); -create sequence ebasic_json_node_varchar_seq; + +create table ebasic_json_unmapped ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_ebasic_json_unmapped primary key (id) +); create table e_basic_ndc ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_e_basic_ndc primary key (id) ); -create sequence e_basic_ndc_seq; + +create table ebasic_no_sdchild ( + id bigint auto_increment not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + constraint pk_ebasic_no_sdchild primary key (id) +); + +create table ebasic_sdchild ( + id bigint auto_increment not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_ebasic_sdchild primary key (id) +); + +create table ebasic_soft_delete ( + id bigint auto_increment not null, + name varchar(255), + description varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_ebasic_soft_delete primary key (id) +); create table e_basicver ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), other varchar(255), - last_update timestamp not null, + last_update datetime(6) not null, constraint pk_e_basicver primary key (id) ); -create sequence e_basicver_seq; create table e_basic_withlife ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), + deleted tinyint(1) default 0 not null, version bigint not null, constraint pk_e_basic_withlife primary key (id) ); -create sequence e_basic_withlife_seq; create table e_basicverucon ( - id integer not null, - name varchar(255), - other varchar(255), - other_one varchar(255), + id integer auto_increment not null, + name varchar(127), + other varchar(127), + other_one varchar(127), description varchar(255), - last_update timestamp not null, + last_update datetime(6) not null, constraint uq_e_basicverucon_name unique (name), + constraint uq_e_basicverucon_other_other_one unique (other,other_one), constraint pk_e_basicverucon primary key (id) ); -create sequence e_basicverucon_seq; + +create table e_col_ab ( + id bigint auto_increment not null, + column_a varchar(255), + column_b varchar(255), + constraint pk_e_col_ab primary key (id) +); + +create table ecustom_id ( + id varchar(127) not null, + name varchar(255), + constraint pk_ecustom_id primary key (id) +); create table eemb_inner ( - id integer not null, + id integer auto_increment not null, nome_inner varchar(255), outer_id integer, update_count integer not null, constraint pk_eemb_inner primary key (id) ); -create sequence eemb_inner_seq; create table eemb_outer ( - id integer not null, + id integer auto_increment not null, nome_outer varchar(255), - date1 timestamp, - date2 timestamp, + date1 datetime(6), + date2 datetime(6), update_count integer not null, constraint pk_eemb_outer primary key (id) ); -create sequence eemb_outer_seq; create table egen_props ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - ts_created timestamp not null, - ts_updated timestamp not null, - ldt_created timestamp not null, - ldt_updated timestamp not null, - odt_created timestamp not null, - odt_updated timestamp not null, - zdt_created timestamp not null, - zdt_updated timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + ts_created datetime(6) not null, + ts_updated datetime(6) not null, + ldt_created datetime(6) not null, + ldt_updated datetime(6) not null, + odt_created datetime(6) not null, + odt_updated datetime(6) not null, + zdt_created datetime(6) not null, + zdt_updated datetime(6) not null, + instant_created datetime(6) not null, + instant_updated datetime(6) not null, long_created bigint not null, long_updated bigint not null, constraint pk_egen_props primary key (id) ); -create sequence egen_props_seq; create table einvoice ( - id bigint not null, - invoice_date timestamp, + id bigint auto_increment not null, + invoice_date datetime(6), state integer, person_id bigint, ship_street varchar(255), ship_suburb varchar(255), ship_city varchar(255), - street varchar(255), - suburb varchar(255), - city varchar(255), + ship_status varchar(3), + bill_street varchar(255), + bill_suburb varchar(255), + bill_city varchar(255), + bill_status varchar(3), version bigint not null, - constraint ck_einvoice_state check (state in (0,1,2)), + constraint ck_einvoice_state check ( state in (0,1,2)), + constraint ck_einvoice_ship_status check ( ship_status in ('ONE','TWO')), + constraint ck_einvoice_bill_status check ( bill_status in ('ONE','TWO')), constraint pk_einvoice primary key (id) ); -create sequence einvoice_seq; create table e_main ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), version bigint not null, constraint pk_e_main primary key (id) ); -create sequence e_main_seq; create table enull_collection ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_enull_collection primary key (id) ); -create sequence enull_collection_seq; create table enull_collection_detail ( - id integer not null, + id integer auto_increment not null, enull_collection_id integer not null, something varchar(255), constraint pk_enull_collection_detail primary key (id) ); -create sequence enull_collection_detail_seq; create table eopt_one_a ( - id integer not null, + id integer auto_increment not null, name_for_a varchar(255), b_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_eopt_one_a primary key (id) ); -create sequence eopt_one_a_seq; create table eopt_one_b ( - id integer not null, + id integer auto_increment not null, name_for_b varchar(255), c_id integer not null, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_eopt_one_b primary key (id) ); -create sequence eopt_one_b_seq; create table eopt_one_c ( - id integer not null, + id integer auto_increment not null, name_for_c varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_eopt_one_c primary key (id) ); -create sequence eopt_one_c_seq; create table eperson ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), notes varchar(255), street varchar(255), suburb varchar(255), - city varchar(255), + addr_city varchar(255), + addr_status varchar(3), version bigint not null, + constraint ck_eperson_addr_status check ( addr_status in ('ONE','TWO')), constraint pk_eperson primary key (id) ); -create sequence eperson_seq; + +create table e_person_online ( + id bigint auto_increment not null, + email varchar(127), + online_status tinyint(1) default 0 not null, + when_updated datetime(6) not null, + constraint uq_e_person_online_email unique (email), + constraint pk_e_person_online primary key (id) +); create table esimple ( usertypeid integer auto_increment not null, @@ -674,97 +1006,204 @@ create table esimple ( constraint pk_esimple primary key (usertypeid) ); +create table esoft_del_book ( + id bigint auto_increment not null, + book_title varchar(255), + lend_by_id bigint, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_book primary key (id) +); + +create table esoft_del_book_esoft_del_user ( + esoft_del_book_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_book_esoft_del_user primary key (esoft_del_book_id,esoft_del_user_id) +); + +create table esoft_del_down ( + id bigint auto_increment not null, + esoft_del_mid_id bigint not null, + down varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_down primary key (id) +); + +create table esoft_del_mid ( + id bigint auto_increment not null, + top_id bigint, + mid varchar(255), + up_id bigint, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_mid primary key (id) +); + +create table esoft_del_one_a ( + id bigint auto_increment not null, + name varchar(255), + oneb_id bigint, + deleted tinyint(1) default 0 not null, + version bigint not null, + constraint uq_esoft_del_one_a_oneb_id unique (oneb_id), + constraint pk_esoft_del_one_a primary key (id) +); + +create table esoft_del_one_b ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_esoft_del_one_b primary key (id) +); + +create table esoft_del_role ( + id bigint auto_increment not null, + role_name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_role primary key (id) +); + +create table esoft_del_role_esoft_del_user ( + esoft_del_role_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_role_esoft_del_user primary key (esoft_del_role_id,esoft_del_user_id) +); + +create table esoft_del_top ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_top primary key (id) +); + +create table esoft_del_up ( + id bigint auto_increment not null, + up varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_up primary key (id) +); + +create table esoft_del_user ( + id bigint auto_increment not null, + user_name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_user primary key (id) +); + +create table esoft_del_user_esoft_del_role ( + esoft_del_user_id bigint not null, + esoft_del_role_id bigint not null, + constraint pk_esoft_del_user_esoft_del_role primary key (esoft_del_user_id,esoft_del_role_id) +); + +create table esome_convert_type ( + id bigint auto_increment not null, + name varchar(255), + money decimal(38), + constraint pk_esome_convert_type primary key (id) +); + create table esome_type ( - id integer not null, + id integer auto_increment not null, currency varchar(3), locale varchar(20), time_zone varchar(20), constraint pk_esome_type primary key (id) ); -create sequence esome_type_seq; create table etrans_many ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_etrans_many primary key (id) ); -create sequence etrans_many_seq; + +create table rawinherit_uncle ( + id integer auto_increment not null, + name varchar(255), + parent_id bigint not null, + version bigint not null, + constraint pk_rawinherit_uncle primary key (id) +); create table evanilla_collection ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_evanilla_collection primary key (id) ); -create sequence evanilla_collection_seq; create table evanilla_collection_detail ( - id integer not null, + id integer auto_increment not null, evanilla_collection_id integer not null, something varchar(255), constraint pk_evanilla_collection_detail primary key (id) ); -create sequence evanilla_collection_detail_seq; create table ewho_props ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, who_created varchar(255) not null, who_modified varchar(255) not null, - version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, constraint pk_ewho_props primary key (id) ); -create sequence ewho_props_seq; create table e_withinet ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), inet_address varchar(50), version bigint not null, constraint pk_e_withinet primary key (id) ); -create sequence e_withinet_seq; create table td_child ( - child_id integer not null, + child_id integer auto_increment not null, child_name varchar(255), parent_id integer not null, constraint pk_td_child primary key (child_id) ); -create sequence td_child_seq; create table td_parent ( parent_type varchar(31) not null, - parent_id integer not null, + parent_id integer auto_increment not null, parent_name varchar(255), extended_name varchar(255), constraint pk_td_parent primary key (parent_id) ); -create sequence td_parent_seq; + +create table empl ( + id bigint auto_increment not null, + name varchar(255), + age integer, + default_address_id bigint, + constraint pk_empl primary key (id) +); create table feature_desc ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), constraint pk_feature_desc primary key (id) ); -create sequence feature_desc_seq; create table f_first ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_f_first primary key (id) ); -create sequence f_first_seq; create table foo ( - foo_id integer not null, + foo_id integer auto_increment not null, important_text varchar(255), version integer not null, constraint pk_foo primary key (foo_id) ); -create sequence foo_seq; create table gen_key_identity ( id bigint auto_increment not null, @@ -773,120 +1212,227 @@ create table gen_key_identity ( ); create table gen_key_sequence ( - id bigint not null, + id bigint auto_increment not null, description varchar(255), constraint pk_gen_key_sequence primary key (id) ); -create sequence seq; create table gen_key_table ( - id bigint not null, + id bigint auto_increment not null, description varchar(255), constraint pk_gen_key_table primary key (id) ); -create sequence gen_key_table_seq; + +create table grand_parent_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + family_name varchar(255), + address varchar(255), + constraint pk_grand_parent_person primary key (identifier) +); + +create table survey_group ( + id bigint auto_increment not null, + name varchar(255), + categoryobjectid bigint, + sequence_number integer not null, + constraint pk_survey_group primary key (id) +); create table c_group ( - id bigint not null, - inactive boolean, + id bigint auto_increment not null, + inactive tinyint(1) default 0 not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, constraint pk_c_group primary key (id) ); -create sequence c_group_seq; + +create table he_doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_he_doc primary key (id) +); + +create table hx_link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hx_link primary key (id) +); + +create table hx_link_doc ( + hx_link_id bigint not null, + he_doc_id bigint not null, + constraint pk_hx_link_doc primary key (hx_link_id,he_doc_id) +); + +create table hi_doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hi_doc primary key (id) +); + +create table hi_link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hi_link primary key (id) +); + +create table hi_link_doc ( + hi_link_id bigint not null, + hi_doc_id bigint not null, + constraint pk_hi_link_doc primary key (hi_link_id,hi_doc_id) +); create table imrelated ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), owner_id bigint not null, constraint pk_imrelated primary key (id) ); -create sequence imrelated_seq; create table imroot ( - dtype varchar(10) not null, - id bigint not null, - title varchar(255), - when_title timestamp, + dtype varchar(31) not null, + id bigint auto_increment not null, name varchar(255), + title varchar(255), + when_title datetime(6), constraint pk_imroot primary key (id) ); -create sequence imroot_seq; create table ixresource ( dtype varchar(255), - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_ixresource primary key (id) ); create table info_company ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), version bigint not null, constraint pk_info_company primary key (id) ); -create sequence info_company_seq; create table info_contact ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), company_id bigint not null, version bigint not null, constraint pk_info_contact primary key (id) ); -create sequence info_contact_seq; create table info_customer ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), company_id bigint, version bigint not null, constraint uq_info_customer_company_id unique (company_id), constraint pk_info_customer primary key (id) ); -create sequence info_customer_seq; create table inner_report ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), forecast_id bigint, constraint uq_inner_report_forecast_id unique (forecast_id), constraint pk_inner_report primary key (id) ); -create sequence inner_report_seq; create table drel_invoice ( - id bigint not null, + id bigint auto_increment not null, booking bigint, version integer not null, constraint pk_drel_invoice primary key (id) ); -create sequence drel_invoice_seq; create table item ( customer integer not null, - itemnumber varchar(255) not null, + itemnumber varchar(127) not null, description varchar(255), units varchar(255), - type integer, - region integer, - date_modified timestamp, - date_created timestamp, + type integer not null, + region integer not null, + date_modified datetime(6), + date_created datetime(6), modified_by varchar(255), created_by varchar(255), version bigint not null, constraint pk_item primary key (customer,itemnumber) ); +create table monkey ( + mid bigint auto_increment not null, + name varchar(255), + food_preference varchar(255), + version bigint not null, + constraint pk_monkey primary key (mid) +); + +create table trainer ( + tid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_trainer primary key (tid) +); + +create table trainer_monkey ( + trainer_tid bigint not null, + monkey_mid bigint not null, + constraint uq_trainer_monkey_mid unique (monkey_mid), + constraint pk_trainer_monkey primary key (trainer_tid,monkey_mid) +); + +create table troop ( + pid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_troop primary key (pid) +); + +create table troop_monkey ( + troop_pid bigint not null, + monkey_mid bigint not null, + constraint uq_troop_monkey_mid unique (monkey_mid), + constraint pk_troop_monkey primary key (troop_pid,monkey_mid) +); + +create table l2_cldf_reset_bean ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_l2_cldf_reset_bean primary key (id) +); + +create table l2_cldf_reset_bean_child ( + id bigint auto_increment not null, + parent_id bigint, + constraint pk_l2_cldf_reset_bean_child primary key (id) +); + create table level1 ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_level1 primary key (id) ); -create sequence level1_seq; create table level1_level4 ( level1_id bigint not null, @@ -901,11 +1447,10 @@ create table level1_level2 ( ); create table level2 ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_level2 primary key (id) ); -create sequence level2_seq; create table level2_level3 ( level2_id bigint not null, @@ -914,28 +1459,52 @@ create table level2_level3 ( ); create table level3 ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_level3 primary key (id) ); -create sequence level3_seq; create table level4 ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_level4 primary key (id) ); -create sequence level4_seq; + +create table link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + deleted tinyint(1) default 0 not null, + constraint pk_link primary key (id) +); + +create table link_draft ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + dirty tinyint(1) default 0 not null, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + deleted tinyint(1) default 0 not null, + constraint pk_link_draft primary key (id) +); create table la_attr_value ( - id integer not null, + id integer auto_increment not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_la_attr_value primary key (id) ); -create sequence la_attr_value_seq; create table la_attr_value_attribute ( la_attr_value_id integer not null, @@ -945,25 +1514,23 @@ create table la_attr_value_attribute ( create table mmedia ( type varchar(31) not null, - id bigint not null, + id bigint auto_increment not null, url varchar(255), note varchar(255), constraint pk_mmedia primary key (id) ); -create sequence mmedia_seq; create table non_updateprop ( - id integer not null, + id integer auto_increment not null, non_enum varchar(5), name varchar(255), note varchar(255), - constraint ck_non_updateprop_non_enum check (non_enum in ('BEGIN','END')), + constraint ck_non_updateprop_non_enum check ( non_enum in ('BEGIN','END')), constraint pk_non_updateprop primary key (id) ); -create sequence non_updateprop_seq; create table mprinter ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), flags bigint not null, current_state_id bigint, @@ -973,43 +1540,38 @@ create table mprinter ( last_swap_black_id bigint, version bigint not null, constraint uq_mprinter_last_swap_cyan_id unique (last_swap_cyan_id), - constraint uq_mprinter_last_swap_magenta_2 unique (last_swap_magenta_id), + constraint uq_mprinter_last_swap_magenta_id unique (last_swap_magenta_id), constraint uq_mprinter_last_swap_yellow_id unique (last_swap_yellow_id), constraint uq_mprinter_last_swap_black_id unique (last_swap_black_id), constraint pk_mprinter primary key (id) ); -create sequence mprinter_seq; create table mprinter_state ( - id bigint not null, - flags bigint, + id bigint auto_increment not null, + flags bigint not null, printer_id bigint, version bigint not null, constraint pk_mprinter_state primary key (id) ); -create sequence mprinter_state_seq; create table mprofile ( - id bigint not null, + id bigint auto_increment not null, picture_id bigint, name varchar(255), constraint pk_mprofile primary key (id) ); -create sequence mprofile_seq; create table mprotected_construct_bean ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_mprotected_construct_bean primary key (id) ); -create sequence mprotected_construct_bean_seq; create table mrole ( - roleid integer not null, + roleid integer auto_increment not null, role_name varchar(255), constraint pk_mrole primary key (roleid) ); -create sequence mrole_seq; create table mrole_muser ( mrole_roleid integer not null, @@ -1018,64 +1580,83 @@ create table mrole_muser ( ); create table msome_other ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_msome_other primary key (id) ); -create sequence msome_other_seq; create table muser ( - userid integer not null, + userid integer auto_increment not null, user_name varchar(255), user_type_id integer, constraint pk_muser primary key (userid) ); -create sequence muser_seq; create table muser_type ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_muser_type primary key (id) ); -create sequence muser_type_seq; + +create table mail_box ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mail_box primary key (id) +); + +create table mail_user ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mail_user primary key (id) +); + +create table mail_user_inbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_inbox primary key (mail_user_id,mail_box_id) +); + +create table mail_user_outbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_outbox primary key (mail_user_id,mail_box_id) +); create table map_super_actual ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - when_created timestamp not null, - when_updated timestamp not null, + when_created datetime(6) not null, + when_updated datetime(6) not null, constraint pk_map_super_actual primary key (id) ); -create sequence map_super_actual_seq; create table c_message ( - id bigint not null, + id bigint auto_increment not null, title varchar(255), body varchar(255), conversation_id bigint, user_id bigint, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, constraint pk_c_message primary key (id) ); -create sequence c_message_seq; create table mnoc_role ( - role_id integer not null, + role_id integer auto_increment not null, role_name varchar(255), version integer not null, constraint pk_mnoc_role primary key (role_id) ); -create sequence mnoc_role_seq; create table mnoc_user ( - user_id integer not null, + user_id integer auto_increment not null, user_name varchar(255), version integer not null, constraint pk_mnoc_user primary key (user_id) ); -create sequence mnoc_user_seq; create table mnoc_user_mnoc_role ( mnoc_user_user_id integer not null, @@ -1083,52 +1664,122 @@ create table mnoc_user_mnoc_role ( constraint pk_mnoc_user_mnoc_role primary key (mnoc_user_user_id,mnoc_role_role_id) ); +create table mny_a ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_a primary key (id) +); + +create table mny_b ( + id bigint auto_increment not null, + name varchar(255), + a_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_b primary key (id) +); + +create table mny_b_mny_c ( + mny_b_id bigint not null, + mny_c_id bigint not null, + constraint pk_mny_b_mny_c primary key (mny_b_id,mny_c_id) +); + +create table mny_c ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_c primary key (id) +); + +create table mny_topic ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mny_topic primary key (id) +); + +create table subtopics ( + topic bigint not null, + subtopic bigint not null, + constraint pk_subtopics primary key (topic,subtopic) +); + create table mp_role ( - id bigint not null, + id bigint auto_increment not null, mp_user_id bigint not null, code varchar(255), organization_id bigint, constraint pk_mp_role primary key (id) ); -create sequence mp_role_seq; create table mp_user ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_mp_user primary key (id) ); -create sequence mp_user_seq; + +create table ms_many_a ( + aid bigint auto_increment not null, + name varchar(255), + ms_many_a_many_b tinyint(1) default 0 not null, + ms_many_b tinyint(1) default 0 not null, + deleted tinyint(1) default 0 not null, + constraint pk_ms_many_a primary key (aid) +); + +create table ms_many_a_many_b ( + ms_many_a_aid bigint not null, + ms_many_b_bid bigint not null, + constraint pk_ms_many_a_many_b primary key (ms_many_a_aid,ms_many_b_bid) +); + +create table ms_many_b ( + bid bigint auto_increment not null, + name varchar(255), + deleted tinyint(1) default 0 not null, + constraint pk_ms_many_b primary key (bid) +); + +create table ms_many_b_many_a ( + ms_many_b_bid bigint not null, + ms_many_a_aid bigint not null, + constraint pk_ms_many_b_many_a primary key (ms_many_b_bid,ms_many_a_aid) +); create table my_lob_size ( - id integer not null, + id integer auto_increment not null, name varchar(255), - my_count integer, - my_lob clob, + my_count integer not null, + my_lob longtext, constraint pk_my_lob_size primary key (id) ); -create sequence my_lob_size_seq; create table my_lob_size_join_many ( - id integer not null, + id integer auto_increment not null, something varchar(255), other varchar(255), parent_id integer, constraint pk_my_lob_size_join_many primary key (id) ); -create sequence my_lob_size_join_many_seq; create table noidbean ( name varchar(255), subject varchar(255), - when_created timestamp not null + when_created datetime(6) not null ); create table o_cached_bean ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_o_cached_bean primary key (id) ); -create sequence o_cached_bean_seq; create table o_cached_bean_country ( o_cached_bean_id bigint not null, @@ -1137,25 +1788,50 @@ create table o_cached_bean_country ( ); create table o_cached_bean_child ( - id bigint not null, + id bigint auto_increment not null, cached_bean_id bigint, constraint pk_o_cached_bean_child primary key (id) ); -create sequence o_cached_bean_child_seq; + +create table o_cached_natkey ( + id bigint auto_increment not null, + store varchar(255), + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey primary key (id) +); + +create table o_cached_natkey3 ( + id bigint auto_increment not null, + store varchar(255), + code integer not null, + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey3 primary key (id) +); create table ocar ( - id integer not null, + id integer auto_increment not null, vin varchar(255), name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_ocar primary key (id) ); -create sequence ocar_seq; + +create table ocompany ( + id integer auto_increment not null, + corp_id varchar(50), + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + constraint uq_ocompany_corp_id unique (corp_id), + constraint pk_ocompany primary key (id) +); create table oengine ( - engine_id binary(16) not null, + engine_id varchar(40) not null, short_desc varchar(255), car_id integer, version integer not null, @@ -1164,7 +1840,7 @@ create table oengine ( ); create table ogear_box ( - id binary(16) not null, + id varchar(40) not null, box_desc varchar(255), box_size integer, car_id integer, @@ -1173,243 +1849,390 @@ create table ogear_box ( constraint pk_ogear_box primary key (id) ); +create table oroad_show_msg ( + id integer auto_increment not null, + company_id integer not null, + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + constraint uq_oroad_show_msg_company_id unique (company_id), + constraint pk_oroad_show_msg primary key (id) +); + +create table om_ordered_detail ( + id bigint auto_increment not null, + name varchar(255), + master_id bigint, + version bigint not null, + sort_order integer, + constraint pk_om_ordered_detail primary key (id) +); + +create table om_ordered_master ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_om_ordered_master primary key (id) +); + create table o_order ( - id integer not null, + id integer auto_increment not null, status integer, order_date date, ship_date date, kcustomer_id integer not null, - cretime timestamp not null, - updtime timestamp not null, - constraint ck_o_order_status check (status in (0,1,2,3)), + cretime datetime(6) not null, + updtime datetime(6) not null, + constraint ck_o_order_status check ( status in (0,1,2,3)), constraint pk_o_order primary key (id) ); -create sequence o_order_seq; create table o_order_detail ( - id integer not null, - order_id integer, + id integer auto_increment not null, + order_id integer not null, order_qty integer, ship_qty integer, unit_price double, product_id integer, - cretime timestamp, - updtime timestamp not null, + cretime datetime(6), + updtime datetime(6) not null, constraint pk_o_order_detail primary key (id) ); -create sequence o_order_detail_seq; create table s_orders ( - uuid varchar(255) not null, + uuid varchar(40) not null, constraint pk_s_orders primary key (uuid) ); create table s_order_items ( - uuid varchar(255) not null, + uuid varchar(40) not null, product_variant_uuid varchar(255), - order_uuid varchar(255), - quantity integer, + order_uuid varchar(40), + quantity integer not null, amount decimal(38), constraint pk_s_order_items primary key (uuid) ); create table or_order_ship ( - id integer not null, + id integer auto_increment not null, order_id integer, - ship_time timestamp, - cretime timestamp not null, - updtime timestamp not null, + ship_time datetime(6), + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_or_order_ship primary key (id) ); -create sequence or_order_ship_seq; + +create table organisation ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_organisation primary key (id) +); + +create table oto_bchild ( + master_id bigint auto_increment not null, + child varchar(255), + constraint pk_oto_bchild primary key (master_id) +); + +create table oto_bmaster ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_oto_bmaster primary key (id) +); create table oto_child ( - id integer not null, + id integer auto_increment not null, name varchar(255), master_id bigint, constraint uq_oto_child_master_id unique (master_id), constraint pk_oto_child primary key (id) ); -create sequence oto_child_seq; + +create table oto_cust ( + cid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_oto_cust primary key (cid) +); + +create table oto_cust_address ( + aid bigint auto_increment not null, + line1 varchar(255), + line2 varchar(255), + line3 varchar(255), + customer_cid bigint, + version bigint not null, + constraint uq_oto_cust_address_customer_cid unique (customer_cid), + constraint pk_oto_cust_address primary key (aid) +); create table oto_master ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_oto_master primary key (id) ); -create sequence oto_master_seq; + +create table oto_prime ( + pid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_oto_prime primary key (pid) +); + +create table oto_prime_extra ( + eid bigint not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_prime_extra primary key (eid) +); + +create table oto_th_many ( + id bigint auto_increment not null, + oto_th_top_id bigint not null, + many varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_oto_th_many primary key (id) +); + +create table oto_th_one ( + id bigint auto_increment not null, + one tinyint(1) default 0 not null, + many_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_oto_th_one_many_id unique (many_id), + constraint pk_oto_th_one primary key (id) +); + +create table oto_th_top ( + id bigint auto_increment not null, + topp varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_oto_th_top primary key (id) +); + +create table oto_ubprime ( + pid varchar(40) not null, + name varchar(255), + version bigint not null, + constraint pk_oto_ubprime primary key (pid) +); + +create table oto_ubprime_extra ( + eid varchar(40) not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_ubprime_extra primary key (eid) +); + +create table oto_uprime ( + pid varchar(40) not null, + name varchar(255), + version bigint not null, + constraint pk_oto_uprime primary key (pid) +); + +create table oto_uprime_extra ( + eid varchar(40) not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_uprime_extra primary key (eid) +); create table pfile ( - id integer not null, + id integer auto_increment not null, name varchar(255), file_content_id integer, file_content2_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint uq_pfile_file_content_id unique (file_content_id), constraint uq_pfile_file_content2_id unique (file_content2_id), constraint pk_pfile primary key (id) ); -create sequence pfile_seq; create table pfile_content ( - id integer not null, - content blob, - cretime timestamp not null, - updtime timestamp not null, + id integer auto_increment not null, + content longblob, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_pfile_content primary key (id) ); -create sequence pfile_content_seq; create table paggview ( - pview_id binary(16), + pview_id varchar(40), amount integer not null, constraint uq_paggview_pview_id unique (pview_id) ); create table pallet_location ( type varchar(31) not null, - id integer not null, + id integer auto_increment not null, zone_sid integer not null, attribute varchar(255), constraint pk_pallet_location primary key (id) ); -create sequence pallet_location_seq; create table parcel ( - parcelid bigint not null, + parcelid bigint auto_increment not null, description varchar(255), constraint pk_parcel primary key (parcelid) ); -create sequence parcel_seq; create table parcel_location ( - parcellocid bigint not null, + parcellocid bigint auto_increment not null, location varchar(255), parcelid bigint, constraint uq_parcel_location_parcelid unique (parcelid), constraint pk_parcel_location primary key (parcellocid) ); -create sequence parcel_location_seq; create table rawinherit_parent ( type varchar(31) not null, - id bigint not null, + id bigint auto_increment not null, val integer, + more varchar(255), constraint pk_rawinherit_parent primary key (id) ); -create sequence rawinherit_parent_seq; -create table rawinherit_parent_rawinherit_dat ( +create table rawinherit_parent_rawinherit_data ( rawinherit_parent_id bigint not null, rawinherit_data_id bigint not null, - constraint pk_rawinherit_parent_rawinher_0 primary key (rawinherit_parent_id,rawinherit_data_id) + constraint pk_rawinherit_parent_rawinherit_data primary key (rawinherit_parent_id,rawinherit_data_id) +); + +create table parent_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_parent_person primary key (identifier) ); create table c_participation ( - id bigint not null, + id bigint auto_increment not null, rating integer, type integer, conversation_id bigint not null, user_id bigint not null, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - constraint ck_c_participation_type check (type in (0,1)), + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint ck_c_participation_type check ( type in (0,1)), constraint pk_c_participation primary key (id) ); -create sequence c_participation_seq; create table mt_permission ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_mt_permission primary key (id) ); create table persistent_file ( - id integer not null, + id integer auto_increment not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_persistent_file primary key (id) ); -create sequence persistent_file_seq; create table persistent_file_content ( - id integer not null, + id integer auto_increment not null, persistent_file_id integer, - content blob, - cretime timestamp not null, - updtime timestamp not null, + content longblob, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, - constraint uq_persistent_file_content_pe_1 unique (persistent_file_id), + constraint uq_persistent_file_content_persistent_file_id unique (persistent_file_id), constraint pk_persistent_file_content primary key (id) ); -create sequence persistent_file_content_seq; create table persons ( - id bigint not null, + id bigint auto_increment not null, surname varchar(64) not null, name varchar(64) not null, constraint pk_persons primary key (id) ); -create sequence persons_seq start with 1000 increment by 40; create table person ( - oid bigint not null, + oid bigint auto_increment not null, default_address_oid bigint, version integer not null, constraint pk_person primary key (oid) ); -create sequence person_seq; create table phones ( - id bigint not null, + id bigint auto_increment not null, phone_number varchar(7) not null, person_id bigint not null, constraint uq_phones_phone_number unique (phone_number), constraint pk_phones primary key (id) ); -create sequence phones_seq; + +create table primary_revision ( + id bigint not null, + revision integer not null, + name varchar(255), + version bigint not null, + constraint pk_primary_revision primary key (id,revision) +); create table o_product ( - id integer not null, + id integer auto_increment not null, sku varchar(20), name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, constraint pk_o_product primary key (id) ); -create sequence o_product_seq; create table pp ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), value varchar(100) not null, constraint pk_pp primary key (id) ); create table pp_to_ww ( - pp_id binary(16) not null, - ww_id binary(16) not null, + pp_id varchar(40) not null, + ww_id varchar(40) not null, constraint pk_pp_to_ww primary key (pp_id,ww_id) ); +create table question ( + id bigint auto_increment not null, + name varchar(255), + groupobjectid bigint, + sequence_number integer not null, + constraint pk_question primary key (id) +); + create table rcustomer ( - company varchar(255) not null, - name varchar(255) not null, + company varchar(127) not null, + name varchar(127) not null, description varchar(255), constraint pk_rcustomer primary key (company,name) ); create table r_orders ( - company varchar(255) not null, + company varchar(127) not null, order_number integer not null, - customername varchar(255), + customername varchar(127), item varchar(255), constraint pk_r_orders primary key (company,order_number) ); @@ -1429,299 +2252,317 @@ create table resourcefile ( constraint pk_resourcefile primary key (id) ); +create table em_role ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_em_role primary key (id) +); + create table mt_role ( - id binary(16) not null, + id varchar(40) not null, name varchar(50), - tenant_id binary(16), + tenant_id varchar(40), version bigint not null, constraint pk_mt_role primary key (id) ); create table mt_role_permission ( - mt_role_id binary(16) not null, - mt_permission_id binary(16) not null, + mt_role_id varchar(40) not null, + mt_permission_id varchar(40) not null, constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) ); -create table em_role ( - id bigint not null, - name varchar(255), - constraint pk_em_role primary key (id) -); -create sequence em_role_seq; - create table f_second ( - id bigint not null, + id bigint auto_increment not null, + mod_name varchar(255), first bigint, title varchar(255), constraint uq_f_second_first unique (first), constraint pk_f_second primary key (id) ); -create sequence f_second_seq; create table section ( - id integer not null, + id integer auto_increment not null, article_id integer, type integer, - content clob, - cretime timestamp not null, - updtime timestamp not null, + content longtext, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, - constraint ck_section_type check (type in (0,1)), + constraint ck_section_type check ( type in (0,1)), constraint pk_section primary key (id) ); -create sequence section_seq; create table self_parent ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), parent_id bigint, version bigint not null, constraint pk_self_parent primary key (id) ); -create sequence self_parent_seq; create table self_ref_customer ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), referred_by_id bigint, constraint pk_self_ref_customer primary key (id) ); -create sequence self_ref_customer_seq; create table self_ref_example ( - id bigint not null, + id bigint auto_increment not null, name varchar(255) not null, parent_id bigint, constraint pk_self_ref_example primary key (id) ); -create sequence self_ref_example_seq; create table some_enum_bean ( - id bigint not null, + id bigint auto_increment not null, some_enum integer, name varchar(255), - constraint ck_some_enum_bean_some_enum check (some_enum in (0,1)), + constraint ck_some_enum_bean_some_enum check ( some_enum in (0,1)), constraint pk_some_enum_bean primary key (id) ); -create sequence some_enum_bean_seq; create table some_file_bean ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), - content blob, + content longblob, version bigint not null, constraint pk_some_file_bean primary key (id) ); -create sequence some_file_bean_seq; create table some_new_types_bean ( - id bigint not null, + id bigint auto_increment not null, dow integer(1), mth integer(1), yr integer, yr_mth date, local_date date, - local_date_time timestamp, - offset_date_time timestamp, - zoned_date_time timestamp, - instant timestamp, + local_date_time datetime(6), + offset_date_time datetime(6), + zoned_date_time datetime(6), + instant datetime(6), zone_id varchar(60), zone_offset varchar(60), + path varchar(255), + period varchar(20), version bigint not null, - constraint ck_some_new_types_bean_dow check (dow in ('1','2','3','4','5','6','7')), - constraint ck_some_new_types_bean_mth check (mth in ('1','2','3','4','5','6','7','8','9','10','11','12')), + constraint ck_some_new_types_bean_dow check ( dow in (1,2,3,4,5,6,7)), + constraint ck_some_new_types_bean_mth check ( mth in (1,2,3,4,5,6,7,8,9,10,11,12)), constraint pk_some_new_types_bean primary key (id) ); -create sequence some_new_types_bean_seq; create table some_period_bean ( - id bigint not null, - period_years integer, - period_months integer, - period_days integer, + id bigint auto_increment not null, anniversary date, version bigint not null, constraint pk_some_period_bean primary key (id) ); -create sequence some_period_bean_seq; create table stockforecast ( type varchar(31) not null, - id bigint not null, + id bigint auto_increment not null, inner_report_id bigint, constraint pk_stockforecast primary key (id) ); -create sequence stockforecast_seq; create table sub_section ( - id integer not null, + id integer auto_increment not null, section_id integer, title varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_sub_section primary key (id) ); -create sequence sub_section_seq; create table sub_type ( - sub_type_id integer not null, + sub_type_id integer auto_increment not null, description varchar(255), version bigint not null, constraint pk_sub_type primary key (sub_type_id) ); -create sequence sub_type_seq; + +create table survey ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_survey primary key (id) +); create table tbytes_only ( - id integer not null, - content blob, + id integer auto_increment not null, + content longblob, constraint pk_tbytes_only primary key (id) ); -create sequence tbytes_only_seq; create table tcar ( type varchar(31) not null, - plate_no varchar(255) not null, + plate_no varchar(32) not null, truckload bigint, constraint pk_tcar primary key (plate_no) ); +create table tevent ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_tevent primary key (id) +); + +create table tevent_many ( + id bigint auto_increment not null, + description varchar(255), + event_id bigint, + units integer not null, + amount double not null, + version bigint not null, + constraint pk_tevent_many primary key (id) +); + +create table tevent_one ( + id bigint auto_increment not null, + name varchar(255), + status integer, + event_id bigint, + version bigint not null, + constraint ck_tevent_one_status check ( status in (0,1)), + constraint uq_tevent_one_event_id unique (event_id), + constraint pk_tevent_one primary key (id) +); + create table tint_root ( my_type integer(3) not null, - id integer not null, + id integer auto_increment not null, name varchar(255), child_property varchar(255), constraint pk_tint_root primary key (id) ); -create sequence tint_root_seq; create table tjoda_entity ( - id integer not null, + id integer auto_increment not null, local_time time, constraint pk_tjoda_entity primary key (id) ); -create sequence tjoda_entity_seq; create table t_mapsuper1 ( - id integer not null, + id integer auto_increment not null, something varchar(255), name varchar(255), version integer not null, constraint pk_t_mapsuper1 primary key (id) ); -create sequence t_mapsuper1_seq; create table t_oneb ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - active boolean, + active tinyint(1) default 0 not null, constraint pk_t_oneb primary key (id) ); -create sequence t_oneb_seq; create table t_detail_with_other_namexxxyy ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - active boolean, + some_unique_value varchar(127), + active tinyint(1) default 0 not null, master_id integer, - constraint pk_t_detail_with_other_namexx_0 primary key (id) + constraint uq_t_detail_with_other_namexxxyy_some_unique_value unique (some_unique_value), + constraint pk_t_detail_with_other_namexxxyy primary key (id) ); -create sequence t_atable_detail_seq; create table ts_detail_two ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - active boolean, + active tinyint(1) default 0 not null, master_id integer, constraint pk_ts_detail_two primary key (id) ); -create sequence ts_detail_two_seq; create table t_atable_thatisrelatively ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - active boolean, + active tinyint(1) default 0 not null, constraint pk_t_atable_thatisrelatively primary key (id) ); -create sequence t_atable_master_seq; create table ts_master_two ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), - active boolean, + active tinyint(1) default 0 not null, constraint pk_ts_master_two primary key (id) ); -create sequence ts_master_two_seq; create table tuuid_entity ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_tuuid_entity primary key (id) ); create table twheel ( - id bigint not null, - owner_plate_no varchar(255) not null, + id bigint auto_increment not null, + owner_plate_no varchar(32) not null, constraint pk_twheel primary key (id) ); -create sequence twheel_seq; create table twith_pre_insert ( - id integer not null, + id integer auto_increment not null, name varchar(255) not null, title varchar(255), constraint pk_twith_pre_insert primary key (id) ); -create sequence twith_pre_insert_seq; create table mt_tenant ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), version bigint not null, constraint pk_mt_tenant primary key (id) ); -create table sa_tire ( - id bigint not null, - version integer not null, - constraint pk_sa_tire primary key (id) +create table test_annotation_base_entity ( + direct varchar(255), + meta varchar(255), + mixed varchar(255), + constraint_annotation varchar(40), + null1 varchar(255) not null, + null2 varchar(255), + null3 varchar(255) ); -create sequence sa_tire_seq; create table tire ( - id bigint not null, + id bigint auto_increment not null, wheel bigint, version integer not null, constraint uq_tire_wheel unique (wheel), constraint pk_tire primary key (id) ); -create sequence tire_seq; + +create table sa_tire ( + id bigint auto_increment not null, + version integer not null, + constraint pk_sa_tire primary key (id) +); create table trip ( - id integer not null, + id integer auto_increment not null, vehicle_driver_id integer, destination varchar(255), address_id smallint, - star_date timestamp, - cretime timestamp not null, - updtime timestamp not null, + star_date datetime(6), + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_trip primary key (id) ); -create sequence trip_seq; create table truck_ref ( - id integer not null, + id integer auto_increment not null, something varchar(255), constraint pk_truck_ref primary key (id) ); -create sequence truck_ref_seq; create table type ( customer integer not null, @@ -1732,8 +2573,16 @@ create table type ( constraint pk_type primary key (customer,type) ); +create table tz_bean ( + id bigint auto_increment not null, + moda varchar(255), + ts datetime(6), + tstz datetime(6), + constraint pk_tz_bean primary key (id) +); + create table ut_detail ( - id integer not null, + id integer auto_increment not null, utmaster_id integer not null, name varchar(255), qty integer, @@ -1741,68 +2590,70 @@ create table ut_detail ( version integer not null, constraint pk_ut_detail primary key (id) ); -create sequence ut_detail_seq; create table ut_master ( - id integer not null, + id integer auto_increment not null, name varchar(255), description varchar(255), version integer not null, constraint pk_ut_master primary key (id) ); -create sequence ut_master_seq; create table uuone ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_uuone primary key (id) ); create table uutwo ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), - master_id binary(16), + master_id varchar(40), constraint pk_uutwo primary key (id) ); -create table em_user ( - id bigint not null, +create table c_user ( + id bigint auto_increment not null, + inactive tinyint(1) default 0 not null, name varchar(255), - constraint pk_em_user primary key (id) + email varchar(255), + password_hash varchar(255), + group_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_c_user primary key (id) ); -create sequence em_user_seq; create table tx_user ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), constraint pk_tx_user primary key (id) ); -create sequence tx_user_seq; -create table c_user ( - id bigint not null, - inactive boolean, - name varchar(255), - email varchar(255), - group_id bigint, +create table g_user ( + id bigint auto_increment not null, + username varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - constraint pk_c_user primary key (id) + constraint pk_g_user primary key (id) +); + +create table em_user ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_em_user primary key (id) ); -create sequence c_user_seq; create table oto_user ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), account_id bigint not null, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, constraint uq_oto_user_account_id unique (account_id), constraint pk_oto_user primary key (id) ); -create sequence oto_user_seq; create table em_user_role ( user_id bigint not null, @@ -1812,39 +2663,39 @@ create table em_user_role ( create table vehicle ( dtype varchar(3) not null, - id integer not null, + id integer auto_increment not null, license_number varchar(255), - registration_date timestamp, - cretime timestamp not null, - updtime timestamp not null, + registration_date datetime(6), + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, - truck_ref_id integer, - capacity double, + siz varchar(1), driver varchar(255), car_ref_id integer, + notes varchar(255), + truck_ref_id integer, + capacity double, + constraint ck_vehicle_siz check ( siz in ('S','M','L','H')), constraint pk_vehicle primary key (id) ); -create sequence vehicle_seq; create table vehicle_driver ( - id integer not null, + id integer auto_increment not null, name varchar(255), vehicle_id integer, address_id smallint, - license_issued_on timestamp, - cretime timestamp not null, - updtime timestamp not null, + license_issued_on datetime(6), + cretime datetime(6) not null, + updtime datetime(6) not null, version bigint not null, constraint pk_vehicle_driver primary key (id) ); -create sequence vehicle_driver_seq; create table warehouses ( - id integer not null, + id integer auto_increment not null, officezoneid integer, constraint pk_warehouses primary key (id) ); -create sequence warehouses_seq; create table warehousesshippingzones ( warehouseid integer not null, @@ -1853,394 +2704,757 @@ create table warehousesshippingzones ( ); create table sa_wheel ( - id bigint not null, + id bigint auto_increment not null, tire bigint, car bigint, version integer not null, constraint pk_sa_wheel primary key (id) ); -create sequence sa_wheel_seq; - -create table sp_car_wheel ( - id bigint not null, - version integer not null, - constraint pk_sp_car_wheel primary key (id) -); -create sequence sp_car_wheel_seq; create table wheel ( - id bigint not null, + id bigint auto_increment not null, version integer not null, constraint pk_wheel primary key (id) ); -create sequence wheel_seq; + +create table sp_car_wheel ( + id bigint auto_increment not null, + version integer not null, + constraint pk_sp_car_wheel primary key (id) +); + +create table g_who_props_otm ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + who_created_id bigint, + who_modified_id bigint, + constraint pk_g_who_props_otm primary key (id) +); create table with_zero ( - id bigint not null, + id bigint auto_increment not null, name varchar(255), parent_id integer, + lang varchar(2) default 'en' not null, version bigint not null, constraint pk_with_zero primary key (id) ); -create sequence with_zero_seq; create table parent ( - id integer not null, + id integer auto_increment not null, name varchar(255), constraint pk_parent primary key (id) ); -create sequence parent_seq; create table wview ( - id binary(16) not null, - name varchar(255) not null, + id varchar(40) not null, + name varchar(127) not null, constraint uq_wview_name unique (name), constraint pk_wview primary key (id) ); create table zones ( type varchar(31) not null, - id integer not null, + id integer auto_increment not null, attribute varchar(255), constraint pk_zones primary key (id) ); -create sequence zones_seq; -alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; +create index ix_contact_last_name_first_name on contact (last_name,first_name); +create index ix_e_basic_name on e_basic (name); create index ix_bar_foo_id on bar (foo_id); +alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; + +create index ix_addr_employee_id on addr (employee_id); +alter table addr add constraint fk_addr_employee_id foreign key (employee_id) references empl (id) on delete restrict on update restrict; -alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; create index ix_o_address_country_code on o_address (country_code); +alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; -alter table animals add constraint fk_animals_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; -create index ix_animals_shelter_id on animals (shelter_id); +alter table album add constraint fk_album_cover_id foreign key (cover_id) references cover (id) on delete restrict on update restrict; -alter table attribute add constraint fk_attribute_attribute_holder_1 foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; -create index ix_attribute_attribute_holder_1 on attribute (attribute_holder_id); +create index ix_animal_shelter_id on animal (shelter_id); +alter table animal add constraint fk_animal_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; + +create index ix_attribute_attribute_holder_id on attribute (attribute_holder_id); +alter table attribute add constraint fk_attribute_attribute_holder_id foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; -alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; create index ix_bbookmark_user_id on bbookmark (user_id); +alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; + +create index ix_bsite_user_site_id on bsite_user (site_id); +alter table bsite_user add constraint fk_bsite_user_site_id foreign key (site_id) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_user_id on bsite_user (user_id); +alter table bsite_user add constraint fk_bsite_user_user_id foreign key (user_id) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_site on bsite_user_b (site); +alter table bsite_user_b add constraint fk_bsite_user_b_site foreign key (site) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_usr on bsite_user_b (usr); +alter table bsite_user_b add constraint fk_bsite_user_b_usr foreign key (usr) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_site_uid on bsite_user_c (site_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_site_uid foreign key (site_uid) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_user_uid on bsite_user_c (user_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_user_uid foreign key (user_uid) references buser (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_agent_invoice foreign key (agent_invoice) references drel_invoice (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_client_invoice foreign key (client_invoice) references drel_invoice (id) on delete restrict on update restrict; -alter table ckey_detail add constraint fk_ckey_detail_ckey_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -create index ix_ckey_detail_one_key_two_key on ckey_detail (one_key,two_key); +create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); +alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_product_1 foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; -create index ix_calculation_result_product_1 on calculation_result (product_configuration_id); +create index ix_calculation_result_product_configuration_id on calculation_result (product_configuration_id); +alter table calculation_result add constraint fk_calculation_result_product_configuration_id foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_group_c_2 foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; -create index ix_calculation_result_group_c_2 on calculation_result (group_configuration_id); +create index ix_calculation_result_group_configuration_id on calculation_result (group_configuration_id); +alter table calculation_result add constraint fk_calculation_result_group_configuration_id foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; +create index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels (car); alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_car foreign key (car) references sp_car_car (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_car on sp_car_car_wheels (car); -alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_w_2 foreign key (wheel) references sp_car_wheel (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_wheel on sp_car_car_wheels (wheel); +create index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels (wheel); +alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_wheel foreign key (wheel) references sp_car_wheel (id) on delete restrict on update restrict; + +create index ix_car_accessory_fuse_id on car_accessory (fuse_id); +alter table car_accessory add constraint fk_car_accessory_fuse_id foreign key (fuse_id) references car_fuse (id) on delete restrict on update restrict; -alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; create index ix_car_accessory_car_id on car_accessory (car_id); +alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; -alter table configuration add constraint fk_configuration_configuratio_1 foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; -create index ix_configuration_configuratio_1 on configuration (configurations_id); +create index ix_category_surveyobjectid on category (surveyobjectid); +alter table category add constraint fk_category_surveyobjectid foreign key (surveyobjectid) references survey (id) on delete restrict on update restrict; + +create index ix_child_person_some_bean_id on child_person (some_bean_id); +alter table child_person add constraint fk_child_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_child_person_parent_identifier on child_person (parent_identifier); +alter table child_person add constraint fk_child_person_parent_identifier foreign key (parent_identifier) references parent_person (identifier) on delete restrict on update restrict; + +create index ix_configuration_configurations_id on configuration (configurations_id); +alter table configuration add constraint fk_configuration_configurations_id foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; create index ix_contact_customer_id on contact (customer_id); +alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; create index ix_contact_group_id on contact (group_id); +alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; -alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; create index ix_contact_note_contact_id on contact_note (contact_id); +alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; -alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_conversation_group_id on c_conversation (group_id); +alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_billing_address_1 foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; -create index ix_o_customer_billing_address_1 on o_customer (billing_address_id); +create index ix_o_customer_billing_address_id on o_customer (billing_address_id); +alter table o_customer add constraint fk_o_customer_billing_address_id foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_shipping_addres_2 foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; -create index ix_o_customer_shipping_addres_2 on o_customer (shipping_address_id); +create index ix_o_customer_shipping_address_id on o_customer (shipping_address_id); +alter table o_customer add constraint fk_o_customer_shipping_address_id foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_dcredit on dcredit_drol (dcredit_id); +alter table dcredit_drol add constraint fk_dcredit_drol_dcredit foreign key (dcredit_id) references dcredit (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_drol on dcredit_drol (drol_id); +alter table dcredit_drol add constraint fk_dcredit_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_drot_drol_drot on drot_drol (drot_id); +alter table drot_drol add constraint fk_drot_drol_drot foreign key (drot_id) references drot (id) on delete restrict on update restrict; + +create index ix_drot_drol_drol on drot_drol (drol_id); +alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_dfk_cascade_one_id on dfk_cascade (one_id); +alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade; + +create index ix_dfk_set_null_one_id on dfk_set_null (one_id); +alter table dfk_set_null add constraint fk_dfk_set_null_one_id foreign key (one_id) references dfk_one (id) on delete set null on update set null; + +alter table doc add constraint fk_doc_id foreign key (id) references doc_draft (id) on delete restrict on update restrict; + +create index ix_doc_link_doc on doc_link (doc_id); +alter table doc_link add constraint fk_doc_link_doc foreign key (doc_id) references doc (id) on delete restrict on update restrict; + +create index ix_doc_link_link on doc_link (link_id); +alter table doc_link add constraint fk_doc_link_link foreign key (link_id) references link (id) on delete restrict on update restrict; + +alter table document add constraint fk_document_id foreign key (id) references document_draft (id) on delete restrict on update restrict; + +create index ix_document_organisation_id on document (organisation_id); +alter table document add constraint fk_document_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_draft_organisation_id on document_draft (organisation_id); +alter table document_draft add constraint fk_document_draft_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_media_document_id on document_media (document_id); +alter table document_media add constraint fk_document_media_document_id foreign key (document_id) references document (id) on delete restrict on update restrict; + +create index ix_document_media_draft_document_id on document_media_draft (document_id); +alter table document_media_draft add constraint fk_document_media_draft_document_id foreign key (document_id) references document_draft (id) on delete restrict on update restrict; + +create index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail (owner_id); +alter table ebasic_json_map_detail add constraint fk_ebasic_json_map_detail_owner_id foreign key (owner_id) references ebasic_json_map (id) on delete restrict on update restrict; + +create index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild (owner_id); +alter table ebasic_no_sdchild add constraint fk_ebasic_no_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; + +create index ix_ebasic_sdchild_owner_id on ebasic_sdchild (owner_id); +alter table ebasic_sdchild add constraint fk_ebasic_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; -alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; create index ix_eemb_inner_outer_id on eemb_inner (outer_id); +alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; -alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; create index ix_einvoice_person_id on einvoice (person_id); +alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; -alter table enull_collection_detail add constraint fk_enull_collection_detail_en_1 foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; -create index ix_enull_collection_detail_en_1 on enull_collection_detail (enull_collection_id); +create index ix_enull_collection_detail_enull_collection_id on enull_collection_detail (enull_collection_id); +alter table enull_collection_detail add constraint fk_enull_collection_detail_enull_collection_id foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; -alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; create index ix_eopt_one_a_b_id on eopt_one_a (b_id); +alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; -alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; create index ix_eopt_one_b_c_id on eopt_one_b (c_id); +alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; -alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_1 foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; -create index ix_evanilla_collection_detail_1 on evanilla_collection_detail (evanilla_collection_id); +create index ix_esoft_del_book_lend_by_id on esoft_del_book (lend_by_id); +alter table esoft_del_book add constraint fk_esoft_del_book_lend_by_id foreign key (lend_by_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user (esoft_del_book_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_book foreign key (esoft_del_book_id) references esoft_del_book (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user (esoft_del_user_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down (esoft_del_mid_id); +alter table esoft_del_down add constraint fk_esoft_del_down_esoft_del_mid_id foreign key (esoft_del_mid_id) references esoft_del_mid (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_top_id on esoft_del_mid (top_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_top_id foreign key (top_id) references esoft_del_top (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_up_id on esoft_del_mid (up_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_up_id foreign key (up_id) references esoft_del_up (id) on delete restrict on update restrict; + +alter table esoft_del_one_a add constraint fk_esoft_del_one_a_oneb_id foreign key (oneb_id) references esoft_del_one_b (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user (esoft_del_role_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user (esoft_del_user_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role (esoft_del_user_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role (esoft_del_role_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_rawinherit_uncle_parent_id on rawinherit_uncle (parent_id); +alter table rawinherit_uncle add constraint fk_rawinherit_uncle_parent_id foreign key (parent_id) references rawinherit_parent (id) on delete restrict on update restrict; + +create index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail (evanilla_collection_id); +alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_evanilla_collection_id foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; -alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; create index ix_td_child_parent_id on td_child (parent_id); +alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; + +create index ix_empl_default_address_id on empl (default_address_id); +alter table empl add constraint fk_empl_default_address_id foreign key (default_address_id) references addr (id) on delete restrict on update restrict; + +create index ix_grand_parent_person_some_bean_id on grand_parent_person (some_bean_id); +alter table grand_parent_person add constraint fk_grand_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_survey_group_categoryobjectid on survey_group (categoryobjectid); +alter table survey_group add constraint fk_survey_group_categoryobjectid foreign key (categoryobjectid) references category (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_hx_link on hx_link_doc (hx_link_id); +alter table hx_link_doc add constraint fk_hx_link_doc_hx_link foreign key (hx_link_id) references hx_link (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_he_doc on hx_link_doc (he_doc_id); +alter table hx_link_doc add constraint fk_hx_link_doc_he_doc foreign key (he_doc_id) references he_doc (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_link on hi_link_doc (hi_link_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_link foreign key (hi_link_id) references hi_link (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_doc on hi_link_doc (hi_doc_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_doc foreign key (hi_doc_id) references hi_doc (id) on delete restrict on update restrict; -alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; create index ix_imrelated_owner_id on imrelated (owner_id); +alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; -alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; create index ix_info_contact_company_id on info_contact (company_id); +alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table info_customer add constraint fk_info_customer_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table inner_report add constraint fk_inner_report_forecast_id foreign key (forecast_id) references stockforecast (id) on delete restrict on update restrict; -alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; create index ix_drel_invoice_booking on drel_invoice (booking); +alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; -alter table item add constraint fk_item_type foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -create index ix_item_customer_type on item (customer,type); +create index ix_item_etype on item (customer,type); +alter table item add constraint fk_item_etype foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -alter table item add constraint fk_item_region foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; -create index ix_item_customer_region on item (customer,region); +create index ix_item_eregion on item (customer,region); +alter table item add constraint fk_item_eregion foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; +alter table trainer_monkey add constraint fk_trainer_monkey_trainer foreign key (trainer_tid) references trainer (tid) on delete restrict on update restrict; + +alter table trainer_monkey add constraint fk_trainer_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_troop foreign key (troop_pid) references troop (pid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +create index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child (parent_id); +alter table l2_cldf_reset_bean_child add constraint fk_l2_cldf_reset_bean_child_parent_id foreign key (parent_id) references l2_cldf_reset_bean (id) on delete restrict on update restrict; + +create index ix_level1_level4_level1 on level1_level4 (level1_id); alter table level1_level4 add constraint fk_level1_level4_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level4_level1_id on level1_level4 (level1_id); +create index ix_level1_level4_level4 on level1_level4 (level4_id); alter table level1_level4 add constraint fk_level1_level4_level4 foreign key (level4_id) references level4 (id) on delete restrict on update restrict; -create index ix_level1_level4_level4_id on level1_level4 (level4_id); +create index ix_level1_level2_level1 on level1_level2 (level1_id); alter table level1_level2 add constraint fk_level1_level2_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level2_level1_id on level1_level2 (level1_id); +create index ix_level1_level2_level2 on level1_level2 (level2_id); alter table level1_level2 add constraint fk_level1_level2_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level1_level2_level2_id on level1_level2 (level2_id); +create index ix_level2_level3_level2 on level2_level3 (level2_id); alter table level2_level3 add constraint fk_level2_level3_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level2_level3_level2_id on level2_level3 (level2_id); +create index ix_level2_level3_level3 on level2_level3 (level3_id); alter table level2_level3 add constraint fk_level2_level3_level3 foreign key (level3_id) references level3 (id) on delete restrict on update restrict; -create index ix_level2_level3_level3_id on level2_level3 (level3_id); -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_1 foreign key (la_attr_value_id) references la_attr_value (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_la_1 on la_attr_value_attribute (la_attr_value_id); +alter table link add constraint fk_link_id foreign key (id) references link_draft (id) on delete restrict on update restrict; -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_at_2 foreign key (attribute_id) references attribute (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_at_2 on la_attr_value_attribute (attribute_id); +create index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute (la_attr_value_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_attr_value foreign key (la_attr_value_id) references la_attr_value (id) on delete restrict on update restrict; + +create index ix_la_attr_value_attribute_attribute on la_attr_value_attribute (attribute_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_attribute foreign key (attribute_id) references attribute (id) on delete restrict on update restrict; -alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; create index ix_mprinter_current_state_id on mprinter (current_state_id); +alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_cyan_id foreign key (last_swap_cyan_id) references mprinter_state (id) on delete restrict on update restrict; -alter table mprinter add constraint fk_mprinter_last_swap_magenta_3 foreign key (last_swap_magenta_id) references mprinter_state (id) on delete restrict on update restrict; +alter table mprinter add constraint fk_mprinter_last_swap_magenta_id foreign key (last_swap_magenta_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_yellow_id foreign key (last_swap_yellow_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_black_id foreign key (last_swap_black_id) references mprinter_state (id) on delete restrict on update restrict; -alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; create index ix_mprinter_state_printer_id on mprinter_state (printer_id); +alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; -alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; create index ix_mprofile_picture_id on mprofile (picture_id); +alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; +create index ix_mrole_muser_mrole on mrole_muser (mrole_roleid); alter table mrole_muser add constraint fk_mrole_muser_mrole foreign key (mrole_roleid) references mrole (roleid) on delete restrict on update restrict; -create index ix_mrole_muser_mrole_roleid on mrole_muser (mrole_roleid); +create index ix_mrole_muser_muser on mrole_muser (muser_userid); alter table mrole_muser add constraint fk_mrole_muser_muser foreign key (muser_userid) references muser (userid) on delete restrict on update restrict; -create index ix_mrole_muser_muser_userid on mrole_muser (muser_userid); -alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; create index ix_muser_user_type_id on muser (user_type_id); +alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_user on mail_user_inbox (mail_user_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_box on mail_user_inbox (mail_box_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_user on mail_user_outbox (mail_user_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_box on mail_user_outbox (mail_box_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; create index ix_c_message_conversation_id on c_message (conversation_id); +alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_message_user_id on c_message (user_id); +alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_u_1 foreign key (mnoc_user_user_id) references mnoc_user (user_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_u_1 on mnoc_user_mnoc_role (mnoc_user_user_id); +create index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role (mnoc_user_user_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_user foreign key (mnoc_user_user_id) references mnoc_user (user_id) on delete restrict on update restrict; -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_r_2 foreign key (mnoc_role_role_id) references mnoc_role (role_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_r_2 on mnoc_user_mnoc_role (mnoc_role_role_id); +create index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role (mnoc_role_role_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_role foreign key (mnoc_role_role_id) references mnoc_role (role_id) on delete restrict on update restrict; + +create index ix_mny_b_a_id on mny_b (a_id); +alter table mny_b add constraint fk_mny_b_a_id foreign key (a_id) references mny_a (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_b on mny_b_mny_c (mny_b_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_b foreign key (mny_b_id) references mny_b (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_c on mny_b_mny_c (mny_c_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_c foreign key (mny_c_id) references mny_c (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_1 on subtopics (topic); +alter table subtopics add constraint fk_subtopics_mny_topic_1 foreign key (topic) references mny_topic (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_2 on subtopics (subtopic); +alter table subtopics add constraint fk_subtopics_mny_topic_2 foreign key (subtopic) references mny_topic (id) on delete restrict on update restrict; -alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; create index ix_mp_role_mp_user_id on mp_role (mp_user_id); +alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; -alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_pare_1 foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; -create index ix_my_lob_size_join_many_pare_1 on my_lob_size_join_many (parent_id); +create index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b (ms_many_a_aid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_ca_1 foreign key (o_cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_ca_1 on o_cached_bean_country (o_cached_bean_id); +create index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b (ms_many_b_bid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_co_2 foreign key (o_country_code) references o_country (code) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_co_2 on o_cached_bean_country (o_country_code); +create index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a (ms_many_b_bid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; -alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_1 foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; -create index ix_o_cached_bean_child_cached_1 on o_cached_bean_child (cached_bean_id); +create index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a (ms_many_a_aid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; + +create index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many (parent_id); +alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_parent_id foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; + +create index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country (o_cached_bean_id); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_cached_bean foreign key (o_cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; + +create index ix_o_cached_bean_country_o_country on o_cached_bean_country (o_country_code); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_country foreign key (o_country_code) references o_country (code) on delete restrict on update restrict; + +create index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child (cached_bean_id); +alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_bean_id foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; alter table oengine add constraint fk_oengine_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; alter table ogear_box add constraint fk_ogear_box_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; -alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; +alter table oroad_show_msg add constraint fk_oroad_show_msg_company_id foreign key (company_id) references ocompany (id) on delete restrict on update restrict; + +create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id); +alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id) on delete restrict on update restrict; + create index ix_o_order_kcustomer_id on o_order (kcustomer_id); +alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_o_order_detail_order_id on o_order_detail (order_id); +alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; create index ix_o_order_detail_product_id on o_order_detail (product_id); +alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; -alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; create index ix_s_order_items_order_uuid on s_order_items (order_uuid); +alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; -alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_or_order_ship_order_id on or_order_ship (order_id); +alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; + +alter table oto_bchild add constraint fk_oto_bchild_master_id foreign key (master_id) references oto_bmaster (id) on delete restrict on update restrict; alter table oto_child add constraint fk_oto_child_master_id foreign key (master_id) references oto_master (id) on delete restrict on update restrict; +alter table oto_cust_address add constraint fk_oto_cust_address_customer_cid foreign key (customer_cid) references oto_cust (cid) on delete restrict on update restrict; + +alter table oto_prime_extra add constraint fk_oto_prime_extra_eid foreign key (eid) references oto_prime (pid) on delete restrict on update restrict; + +create index ix_oto_th_many_oto_th_top_id on oto_th_many (oto_th_top_id); +alter table oto_th_many add constraint fk_oto_th_many_oto_th_top_id foreign key (oto_th_top_id) references oto_th_top (id) on delete restrict on update restrict; + +alter table oto_th_one add constraint fk_oto_th_one_many_id foreign key (many_id) references oto_th_many (id) on delete restrict on update restrict; + +alter table oto_ubprime_extra add constraint fk_oto_ubprime_extra_eid foreign key (eid) references oto_ubprime (pid) on delete restrict on update restrict; + +alter table oto_uprime_extra add constraint fk_oto_uprime_extra_eid foreign key (eid) references oto_uprime (pid) on delete restrict on update restrict; + alter table pfile add constraint fk_pfile_file_content_id foreign key (file_content_id) references pfile_content (id) on delete restrict on update restrict; alter table pfile add constraint fk_pfile_file_content2_id foreign key (file_content2_id) references pfile_content (id) on delete restrict on update restrict; alter table paggview add constraint fk_paggview_pview_id foreign key (pview_id) references pp (id) on delete restrict on update restrict; -alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; create index ix_pallet_location_zone_sid on pallet_location (zone_sid); +alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; alter table parcel_location add constraint fk_parcel_location_parcelid foreign key (parcelid) references parcel (parcelid) on delete restrict on update restrict; -alter table rawinherit_parent_rawinherit_dat add constraint fk_rawinherit_parent_rawinher_1 foreign key (rawinherit_parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinher_1 on rawinherit_parent_rawinherit_dat (rawinherit_parent_id); +create index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data (rawinherit_parent_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_parent foreign key (rawinherit_parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -alter table rawinherit_parent_rawinherit_dat add constraint fk_rawinherit_parent_rawinher_2 foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinher_2 on rawinherit_parent_rawinherit_dat (rawinherit_data_id); +create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict; -alter table c_participation add constraint fk_c_participation_conversati_1 foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -create index ix_c_participation_conversati_1 on c_participation (conversation_id); +create index ix_parent_person_some_bean_id on parent_person (some_bean_id); +alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_parent_person_parent_identifier on parent_person (parent_identifier); +alter table parent_person add constraint fk_parent_person_parent_identifier foreign key (parent_identifier) references grand_parent_person (identifier) on delete restrict on update restrict; + +create index ix_c_participation_conversation_id on c_participation (conversation_id); +alter table c_participation add constraint fk_c_participation_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_participation_user_id on c_participation (user_id); +alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; -alter table persistent_file_content add constraint fk_persistent_file_content_pe_1 foreign key (persistent_file_id) references persistent_file (id) on delete restrict on update restrict; +alter table persistent_file_content add constraint fk_persistent_file_content_persistent_file_id foreign key (persistent_file_id) references persistent_file (id) on delete restrict on update restrict; -alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; create index ix_person_default_address_oid on person (default_address_oid); +alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; -alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; +create index ix_pp_to_ww_pp on pp_to_ww (pp_id); alter table pp_to_ww add constraint fk_pp_to_ww_pp foreign key (pp_id) references pp (id) on delete restrict on update restrict; -create index ix_pp_to_ww_pp_id on pp_to_ww (pp_id); +create index ix_pp_to_ww_wview on pp_to_ww (ww_id); alter table pp_to_ww add constraint fk_pp_to_ww_wview foreign key (ww_id) references wview (id) on delete restrict on update restrict; -create index ix_pp_to_ww_ww_id on pp_to_ww (ww_id); -alter table r_orders add constraint fk_r_orders_rcustomer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; -create index ix_r_orders_company_customern_1 on r_orders (company,customername); +create index ix_question_groupobjectid on question (groupobjectid); +alter table question add constraint fk_question_groupobjectid foreign key (groupobjectid) references survey_group (id) on delete restrict on update restrict; -alter table resourcefile add constraint fk_resourcefile_parentresourc_1 foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; -create index ix_resourcefile_parentresourc_1 on resourcefile (parentresourcefileid); +create index ix_r_orders_customer on r_orders (company,customername); +alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; + +create index ix_resourcefile_parentresourcefileid on resourcefile (parentresourcefileid); +alter table resourcefile add constraint fk_resourcefile_parentresourcefileid foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; -alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; create index ix_mt_role_tenant_id on mt_role (tenant_id); +alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; +create index ix_mt_role_permission_mt_role on mt_role_permission (mt_role_id); alter table mt_role_permission add constraint fk_mt_role_permission_mt_role foreign key (mt_role_id) references mt_role (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_role_1 on mt_role_permission (mt_role_id); -alter table mt_role_permission add constraint fk_mt_role_permission_mt_perm_2 foreign key (mt_permission_id) references mt_permission (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_perm_2 on mt_role_permission (mt_permission_id); +create index ix_mt_role_permission_mt_permission on mt_role_permission (mt_permission_id); +alter table mt_role_permission add constraint fk_mt_role_permission_mt_permission foreign key (mt_permission_id) references mt_permission (id) on delete restrict on update restrict; alter table f_second add constraint fk_f_second_first foreign key (first) references f_first (id) on delete restrict on update restrict; -alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; create index ix_section_article_id on section (article_id); +alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; -alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; create index ix_self_parent_parent_id on self_parent (parent_id); +alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; -alter table self_ref_customer add constraint fk_self_ref_customer_referred_1 foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; -create index ix_self_ref_customer_referred_1 on self_ref_customer (referred_by_id); +create index ix_self_ref_customer_referred_by_id on self_ref_customer (referred_by_id); +alter table self_ref_customer add constraint fk_self_ref_customer_referred_by_id foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; -alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; create index ix_self_ref_example_parent_id on self_ref_example (parent_id); +alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; -alter table stockforecast add constraint fk_stockforecast_inner_report_1 foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; -create index ix_stockforecast_inner_report_1 on stockforecast (inner_report_id); +create index ix_stockforecast_inner_report_id on stockforecast (inner_report_id); +alter table stockforecast add constraint fk_stockforecast_inner_report_id foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; -alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; create index ix_sub_section_section_id on sub_section (section_id); +alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; -alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexx_1 foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; -create index ix_t_detail_with_other_namexx_1 on t_detail_with_other_namexxxyy (master_id); +create index ix_tevent_many_event_id on tevent_many (event_id); +alter table tevent_many add constraint fk_tevent_many_event_id foreign key (event_id) references tevent_one (id) on delete restrict on update restrict; + +alter table tevent_one add constraint fk_tevent_one_event_id foreign key (event_id) references tevent (id) on delete restrict on update restrict; + +create index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy (master_id); +alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexxxyy_master_id foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; -alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; create index ix_ts_detail_two_master_id on ts_detail_two (master_id); +alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; -alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; create index ix_twheel_owner_plate_no on twheel (owner_plate_no); +alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; alter table tire add constraint fk_tire_wheel foreign key (wheel) references wheel (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; create index ix_trip_vehicle_driver_id on trip (vehicle_driver_id); +alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_trip_address_id on trip (address_id); +alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; create index ix_type_sub_type_id on type (sub_type_id); +alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; -alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; create index ix_ut_detail_utmaster_id on ut_detail (utmaster_id); +alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; -alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; create index ix_uutwo_master_id on uutwo (master_id); +alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; -alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_user_group_id on c_user (group_id); +alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; alter table oto_user add constraint fk_oto_user_account_id foreign key (account_id) references oto_account (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; create index ix_em_user_role_user_id on em_user_role (user_id); +alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; create index ix_em_user_role_role_id on em_user_role (role_id); +alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; -alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); - -alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; create index ix_vehicle_car_ref_id on vehicle (car_ref_id); +alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; + +create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); +alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; create index ix_vehicle_driver_vehicle_id on vehicle_driver (vehicle_id); +alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_vehicle_driver_address_id on vehicle_driver (address_id); +alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; create index ix_warehouses_officezoneid on warehouses (officezoneid); +alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; -alter table warehousesshippingzones add constraint fk_warehousesshippingzones_wa_1 foreign key (warehouseid) references warehouses (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_wa_1 on warehousesshippingzones (warehouseid); +create index ix_warehousesshippingzones_warehouses on warehousesshippingzones (warehouseid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_warehouses foreign key (warehouseid) references warehouses (id) on delete restrict on update restrict; -alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zo_2 foreign key (shippingzoneid) references zones (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_sh_2 on warehousesshippingzones (shippingzoneid); +create index ix_warehousesshippingzones_zones on warehousesshippingzones (shippingzoneid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zones foreign key (shippingzoneid) references zones (id) on delete restrict on update restrict; -alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; create index ix_sa_wheel_tire on sa_wheel (tire); +alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; -alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; create index ix_sa_wheel_car on sa_wheel (car); +alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_created_id on g_who_props_otm (who_created_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_created_id foreign key (who_created_id) references g_user (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_modified_id on g_who_props_otm (who_modified_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_modified_id foreign key (who_modified_id) references g_user (id) on delete restrict on update restrict; -alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; create index ix_with_zero_parent_id on with_zero (parent_id); +alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; +alter table hx_link add column sys_period_start datetime(6) default now(6); +alter table hx_link add column sys_period_end datetime(6); +update hx_link set sys_period_start = when_created; +create table hx_link_history( + id bigint, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hx_link_with_history as select * from hx_link union all select * from hx_link_history; + +delimiter $$ +create trigger hx_link_history_upd before update on hx_link for each row begin + insert into hx_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hx_link_history_del before delete on hx_link for each row begin + insert into hx_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); +end$$ +alter table hi_link add column sys_period_start datetime(6) default now(6); +alter table hi_link add column sys_period_end datetime(6); +update hi_link set sys_period_start = when_created; +create table hi_link_history( + id bigint, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hi_link_with_history as select * from hi_link union all select * from hi_link_history; + +delimiter $$ +create trigger hi_link_history_upd before update on hi_link for each row begin + insert into hi_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hi_link_history_del before delete on hi_link for each row begin + insert into hi_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); +end$$ +alter table hi_link_doc add column sys_period_start datetime(6) default now(6); +alter table hi_link_doc add column sys_period_end datetime(6); +create table hi_link_doc_history( + hi_link_id bigint, + hi_doc_id bigint, + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hi_link_doc_with_history as select * from hi_link_doc union all select * from hi_link_doc_history; + +delimiter $$ +create trigger hi_link_doc_history_upd before update on hi_link_doc for each row begin + insert into hi_link_doc_history (sys_period_start,sys_period_end,hi_link_id, hi_doc_id) values (OLD.sys_period_start, now(6),OLD.hi_link_id, OLD.hi_doc_id); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hi_link_doc_history_del before delete on hi_link_doc for each row begin + insert into hi_link_doc_history (sys_period_start,sys_period_end,hi_link_id, hi_doc_id) values (OLD.sys_period_start, now(6),OLD.hi_link_id, OLD.hi_doc_id); +end$$ +alter table link add column sys_period_start datetime(6) default now(6); +alter table link add column sys_period_end datetime(6); +update link set sys_period_start = when_created; +create table link_history( + id bigint, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + deleted tinyint(1), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view link_with_history as select * from link union all select * from link_history; + +delimiter $$ +create trigger link_history_upd before update on link for each row begin + insert into link_history (sys_period_start,sys_period_end,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger link_history_del before delete on link for each row begin + insert into link_history (sys_period_start,sys_period_end,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); +end$$ +alter table c_user add column sys_period_start datetime(6) default now(6); +alter table c_user add column sys_period_end datetime(6); +update c_user set sys_period_start = when_created; +create table c_user_history( + id bigint, + inactive tinyint(1), + name varchar(255), + email varchar(255), + password_hash varchar(255), + group_id bigint, + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view c_user_with_history as select * from c_user union all select * from c_user_history; + +delimiter $$ +create trigger c_user_history_upd before update on c_user for each row begin + insert into c_user_history (sys_period_start,sys_period_end,id, inactive, name, email, group_id, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger c_user_history_del before delete on c_user for each row begin + insert into c_user_history (sys_period_start,sys_period_end,id, inactive, name, email, group_id, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); +end$$ diff --git a/src/test/ddl-review/h2-drop-all.sql b/src/test/ddl-review/h2-drop-all.sql index 080923655..1113deffc 100644 --- a/src/test/ddl-review/h2-drop-all.sql +++ b/src/test/ddl-review/h2-drop-all.sql @@ -1,780 +1,1140 @@ -alter table bar drop constraint fk_bar_foo_id; -drop index ix_bar_foo_id; +-- Generated by ebean unknown at 2018-03-08T06:41:41.155Z +alter table bar drop foreign key fk_bar_foo_id; +drop index ix_bar_foo_id on bar; -alter table o_address drop constraint fk_o_address_country_code; -drop index ix_o_address_country_code; +alter table addr drop foreign key fk_addr_employee_id; +drop index ix_addr_employee_id on addr; -alter table animals drop constraint fk_animals_shelter_id; -drop index ix_animals_shelter_id; +alter table o_address drop foreign key fk_o_address_country_code; +drop index ix_o_address_country_code on o_address; -alter table attribute drop constraint fk_attribute_attribute_holder_1; -drop index ix_attribute_attribute_holder_1; +alter table album drop foreign key fk_album_cover_id; -alter table bbookmark drop constraint fk_bbookmark_user_id; -drop index ix_bbookmark_user_id; +alter table animal drop foreign key fk_animal_shelter_id; +drop index ix_animal_shelter_id on animal; -alter table drel_booking drop constraint fk_drel_booking_agent_invoice; +alter table attribute drop foreign key fk_attribute_attribute_holder_id; +drop index ix_attribute_attribute_holder_id on attribute; -alter table drel_booking drop constraint fk_drel_booking_client_invoice; +alter table bbookmark drop foreign key fk_bbookmark_user_id; +drop index ix_bbookmark_user_id on bbookmark; -alter table ckey_detail drop constraint fk_ckey_detail_ckey_parent; -drop index ix_ckey_detail_one_key_two_key; +alter table bsite_user drop foreign key fk_bsite_user_site_id; +drop index ix_bsite_user_site_id on bsite_user; -alter table ckey_parent drop constraint fk_ckey_parent_assoc_id; -drop index ix_ckey_parent_assoc_id; +alter table bsite_user drop foreign key fk_bsite_user_user_id; +drop index ix_bsite_user_user_id on bsite_user; -alter table calculation_result drop constraint fk_calculation_result_product_1; -drop index ix_calculation_result_product_1; +alter table bsite_user_b drop foreign key fk_bsite_user_b_site; +drop index ix_bsite_user_b_site on bsite_user_b; -alter table calculation_result drop constraint fk_calculation_result_group_c_2; -drop index ix_calculation_result_group_c_2; +alter table bsite_user_b drop foreign key fk_bsite_user_b_usr; +drop index ix_bsite_user_b_usr on bsite_user_b; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_car; -drop index ix_sp_car_car_wheels_car; +alter table bsite_user_c drop foreign key fk_bsite_user_c_site_uid; +drop index ix_bsite_user_c_site_uid on bsite_user_c; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_w_2; -drop index ix_sp_car_car_wheels_wheel; +alter table bsite_user_c drop foreign key fk_bsite_user_c_user_uid; +drop index ix_bsite_user_c_user_uid on bsite_user_c; -alter table car_accessory drop constraint fk_car_accessory_car_id; -drop index ix_car_accessory_car_id; +alter table drel_booking drop foreign key fk_drel_booking_agent_invoice; -alter table configuration drop constraint fk_configuration_configuratio_1; -drop index ix_configuration_configuratio_1; +alter table drel_booking drop foreign key fk_drel_booking_client_invoice; -alter table contact drop constraint fk_contact_customer_id; -drop index ix_contact_customer_id; +alter table ckey_detail drop foreign key fk_ckey_detail_parent; +drop index ix_ckey_detail_parent on ckey_detail; -alter table contact drop constraint fk_contact_group_id; -drop index ix_contact_group_id; +alter table ckey_parent drop foreign key fk_ckey_parent_assoc_id; +drop index ix_ckey_parent_assoc_id on ckey_parent; -alter table contact_note drop constraint fk_contact_note_contact_id; -drop index ix_contact_note_contact_id; +alter table calculation_result drop foreign key fk_calculation_result_product_configuration_id; +drop index ix_calculation_result_product_configuration_id on calculation_result; -alter table c_conversation drop constraint fk_c_conversation_group_id; -drop index ix_c_conversation_group_id; +alter table calculation_result drop foreign key fk_calculation_result_group_configuration_id; +drop index ix_calculation_result_group_configuration_id on calculation_result; -alter table o_customer drop constraint fk_o_customer_billing_address_1; -drop index ix_o_customer_billing_address_1; +alter table sp_car_car_wheels drop foreign key fk_sp_car_car_wheels_sp_car_car; +drop index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels; -alter table o_customer drop constraint fk_o_customer_shipping_addres_2; -drop index ix_o_customer_shipping_addres_2; +alter table sp_car_car_wheels drop foreign key fk_sp_car_car_wheels_sp_car_wheel; +drop index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels; -alter table eemb_inner drop constraint fk_eemb_inner_outer_id; -drop index ix_eemb_inner_outer_id; +alter table car_accessory drop foreign key fk_car_accessory_fuse_id; +drop index ix_car_accessory_fuse_id on car_accessory; -alter table einvoice drop constraint fk_einvoice_person_id; -drop index ix_einvoice_person_id; +alter table car_accessory drop foreign key fk_car_accessory_car_id; +drop index ix_car_accessory_car_id on car_accessory; -alter table enull_collection_detail drop constraint fk_enull_collection_detail_en_1; -drop index ix_enull_collection_detail_en_1; +alter table category drop foreign key fk_category_surveyobjectid; +drop index ix_category_surveyobjectid on category; -alter table eopt_one_a drop constraint fk_eopt_one_a_b_id; -drop index ix_eopt_one_a_b_id; +alter table child_person drop foreign key fk_child_person_some_bean_id; +drop index ix_child_person_some_bean_id on child_person; -alter table eopt_one_b drop constraint fk_eopt_one_b_c_id; -drop index ix_eopt_one_b_c_id; +alter table child_person drop foreign key fk_child_person_parent_identifier; +drop index ix_child_person_parent_identifier on child_person; -alter table evanilla_collection_detail drop constraint fk_evanilla_collection_detail_1; -drop index ix_evanilla_collection_detail_1; +alter table configuration drop foreign key fk_configuration_configurations_id; +drop index ix_configuration_configurations_id on configuration; -alter table td_child drop constraint fk_td_child_parent_id; -drop index ix_td_child_parent_id; +alter table contact drop foreign key fk_contact_customer_id; +drop index ix_contact_customer_id on contact; -alter table imrelated drop constraint fk_imrelated_owner_id; -drop index ix_imrelated_owner_id; +alter table contact drop foreign key fk_contact_group_id; +drop index ix_contact_group_id on contact; -alter table info_contact drop constraint fk_info_contact_company_id; -drop index ix_info_contact_company_id; +alter table contact_note drop foreign key fk_contact_note_contact_id; +drop index ix_contact_note_contact_id on contact_note; -alter table info_customer drop constraint fk_info_customer_company_id; +alter table c_conversation drop foreign key fk_c_conversation_group_id; +drop index ix_c_conversation_group_id on c_conversation; -alter table inner_report drop constraint fk_inner_report_forecast_id; +alter table o_customer drop foreign key fk_o_customer_billing_address_id; +drop index ix_o_customer_billing_address_id on o_customer; -alter table drel_invoice drop constraint fk_drel_invoice_booking; -drop index ix_drel_invoice_booking; +alter table o_customer drop foreign key fk_o_customer_shipping_address_id; +drop index ix_o_customer_shipping_address_id on o_customer; -alter table item drop constraint fk_item_type; -drop index ix_item_customer_type; +alter table dcredit_drol drop foreign key fk_dcredit_drol_dcredit; +drop index ix_dcredit_drol_dcredit on dcredit_drol; -alter table item drop constraint fk_item_region; -drop index ix_item_customer_region; +alter table dcredit_drol drop foreign key fk_dcredit_drol_drol; +drop index ix_dcredit_drol_drol on dcredit_drol; -alter table level1_level4 drop constraint fk_level1_level4_level1; -drop index ix_level1_level4_level1_id; +alter table drot_drol drop foreign key fk_drot_drol_drot; +drop index ix_drot_drol_drot on drot_drol; -alter table level1_level4 drop constraint fk_level1_level4_level4; -drop index ix_level1_level4_level4_id; +alter table drot_drol drop foreign key fk_drot_drol_drol; +drop index ix_drot_drol_drol on drot_drol; -alter table level1_level2 drop constraint fk_level1_level2_level1; -drop index ix_level1_level2_level1_id; +alter table dfk_cascade drop foreign key fk_dfk_cascade_one_id; +drop index ix_dfk_cascade_one_id on dfk_cascade; -alter table level1_level2 drop constraint fk_level1_level2_level2; -drop index ix_level1_level2_level2_id; +alter table dfk_set_null drop foreign key fk_dfk_set_null_one_id; +drop index ix_dfk_set_null_one_id on dfk_set_null; -alter table level2_level3 drop constraint fk_level2_level3_level2; -drop index ix_level2_level3_level2_id; +alter table doc drop foreign key fk_doc_id; -alter table level2_level3 drop constraint fk_level2_level3_level3; -drop index ix_level2_level3_level3_id; +alter table doc_link drop foreign key fk_doc_link_doc; +drop index ix_doc_link_doc on doc_link; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_la_1; -drop index ix_la_attr_value_attribute_la_1; +alter table doc_link drop foreign key fk_doc_link_link; +drop index ix_doc_link_link on doc_link; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_at_2; -drop index ix_la_attr_value_attribute_at_2; +alter table document drop foreign key fk_document_id; -alter table mprinter drop constraint fk_mprinter_current_state_id; -drop index ix_mprinter_current_state_id; +alter table document drop foreign key fk_document_organisation_id; +drop index ix_document_organisation_id on document; -alter table mprinter drop constraint fk_mprinter_last_swap_cyan_id; +alter table document_draft drop foreign key fk_document_draft_organisation_id; +drop index ix_document_draft_organisation_id on document_draft; -alter table mprinter drop constraint fk_mprinter_last_swap_magenta_3; +alter table document_media drop foreign key fk_document_media_document_id; +drop index ix_document_media_document_id on document_media; -alter table mprinter drop constraint fk_mprinter_last_swap_yellow_id; +alter table document_media_draft drop foreign key fk_document_media_draft_document_id; +drop index ix_document_media_draft_document_id on document_media_draft; -alter table mprinter drop constraint fk_mprinter_last_swap_black_id; +alter table ebasic_json_map_detail drop foreign key fk_ebasic_json_map_detail_owner_id; +drop index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail; -alter table mprinter_state drop constraint fk_mprinter_state_printer_id; -drop index ix_mprinter_state_printer_id; +alter table ebasic_no_sdchild drop foreign key fk_ebasic_no_sdchild_owner_id; +drop index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild; -alter table mprofile drop constraint fk_mprofile_picture_id; -drop index ix_mprofile_picture_id; +alter table ebasic_sdchild drop foreign key fk_ebasic_sdchild_owner_id; +drop index ix_ebasic_sdchild_owner_id on ebasic_sdchild; -alter table mrole_muser drop constraint fk_mrole_muser_mrole; -drop index ix_mrole_muser_mrole_roleid; +alter table eemb_inner drop foreign key fk_eemb_inner_outer_id; +drop index ix_eemb_inner_outer_id on eemb_inner; -alter table mrole_muser drop constraint fk_mrole_muser_muser; -drop index ix_mrole_muser_muser_userid; +alter table einvoice drop foreign key fk_einvoice_person_id; +drop index ix_einvoice_person_id on einvoice; -alter table muser drop constraint fk_muser_user_type_id; -drop index ix_muser_user_type_id; +alter table enull_collection_detail drop foreign key fk_enull_collection_detail_enull_collection_id; +drop index ix_enull_collection_detail_enull_collection_id on enull_collection_detail; -alter table c_message drop constraint fk_c_message_conversation_id; -drop index ix_c_message_conversation_id; +alter table eopt_one_a drop foreign key fk_eopt_one_a_b_id; +drop index ix_eopt_one_a_b_id on eopt_one_a; -alter table c_message drop constraint fk_c_message_user_id; -drop index ix_c_message_user_id; +alter table eopt_one_b drop foreign key fk_eopt_one_b_c_id; +drop index ix_eopt_one_b_c_id on eopt_one_b; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_u_1; -drop index ix_mnoc_user_mnoc_role_mnoc_u_1; +alter table esoft_del_book drop foreign key fk_esoft_del_book_lend_by_id; +drop index ix_esoft_del_book_lend_by_id on esoft_del_book; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_r_2; -drop index ix_mnoc_user_mnoc_role_mnoc_r_2; +alter table esoft_del_book_esoft_del_user drop foreign key fk_esoft_del_book_esoft_del_user_esoft_del_book; +drop index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user; -alter table mp_role drop constraint fk_mp_role_mp_user_id; -drop index ix_mp_role_mp_user_id; +alter table esoft_del_book_esoft_del_user drop foreign key fk_esoft_del_book_esoft_del_user_esoft_del_user; +drop index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user; -alter table my_lob_size_join_many drop constraint fk_my_lob_size_join_many_pare_1; -drop index ix_my_lob_size_join_many_pare_1; +alter table esoft_del_down drop foreign key fk_esoft_del_down_esoft_del_mid_id; +drop index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_ca_1; -drop index ix_o_cached_bean_country_o_ca_1; +alter table esoft_del_mid drop foreign key fk_esoft_del_mid_top_id; +drop index ix_esoft_del_mid_top_id on esoft_del_mid; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_co_2; -drop index ix_o_cached_bean_country_o_co_2; +alter table esoft_del_mid drop foreign key fk_esoft_del_mid_up_id; +drop index ix_esoft_del_mid_up_id on esoft_del_mid; -alter table o_cached_bean_child drop constraint fk_o_cached_bean_child_cached_1; -drop index ix_o_cached_bean_child_cached_1; +alter table esoft_del_one_a drop foreign key fk_esoft_del_one_a_oneb_id; -alter table oengine drop constraint fk_oengine_car_id; +alter table esoft_del_role_esoft_del_user drop foreign key fk_esoft_del_role_esoft_del_user_esoft_del_role; +drop index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user; -alter table ogear_box drop constraint fk_ogear_box_car_id; +alter table esoft_del_role_esoft_del_user drop foreign key fk_esoft_del_role_esoft_del_user_esoft_del_user; +drop index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user; -alter table o_order drop constraint fk_o_order_kcustomer_id; -drop index ix_o_order_kcustomer_id; +alter table esoft_del_user_esoft_del_role drop foreign key fk_esoft_del_user_esoft_del_role_esoft_del_user; +drop index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role; -alter table o_order_detail drop constraint fk_o_order_detail_order_id; -drop index ix_o_order_detail_order_id; +alter table esoft_del_user_esoft_del_role drop foreign key fk_esoft_del_user_esoft_del_role_esoft_del_role; +drop index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role; -alter table o_order_detail drop constraint fk_o_order_detail_product_id; -drop index ix_o_order_detail_product_id; +alter table rawinherit_uncle drop foreign key fk_rawinherit_uncle_parent_id; +drop index ix_rawinherit_uncle_parent_id on rawinherit_uncle; -alter table s_order_items drop constraint fk_s_order_items_order_uuid; -drop index ix_s_order_items_order_uuid; +alter table evanilla_collection_detail drop foreign key fk_evanilla_collection_detail_evanilla_collection_id; +drop index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail; -alter table or_order_ship drop constraint fk_or_order_ship_order_id; -drop index ix_or_order_ship_order_id; +alter table td_child drop foreign key fk_td_child_parent_id; +drop index ix_td_child_parent_id on td_child; -alter table oto_child drop constraint fk_oto_child_master_id; +alter table empl drop foreign key fk_empl_default_address_id; +drop index ix_empl_default_address_id on empl; -alter table pfile drop constraint fk_pfile_file_content_id; +alter table grand_parent_person drop foreign key fk_grand_parent_person_some_bean_id; +drop index ix_grand_parent_person_some_bean_id on grand_parent_person; -alter table pfile drop constraint fk_pfile_file_content2_id; +alter table survey_group drop foreign key fk_survey_group_categoryobjectid; +drop index ix_survey_group_categoryobjectid on survey_group; -alter table paggview drop constraint fk_paggview_pview_id; +alter table hx_link_doc drop foreign key fk_hx_link_doc_hx_link; +drop index ix_hx_link_doc_hx_link on hx_link_doc; -alter table pallet_location drop constraint fk_pallet_location_zone_sid; -drop index ix_pallet_location_zone_sid; +alter table hx_link_doc drop foreign key fk_hx_link_doc_he_doc; +drop index ix_hx_link_doc_he_doc on hx_link_doc; -alter table parcel_location drop constraint fk_parcel_location_parcelid; +alter table hi_link_doc drop foreign key fk_hi_link_doc_hi_link; +drop index ix_hi_link_doc_hi_link on hi_link_doc; -alter table rawinherit_parent_rawinherit_dat drop constraint fk_rawinherit_parent_rawinher_1; -drop index ix_rawinherit_parent_rawinher_1; +alter table hi_link_doc drop foreign key fk_hi_link_doc_hi_doc; +drop index ix_hi_link_doc_hi_doc on hi_link_doc; -alter table rawinherit_parent_rawinherit_dat drop constraint fk_rawinherit_parent_rawinher_2; -drop index ix_rawinherit_parent_rawinher_2; +alter table imrelated drop foreign key fk_imrelated_owner_id; +drop index ix_imrelated_owner_id on imrelated; -alter table c_participation drop constraint fk_c_participation_conversati_1; -drop index ix_c_participation_conversati_1; +alter table info_contact drop foreign key fk_info_contact_company_id; +drop index ix_info_contact_company_id on info_contact; -alter table c_participation drop constraint fk_c_participation_user_id; -drop index ix_c_participation_user_id; +alter table info_customer drop foreign key fk_info_customer_company_id; -alter table persistent_file_content drop constraint fk_persistent_file_content_pe_1; +alter table inner_report drop foreign key fk_inner_report_forecast_id; -alter table person drop constraint fk_person_default_address_oid; -drop index ix_person_default_address_oid; +alter table drel_invoice drop foreign key fk_drel_invoice_booking; +drop index ix_drel_invoice_booking on drel_invoice; -alter table phones drop constraint fk_phones_person_id; -drop index ix_phones_person_id; +alter table item drop foreign key fk_item_etype; +drop index ix_item_etype on item; -alter table pp_to_ww drop constraint fk_pp_to_ww_pp; -drop index ix_pp_to_ww_pp_id; +alter table item drop foreign key fk_item_eregion; +drop index ix_item_eregion on item; -alter table pp_to_ww drop constraint fk_pp_to_ww_wview; -drop index ix_pp_to_ww_ww_id; +alter table trainer_monkey drop foreign key fk_trainer_monkey_trainer; -alter table r_orders drop constraint fk_r_orders_rcustomer; -drop index ix_r_orders_company_customern_1; +alter table trainer_monkey drop foreign key fk_trainer_monkey_monkey; -alter table resourcefile drop constraint fk_resourcefile_parentresourc_1; -drop index ix_resourcefile_parentresourc_1; +alter table troop_monkey drop foreign key fk_troop_monkey_troop; -alter table mt_role drop constraint fk_mt_role_tenant_id; -drop index ix_mt_role_tenant_id; +alter table troop_monkey drop foreign key fk_troop_monkey_monkey; -alter table mt_role_permission drop constraint fk_mt_role_permission_mt_role; -drop index ix_mt_role_permission_mt_role_1; +alter table l2_cldf_reset_bean_child drop foreign key fk_l2_cldf_reset_bean_child_parent_id; +drop index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child; -alter table mt_role_permission drop constraint fk_mt_role_permission_mt_perm_2; -drop index ix_mt_role_permission_mt_perm_2; +alter table level1_level4 drop foreign key fk_level1_level4_level1; +drop index ix_level1_level4_level1 on level1_level4; -alter table f_second drop constraint fk_f_second_first; +alter table level1_level4 drop foreign key fk_level1_level4_level4; +drop index ix_level1_level4_level4 on level1_level4; -alter table section drop constraint fk_section_article_id; -drop index ix_section_article_id; +alter table level1_level2 drop foreign key fk_level1_level2_level1; +drop index ix_level1_level2_level1 on level1_level2; -alter table self_parent drop constraint fk_self_parent_parent_id; -drop index ix_self_parent_parent_id; +alter table level1_level2 drop foreign key fk_level1_level2_level2; +drop index ix_level1_level2_level2 on level1_level2; -alter table self_ref_customer drop constraint fk_self_ref_customer_referred_1; -drop index ix_self_ref_customer_referred_1; +alter table level2_level3 drop foreign key fk_level2_level3_level2; +drop index ix_level2_level3_level2 on level2_level3; -alter table self_ref_example drop constraint fk_self_ref_example_parent_id; -drop index ix_self_ref_example_parent_id; +alter table level2_level3 drop foreign key fk_level2_level3_level3; +drop index ix_level2_level3_level3 on level2_level3; -alter table stockforecast drop constraint fk_stockforecast_inner_report_1; -drop index ix_stockforecast_inner_report_1; +alter table link drop foreign key fk_link_id; -alter table sub_section drop constraint fk_sub_section_section_id; -drop index ix_sub_section_section_id; +alter table la_attr_value_attribute drop foreign key fk_la_attr_value_attribute_la_attr_value; +drop index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute; -alter table t_detail_with_other_namexxxyy drop constraint fk_t_detail_with_other_namexx_1; -drop index ix_t_detail_with_other_namexx_1; +alter table la_attr_value_attribute drop foreign key fk_la_attr_value_attribute_attribute; +drop index ix_la_attr_value_attribute_attribute on la_attr_value_attribute; -alter table ts_detail_two drop constraint fk_ts_detail_two_master_id; -drop index ix_ts_detail_two_master_id; +alter table mprinter drop foreign key fk_mprinter_current_state_id; +drop index ix_mprinter_current_state_id on mprinter; -alter table twheel drop constraint fk_twheel_owner_plate_no; -drop index ix_twheel_owner_plate_no; +alter table mprinter drop foreign key fk_mprinter_last_swap_cyan_id; -alter table tire drop constraint fk_tire_wheel; +alter table mprinter drop foreign key fk_mprinter_last_swap_magenta_id; -alter table trip drop constraint fk_trip_vehicle_driver_id; -drop index ix_trip_vehicle_driver_id; +alter table mprinter drop foreign key fk_mprinter_last_swap_yellow_id; -alter table trip drop constraint fk_trip_address_id; -drop index ix_trip_address_id; +alter table mprinter drop foreign key fk_mprinter_last_swap_black_id; -alter table type drop constraint fk_type_sub_type_id; -drop index ix_type_sub_type_id; +alter table mprinter_state drop foreign key fk_mprinter_state_printer_id; +drop index ix_mprinter_state_printer_id on mprinter_state; -alter table ut_detail drop constraint fk_ut_detail_utmaster_id; -drop index ix_ut_detail_utmaster_id; +alter table mprofile drop foreign key fk_mprofile_picture_id; +drop index ix_mprofile_picture_id on mprofile; -alter table uutwo drop constraint fk_uutwo_master_id; -drop index ix_uutwo_master_id; +alter table mrole_muser drop foreign key fk_mrole_muser_mrole; +drop index ix_mrole_muser_mrole on mrole_muser; -alter table c_user drop constraint fk_c_user_group_id; -drop index ix_c_user_group_id; +alter table mrole_muser drop foreign key fk_mrole_muser_muser; +drop index ix_mrole_muser_muser on mrole_muser; -alter table oto_user drop constraint fk_oto_user_account_id; +alter table muser drop foreign key fk_muser_user_type_id; +drop index ix_muser_user_type_id on muser; -alter table em_user_role drop constraint fk_em_user_role_user_id; -drop index ix_em_user_role_user_id; +alter table mail_user_inbox drop foreign key fk_mail_user_inbox_mail_user; +drop index ix_mail_user_inbox_mail_user on mail_user_inbox; -alter table em_user_role drop constraint fk_em_user_role_role_id; -drop index ix_em_user_role_role_id; +alter table mail_user_inbox drop foreign key fk_mail_user_inbox_mail_box; +drop index ix_mail_user_inbox_mail_box on mail_user_inbox; -alter table vehicle drop constraint fk_vehicle_truck_ref_id; -drop index ix_vehicle_truck_ref_id; +alter table mail_user_outbox drop foreign key fk_mail_user_outbox_mail_user; +drop index ix_mail_user_outbox_mail_user on mail_user_outbox; -alter table vehicle drop constraint fk_vehicle_car_ref_id; -drop index ix_vehicle_car_ref_id; +alter table mail_user_outbox drop foreign key fk_mail_user_outbox_mail_box; +drop index ix_mail_user_outbox_mail_box on mail_user_outbox; -alter table vehicle_driver drop constraint fk_vehicle_driver_vehicle_id; -drop index ix_vehicle_driver_vehicle_id; +alter table c_message drop foreign key fk_c_message_conversation_id; +drop index ix_c_message_conversation_id on c_message; -alter table vehicle_driver drop constraint fk_vehicle_driver_address_id; -drop index ix_vehicle_driver_address_id; +alter table c_message drop foreign key fk_c_message_user_id; +drop index ix_c_message_user_id on c_message; -alter table warehouses drop constraint fk_warehouses_officezoneid; -drop index ix_warehouses_officezoneid; +alter table mnoc_user_mnoc_role drop foreign key fk_mnoc_user_mnoc_role_mnoc_user; +drop index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_wa_1; -drop index ix_warehousesshippingzones_wa_1; +alter table mnoc_user_mnoc_role drop foreign key fk_mnoc_user_mnoc_role_mnoc_role; +drop index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_zo_2; -drop index ix_warehousesshippingzones_sh_2; +alter table mny_b drop foreign key fk_mny_b_a_id; +drop index ix_mny_b_a_id on mny_b; -alter table sa_wheel drop constraint fk_sa_wheel_tire; -drop index ix_sa_wheel_tire; +alter table mny_b_mny_c drop foreign key fk_mny_b_mny_c_mny_b; +drop index ix_mny_b_mny_c_mny_b on mny_b_mny_c; -alter table sa_wheel drop constraint fk_sa_wheel_car; -drop index ix_sa_wheel_car; +alter table mny_b_mny_c drop foreign key fk_mny_b_mny_c_mny_c; +drop index ix_mny_b_mny_c_mny_c on mny_b_mny_c; -alter table with_zero drop constraint fk_with_zero_parent_id; -drop index ix_with_zero_parent_id; +alter table subtopics drop foreign key fk_subtopics_mny_topic_1; +drop index ix_subtopics_mny_topic_1 on subtopics; + +alter table subtopics drop foreign key fk_subtopics_mny_topic_2; +drop index ix_subtopics_mny_topic_2 on subtopics; + +alter table mp_role drop foreign key fk_mp_role_mp_user_id; +drop index ix_mp_role_mp_user_id on mp_role; + +alter table ms_many_a_many_b drop foreign key fk_ms_many_a_many_b_ms_many_a; +drop index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b; + +alter table ms_many_a_many_b drop foreign key fk_ms_many_a_many_b_ms_many_b; +drop index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b; + +alter table ms_many_b_many_a drop foreign key fk_ms_many_b_many_a_ms_many_b; +drop index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a; + +alter table ms_many_b_many_a drop foreign key fk_ms_many_b_many_a_ms_many_a; +drop index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a; + +alter table my_lob_size_join_many drop foreign key fk_my_lob_size_join_many_parent_id; +drop index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many; + +alter table o_cached_bean_country drop foreign key fk_o_cached_bean_country_o_cached_bean; +drop index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country; + +alter table o_cached_bean_country drop foreign key fk_o_cached_bean_country_o_country; +drop index ix_o_cached_bean_country_o_country on o_cached_bean_country; + +alter table o_cached_bean_child drop foreign key fk_o_cached_bean_child_cached_bean_id; +drop index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child; + +alter table oengine drop foreign key fk_oengine_car_id; + +alter table ogear_box drop foreign key fk_ogear_box_car_id; + +alter table oroad_show_msg drop foreign key fk_oroad_show_msg_company_id; + +alter table om_ordered_detail drop foreign key fk_om_ordered_detail_master_id; +drop index ix_om_ordered_detail_master_id on om_ordered_detail; + +alter table o_order drop foreign key fk_o_order_kcustomer_id; +drop index ix_o_order_kcustomer_id on o_order; + +alter table o_order_detail drop foreign key fk_o_order_detail_order_id; +drop index ix_o_order_detail_order_id on o_order_detail; + +alter table o_order_detail drop foreign key fk_o_order_detail_product_id; +drop index ix_o_order_detail_product_id on o_order_detail; + +alter table s_order_items drop foreign key fk_s_order_items_order_uuid; +drop index ix_s_order_items_order_uuid on s_order_items; + +alter table or_order_ship drop foreign key fk_or_order_ship_order_id; +drop index ix_or_order_ship_order_id on or_order_ship; + +alter table oto_bchild drop foreign key fk_oto_bchild_master_id; + +alter table oto_child drop foreign key fk_oto_child_master_id; + +alter table oto_cust_address drop foreign key fk_oto_cust_address_customer_cid; + +alter table oto_prime_extra drop foreign key fk_oto_prime_extra_eid; + +alter table oto_th_many drop foreign key fk_oto_th_many_oto_th_top_id; +drop index ix_oto_th_many_oto_th_top_id on oto_th_many; + +alter table oto_th_one drop foreign key fk_oto_th_one_many_id; + +alter table oto_ubprime_extra drop foreign key fk_oto_ubprime_extra_eid; + +alter table oto_uprime_extra drop foreign key fk_oto_uprime_extra_eid; + +alter table pfile drop foreign key fk_pfile_file_content_id; + +alter table pfile drop foreign key fk_pfile_file_content2_id; + +alter table paggview drop foreign key fk_paggview_pview_id; + +alter table pallet_location drop foreign key fk_pallet_location_zone_sid; +drop index ix_pallet_location_zone_sid on pallet_location; + +alter table parcel_location drop foreign key fk_parcel_location_parcelid; + +alter table rawinherit_parent_rawinherit_data drop foreign key fk_rawinherit_parent_rawinherit_data_rawinherit_parent; +drop index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data; + +alter table rawinherit_parent_rawinherit_data drop foreign key fk_rawinherit_parent_rawinherit_data_rawinherit_data; +drop index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data; + +alter table parent_person drop foreign key fk_parent_person_some_bean_id; +drop index ix_parent_person_some_bean_id on parent_person; + +alter table parent_person drop foreign key fk_parent_person_parent_identifier; +drop index ix_parent_person_parent_identifier on parent_person; + +alter table c_participation drop foreign key fk_c_participation_conversation_id; +drop index ix_c_participation_conversation_id on c_participation; + +alter table c_participation drop foreign key fk_c_participation_user_id; +drop index ix_c_participation_user_id on c_participation; + +alter table persistent_file_content drop foreign key fk_persistent_file_content_persistent_file_id; + +alter table person drop foreign key fk_person_default_address_oid; +drop index ix_person_default_address_oid on person; + +alter table phones drop foreign key fk_phones_person_id; +drop index ix_phones_person_id on phones; + +alter table pp_to_ww drop foreign key fk_pp_to_ww_pp; +drop index ix_pp_to_ww_pp on pp_to_ww; + +alter table pp_to_ww drop foreign key fk_pp_to_ww_wview; +drop index ix_pp_to_ww_wview on pp_to_ww; + +alter table question drop foreign key fk_question_groupobjectid; +drop index ix_question_groupobjectid on question; + +alter table r_orders drop foreign key fk_r_orders_customer; +drop index ix_r_orders_customer on r_orders; + +alter table resourcefile drop foreign key fk_resourcefile_parentresourcefileid; +drop index ix_resourcefile_parentresourcefileid on resourcefile; + +alter table mt_role drop foreign key fk_mt_role_tenant_id; +drop index ix_mt_role_tenant_id on mt_role; + +alter table mt_role_permission drop foreign key fk_mt_role_permission_mt_role; +drop index ix_mt_role_permission_mt_role on mt_role_permission; + +alter table mt_role_permission drop foreign key fk_mt_role_permission_mt_permission; +drop index ix_mt_role_permission_mt_permission on mt_role_permission; + +alter table f_second drop foreign key fk_f_second_first; + +alter table section drop foreign key fk_section_article_id; +drop index ix_section_article_id on section; + +alter table self_parent drop foreign key fk_self_parent_parent_id; +drop index ix_self_parent_parent_id on self_parent; + +alter table self_ref_customer drop foreign key fk_self_ref_customer_referred_by_id; +drop index ix_self_ref_customer_referred_by_id on self_ref_customer; + +alter table self_ref_example drop foreign key fk_self_ref_example_parent_id; +drop index ix_self_ref_example_parent_id on self_ref_example; + +alter table stockforecast drop foreign key fk_stockforecast_inner_report_id; +drop index ix_stockforecast_inner_report_id on stockforecast; + +alter table sub_section drop foreign key fk_sub_section_section_id; +drop index ix_sub_section_section_id on sub_section; + +alter table tevent_many drop foreign key fk_tevent_many_event_id; +drop index ix_tevent_many_event_id on tevent_many; + +alter table tevent_one drop foreign key fk_tevent_one_event_id; + +alter table t_detail_with_other_namexxxyy drop foreign key fk_t_detail_with_other_namexxxyy_master_id; +drop index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy; + +alter table ts_detail_two drop foreign key fk_ts_detail_two_master_id; +drop index ix_ts_detail_two_master_id on ts_detail_two; + +alter table twheel drop foreign key fk_twheel_owner_plate_no; +drop index ix_twheel_owner_plate_no on twheel; + +alter table tire drop foreign key fk_tire_wheel; + +alter table trip drop foreign key fk_trip_vehicle_driver_id; +drop index ix_trip_vehicle_driver_id on trip; + +alter table trip drop foreign key fk_trip_address_id; +drop index ix_trip_address_id on trip; + +alter table type drop foreign key fk_type_sub_type_id; +drop index ix_type_sub_type_id on type; + +alter table ut_detail drop foreign key fk_ut_detail_utmaster_id; +drop index ix_ut_detail_utmaster_id on ut_detail; + +alter table uutwo drop foreign key fk_uutwo_master_id; +drop index ix_uutwo_master_id on uutwo; + +alter table c_user drop foreign key fk_c_user_group_id; +drop index ix_c_user_group_id on c_user; + +alter table oto_user drop foreign key fk_oto_user_account_id; + +alter table em_user_role drop foreign key fk_em_user_role_user_id; +drop index ix_em_user_role_user_id on em_user_role; + +alter table em_user_role drop foreign key fk_em_user_role_role_id; +drop index ix_em_user_role_role_id on em_user_role; + +alter table vehicle drop foreign key fk_vehicle_car_ref_id; +drop index ix_vehicle_car_ref_id on vehicle; + +alter table vehicle drop foreign key fk_vehicle_truck_ref_id; +drop index ix_vehicle_truck_ref_id on vehicle; + +alter table vehicle_driver drop foreign key fk_vehicle_driver_vehicle_id; +drop index ix_vehicle_driver_vehicle_id on vehicle_driver; + +alter table vehicle_driver drop foreign key fk_vehicle_driver_address_id; +drop index ix_vehicle_driver_address_id on vehicle_driver; + +alter table warehouses drop foreign key fk_warehouses_officezoneid; +drop index ix_warehouses_officezoneid on warehouses; + +alter table warehousesshippingzones drop foreign key fk_warehousesshippingzones_warehouses; +drop index ix_warehousesshippingzones_warehouses on warehousesshippingzones; + +alter table warehousesshippingzones drop foreign key fk_warehousesshippingzones_zones; +drop index ix_warehousesshippingzones_zones on warehousesshippingzones; + +alter table sa_wheel drop foreign key fk_sa_wheel_tire; +drop index ix_sa_wheel_tire on sa_wheel; + +alter table sa_wheel drop foreign key fk_sa_wheel_car; +drop index ix_sa_wheel_car on sa_wheel; + +alter table g_who_props_otm drop foreign key fk_g_who_props_otm_who_created_id; +drop index ix_g_who_props_otm_who_created_id on g_who_props_otm; + +alter table g_who_props_otm drop foreign key fk_g_who_props_otm_who_modified_id; +drop index ix_g_who_props_otm_who_modified_id on g_who_props_otm; + +alter table with_zero drop foreign key fk_with_zero_parent_id; +drop index ix_with_zero_parent_id on with_zero; drop table if exists asimple_bean; -drop sequence if exists asimple_bean_seq; drop table if exists bar; -drop sequence if exists bar_seq; drop table if exists oto_account; -drop sequence if exists oto_account_seq; -drop table if exists o_address; -drop sequence if exists o_address_seq; +drop table if exists addr; drop table if exists address; -drop sequence if exists address_seq; -drop table if exists animals; -drop sequence if exists animals_seq; +drop table if exists o_address; + +drop table if exists album; + +drop table if exists animal; drop table if exists animal_shelter; -drop sequence if exists animal_shelter_seq; drop table if exists article; -drop sequence if exists article_seq; drop table if exists attribute; -drop sequence if exists attribute_seq; drop table if exists attribute_holder; -drop sequence if exists attribute_holder_seq; drop table if exists audit_log; -drop sequence if exists audit_log_seq; drop table if exists bbookmark; -drop sequence if exists bbookmark_seq; drop table if exists bbookmark_user; -drop sequence if exists bbookmark_user_seq; drop table if exists bsimple_with_gen; -drop sequence if exists bsimple_with_gen_seq; + +drop table if exists bsite; + +drop table if exists bsite_user; + +drop table if exists bsite_user_b; + +drop table if exists bsite_user_c; + +drop table if exists buser; drop table if exists bwith_qident; -drop sequence if exists bwith_qident_seq; drop table if exists basic_joda_entity; -drop sequence if exists basic_joda_entity_seq; drop table if exists bean_with_time_zone; -drop sequence if exists bean_with_time_zone_seq; drop table if exists drel_booking; -drop sequence if exists drel_booking_seq; + +drop table if exists cinh_root; drop table if exists ckey_assoc; -drop sequence if exists ckey_assoc_seq; drop table if exists ckey_detail; -drop sequence if exists ckey_detail_seq; drop table if exists ckey_parent; drop table if exists calculation_result; -drop sequence if exists calculation_result_seq; drop table if exists cao_bean; drop table if exists sa_car; -drop sequence if exists sa_car_seq; drop table if exists sp_car_car; -drop sequence if exists sp_car_car_seq; drop table if exists sp_car_car_wheels; drop table if exists car_accessory; -drop sequence if exists car_accessory_seq; + +drop table if exists car_fuse; + +drop table if exists category; + +drop table if exists child_person; drop table if exists configuration; -drop sequence if exists configuration_seq; drop table if exists configurations; -drop sequence if exists configurations_seq; drop table if exists contact; -drop sequence if exists contact_seq; drop table if exists contact_group; -drop sequence if exists contact_group_seq; drop table if exists contact_note; -drop sequence if exists contact_note_seq; drop table if exists c_conversation; -drop sequence if exists c_conversation_seq; drop table if exists o_country; +drop table if exists cover; + drop table if exists o_customer; -drop sequence if exists o_customer_seq; + +drop table if exists dcredit; + +drop table if exists dcredit_drol; drop table if exists dexh_entity; -drop sequence if exists dexh_entity_seq; drop table if exists dperson; -drop sequence if exists dperson_seq; + +drop table if exists drol; + +drop table if exists drot; + +drop table if exists drot_drol; drop table if exists rawinherit_data; -drop sequence if exists rawinherit_data_seq; + +drop table if exists dfk_cascade; + +drop table if exists dfk_cascade_one; + +drop table if exists dfk_none; + +drop table if exists dfk_none_via_join; + +drop table if exists dfk_one; + +drop table if exists dfk_set_null; + +drop table if exists doc; + +drop table if exists doc_link; + +drop table if exists doc_link_draft; + +drop table if exists doc_draft; + +drop table if exists document; + +drop table if exists document_draft; + +drop table if exists document_media; + +drop table if exists document_media_draft; + +drop table if exists earray_bean; + +drop table if exists earray_set_bean; drop table if exists e_basic; -drop sequence if exists e_basic_seq; + +drop table if exists ebasic_change_log; drop table if exists ebasic_clob; -drop sequence if exists ebasic_clob_seq; drop table if exists ebasic_clob_fetch_eager; -drop sequence if exists ebasic_clob_fetch_eager_seq; drop table if exists ebasic_clob_no_ver; -drop sequence if exists ebasic_clob_no_ver_seq; drop table if exists e_basicenc; -drop sequence if exists e_basicenc_seq; drop table if exists e_basicenc_bin; -drop sequence if exists e_basicenc_bin_seq; drop table if exists e_basic_enum_id; +drop table if exists e_basic_eni; + +drop table if exists ebasic_hstore; + +drop table if exists ebasic_json_list; + drop table if exists ebasic_json_map; -drop sequence if exists ebasic_json_map_seq; drop table if exists ebasic_json_map_blob; -drop sequence if exists ebasic_json_map_blob_seq; drop table if exists ebasic_json_map_clob; -drop sequence if exists ebasic_json_map_clob_seq; + +drop table if exists ebasic_json_map_detail; drop table if exists ebasic_json_map_json_b; -drop sequence if exists ebasic_json_map_json_b_seq; drop table if exists ebasic_json_map_varchar; -drop sequence if exists ebasic_json_map_varchar_seq; drop table if exists ebasic_json_node; -drop sequence if exists ebasic_json_node_seq; drop table if exists ebasic_json_node_blob; -drop sequence if exists ebasic_json_node_blob_seq; drop table if exists ebasic_json_node_json_b; -drop sequence if exists ebasic_json_node_json_b_seq; drop table if exists ebasic_json_node_varchar; -drop sequence if exists ebasic_json_node_varchar_seq; + +drop table if exists ebasic_json_unmapped; drop table if exists e_basic_ndc; -drop sequence if exists e_basic_ndc_seq; + +drop table if exists ebasic_no_sdchild; + +drop table if exists ebasic_sdchild; + +drop table if exists ebasic_soft_delete; drop table if exists e_basicver; -drop sequence if exists e_basicver_seq; drop table if exists e_basic_withlife; -drop sequence if exists e_basic_withlife_seq; drop table if exists e_basicverucon; -drop sequence if exists e_basicverucon_seq; + +drop table if exists e_col_ab; + +drop table if exists ecustom_id; drop table if exists eemb_inner; -drop sequence if exists eemb_inner_seq; drop table if exists eemb_outer; -drop sequence if exists eemb_outer_seq; drop table if exists egen_props; -drop sequence if exists egen_props_seq; drop table if exists einvoice; -drop sequence if exists einvoice_seq; drop table if exists e_main; -drop sequence if exists e_main_seq; drop table if exists enull_collection; -drop sequence if exists enull_collection_seq; drop table if exists enull_collection_detail; -drop sequence if exists enull_collection_detail_seq; drop table if exists eopt_one_a; -drop sequence if exists eopt_one_a_seq; drop table if exists eopt_one_b; -drop sequence if exists eopt_one_b_seq; drop table if exists eopt_one_c; -drop sequence if exists eopt_one_c_seq; drop table if exists eperson; -drop sequence if exists eperson_seq; + +drop table if exists e_person_online; drop table if exists esimple; +drop table if exists esoft_del_book; + +drop table if exists esoft_del_book_esoft_del_user; + +drop table if exists esoft_del_down; + +drop table if exists esoft_del_mid; + +drop table if exists esoft_del_one_a; + +drop table if exists esoft_del_one_b; + +drop table if exists esoft_del_role; + +drop table if exists esoft_del_role_esoft_del_user; + +drop table if exists esoft_del_top; + +drop table if exists esoft_del_up; + +drop table if exists esoft_del_user; + +drop table if exists esoft_del_user_esoft_del_role; + +drop table if exists esome_convert_type; + drop table if exists esome_type; -drop sequence if exists esome_type_seq; drop table if exists etrans_many; -drop sequence if exists etrans_many_seq; + +drop table if exists rawinherit_uncle; drop table if exists evanilla_collection; -drop sequence if exists evanilla_collection_seq; drop table if exists evanilla_collection_detail; -drop sequence if exists evanilla_collection_detail_seq; drop table if exists ewho_props; -drop sequence if exists ewho_props_seq; drop table if exists e_withinet; -drop sequence if exists e_withinet_seq; drop table if exists td_child; -drop sequence if exists td_child_seq; drop table if exists td_parent; -drop sequence if exists td_parent_seq; + +drop table if exists empl; drop table if exists feature_desc; -drop sequence if exists feature_desc_seq; drop table if exists f_first; -drop sequence if exists f_first_seq; drop table if exists foo; -drop sequence if exists foo_seq; drop table if exists gen_key_identity; drop table if exists gen_key_sequence; -drop sequence if exists seq; drop table if exists gen_key_table; -drop sequence if exists gen_key_table_seq; + +drop table if exists grand_parent_person; + +drop table if exists survey_group; drop table if exists c_group; -drop sequence if exists c_group_seq; + +drop table if exists he_doc; + +drop trigger hx_link_history_upd; +drop trigger hx_link_history_del; +drop view hx_link_with_history; +alter table hx_link drop column sys_period_start; +alter table hx_link drop column sys_period_end; +drop table hx_link_history; + +drop table if exists hx_link; + +drop table if exists hx_link_doc; + +drop table if exists hi_doc; + +drop trigger hi_link_history_upd; +drop trigger hi_link_history_del; +drop view hi_link_with_history; +alter table hi_link drop column sys_period_start; +alter table hi_link drop column sys_period_end; +drop table hi_link_history; + +drop table if exists hi_link; + +drop trigger hi_link_doc_history_upd; +drop trigger hi_link_doc_history_del; +drop view hi_link_doc_with_history; +alter table hi_link_doc drop column sys_period_start; +alter table hi_link_doc drop column sys_period_end; +drop table hi_link_doc_history; + +drop table if exists hi_link_doc; drop table if exists imrelated; -drop sequence if exists imrelated_seq; drop table if exists imroot; -drop sequence if exists imroot_seq; drop table if exists ixresource; drop table if exists info_company; -drop sequence if exists info_company_seq; drop table if exists info_contact; -drop sequence if exists info_contact_seq; drop table if exists info_customer; -drop sequence if exists info_customer_seq; drop table if exists inner_report; -drop sequence if exists inner_report_seq; drop table if exists drel_invoice; -drop sequence if exists drel_invoice_seq; drop table if exists item; +drop table if exists monkey; + +drop table if exists trainer; + +drop table if exists trainer_monkey; + +drop table if exists troop; + +drop table if exists troop_monkey; + +drop table if exists l2_cldf_reset_bean; + +drop table if exists l2_cldf_reset_bean_child; + drop table if exists level1; -drop sequence if exists level1_seq; drop table if exists level1_level4; drop table if exists level1_level2; drop table if exists level2; -drop sequence if exists level2_seq; drop table if exists level2_level3; drop table if exists level3; -drop sequence if exists level3_seq; drop table if exists level4; -drop sequence if exists level4_seq; + +drop trigger link_history_upd; +drop trigger link_history_del; +drop view link_with_history; +alter table link drop column sys_period_start; +alter table link drop column sys_period_end; +drop table link_history; + +drop table if exists link; + +drop table if exists link_draft; drop table if exists la_attr_value; -drop sequence if exists la_attr_value_seq; drop table if exists la_attr_value_attribute; drop table if exists mmedia; -drop sequence if exists mmedia_seq; drop table if exists non_updateprop; -drop sequence if exists non_updateprop_seq; drop table if exists mprinter; -drop sequence if exists mprinter_seq; drop table if exists mprinter_state; -drop sequence if exists mprinter_state_seq; drop table if exists mprofile; -drop sequence if exists mprofile_seq; drop table if exists mprotected_construct_bean; -drop sequence if exists mprotected_construct_bean_seq; drop table if exists mrole; -drop sequence if exists mrole_seq; drop table if exists mrole_muser; drop table if exists msome_other; -drop sequence if exists msome_other_seq; drop table if exists muser; -drop sequence if exists muser_seq; drop table if exists muser_type; -drop sequence if exists muser_type_seq; + +drop table if exists mail_box; + +drop table if exists mail_user; + +drop table if exists mail_user_inbox; + +drop table if exists mail_user_outbox; drop table if exists map_super_actual; -drop sequence if exists map_super_actual_seq; drop table if exists c_message; -drop sequence if exists c_message_seq; drop table if exists mnoc_role; -drop sequence if exists mnoc_role_seq; drop table if exists mnoc_user; -drop sequence if exists mnoc_user_seq; drop table if exists mnoc_user_mnoc_role; +drop table if exists mny_a; + +drop table if exists mny_b; + +drop table if exists mny_b_mny_c; + +drop table if exists mny_c; + +drop table if exists mny_topic; + +drop table if exists subtopics; + drop table if exists mp_role; -drop sequence if exists mp_role_seq; drop table if exists mp_user; -drop sequence if exists mp_user_seq; + +drop table if exists ms_many_a; + +drop table if exists ms_many_a_many_b; + +drop table if exists ms_many_b; + +drop table if exists ms_many_b_many_a; drop table if exists my_lob_size; -drop sequence if exists my_lob_size_seq; drop table if exists my_lob_size_join_many; -drop sequence if exists my_lob_size_join_many_seq; drop table if exists noidbean; drop table if exists o_cached_bean; -drop sequence if exists o_cached_bean_seq; drop table if exists o_cached_bean_country; drop table if exists o_cached_bean_child; -drop sequence if exists o_cached_bean_child_seq; + +drop table if exists o_cached_natkey; + +drop table if exists o_cached_natkey3; drop table if exists ocar; -drop sequence if exists ocar_seq; + +drop table if exists ocompany; drop table if exists oengine; drop table if exists ogear_box; +drop table if exists oroad_show_msg; + +drop table if exists om_ordered_detail; + +drop table if exists om_ordered_master; + drop table if exists o_order; -drop sequence if exists o_order_seq; drop table if exists o_order_detail; -drop sequence if exists o_order_detail_seq; drop table if exists s_orders; drop table if exists s_order_items; drop table if exists or_order_ship; -drop sequence if exists or_order_ship_seq; + +drop table if exists organisation; + +drop table if exists oto_bchild; + +drop table if exists oto_bmaster; drop table if exists oto_child; -drop sequence if exists oto_child_seq; + +drop table if exists oto_cust; + +drop table if exists oto_cust_address; drop table if exists oto_master; -drop sequence if exists oto_master_seq; + +drop table if exists oto_prime; + +drop table if exists oto_prime_extra; + +drop table if exists oto_th_many; + +drop table if exists oto_th_one; + +drop table if exists oto_th_top; + +drop table if exists oto_ubprime; + +drop table if exists oto_ubprime_extra; + +drop table if exists oto_uprime; + +drop table if exists oto_uprime_extra; drop table if exists pfile; -drop sequence if exists pfile_seq; drop table if exists pfile_content; -drop sequence if exists pfile_content_seq; drop table if exists paggview; drop table if exists pallet_location; -drop sequence if exists pallet_location_seq; drop table if exists parcel; -drop sequence if exists parcel_seq; drop table if exists parcel_location; -drop sequence if exists parcel_location_seq; drop table if exists rawinherit_parent; -drop sequence if exists rawinherit_parent_seq; -drop table if exists rawinherit_parent_rawinherit_dat; +drop table if exists rawinherit_parent_rawinherit_data; + +drop table if exists parent_person; drop table if exists c_participation; -drop sequence if exists c_participation_seq; drop table if exists mt_permission; drop table if exists persistent_file; -drop sequence if exists persistent_file_seq; drop table if exists persistent_file_content; -drop sequence if exists persistent_file_content_seq; drop table if exists persons; -drop sequence if exists persons_seq; drop table if exists person; -drop sequence if exists person_seq; drop table if exists phones; -drop sequence if exists phones_seq; + +drop table if exists primary_revision; drop table if exists o_product; -drop sequence if exists o_product_seq; drop table if exists pp; drop table if exists pp_to_ww; +drop table if exists question; + drop table if exists rcustomer; drop table if exists r_orders; @@ -783,154 +1143,136 @@ drop table if exists region; drop table if exists resourcefile; +drop table if exists em_role; + drop table if exists mt_role; drop table if exists mt_role_permission; -drop table if exists em_role; -drop sequence if exists em_role_seq; - drop table if exists f_second; -drop sequence if exists f_second_seq; drop table if exists section; -drop sequence if exists section_seq; drop table if exists self_parent; -drop sequence if exists self_parent_seq; drop table if exists self_ref_customer; -drop sequence if exists self_ref_customer_seq; drop table if exists self_ref_example; -drop sequence if exists self_ref_example_seq; drop table if exists some_enum_bean; -drop sequence if exists some_enum_bean_seq; drop table if exists some_file_bean; -drop sequence if exists some_file_bean_seq; drop table if exists some_new_types_bean; -drop sequence if exists some_new_types_bean_seq; drop table if exists some_period_bean; -drop sequence if exists some_period_bean_seq; drop table if exists stockforecast; -drop sequence if exists stockforecast_seq; drop table if exists sub_section; -drop sequence if exists sub_section_seq; drop table if exists sub_type; -drop sequence if exists sub_type_seq; + +drop table if exists survey; drop table if exists tbytes_only; -drop sequence if exists tbytes_only_seq; drop table if exists tcar; +drop table if exists tevent; + +drop table if exists tevent_many; + +drop table if exists tevent_one; + drop table if exists tint_root; -drop sequence if exists tint_root_seq; drop table if exists tjoda_entity; -drop sequence if exists tjoda_entity_seq; drop table if exists t_mapsuper1; -drop sequence if exists t_mapsuper1_seq; drop table if exists t_oneb; -drop sequence if exists t_oneb_seq; drop table if exists t_detail_with_other_namexxxyy; -drop sequence if exists t_atable_detail_seq; drop table if exists ts_detail_two; -drop sequence if exists ts_detail_two_seq; drop table if exists t_atable_thatisrelatively; -drop sequence if exists t_atable_master_seq; drop table if exists ts_master_two; -drop sequence if exists ts_master_two_seq; drop table if exists tuuid_entity; drop table if exists twheel; -drop sequence if exists twheel_seq; drop table if exists twith_pre_insert; -drop sequence if exists twith_pre_insert_seq; drop table if exists mt_tenant; -drop table if exists sa_tire; -drop sequence if exists sa_tire_seq; +drop table if exists test_annotation_base_entity; drop table if exists tire; -drop sequence if exists tire_seq; + +drop table if exists sa_tire; drop table if exists trip; -drop sequence if exists trip_seq; drop table if exists truck_ref; -drop sequence if exists truck_ref_seq; drop table if exists type; +drop table if exists tz_bean; + drop table if exists ut_detail; -drop sequence if exists ut_detail_seq; drop table if exists ut_master; -drop sequence if exists ut_master_seq; drop table if exists uuone; drop table if exists uutwo; -drop table if exists em_user; -drop sequence if exists em_user_seq; - -drop table if exists tx_user; -drop sequence if exists tx_user_seq; +drop trigger c_user_history_upd; +drop trigger c_user_history_del; +drop view c_user_with_history; +alter table c_user drop column sys_period_start; +alter table c_user drop column sys_period_end; +drop table c_user_history; drop table if exists c_user; -drop sequence if exists c_user_seq; + +drop table if exists tx_user; + +drop table if exists g_user; + +drop table if exists em_user; drop table if exists oto_user; -drop sequence if exists oto_user_seq; drop table if exists em_user_role; drop table if exists vehicle; -drop sequence if exists vehicle_seq; drop table if exists vehicle_driver; -drop sequence if exists vehicle_driver_seq; drop table if exists warehouses; -drop sequence if exists warehouses_seq; drop table if exists warehousesshippingzones; drop table if exists sa_wheel; -drop sequence if exists sa_wheel_seq; - -drop table if exists sp_car_wheel; -drop sequence if exists sp_car_wheel_seq; drop table if exists wheel; -drop sequence if exists wheel_seq; + +drop table if exists sp_car_wheel; + +drop table if exists g_who_props_otm; drop table if exists with_zero; -drop sequence if exists with_zero_seq; drop table if exists parent; -drop sequence if exists parent_seq; drop table if exists wview; drop table if exists zones; -drop sequence if exists zones_seq; +drop index ix_contact_last_name_first_name on contact; +drop index ix_e_basic_name on e_basic; diff --git a/src/test/ddl-review/mysql-create-all.sql b/src/test/ddl-review/mysql-create-all.sql index 974b5461d..67fd4e368 100644 --- a/src/test/ddl-review/mysql-create-all.sql +++ b/src/test/ddl-review/mysql-create-all.sql @@ -1,3 +1,4 @@ +-- Generated by ebean unknown at 2018-03-08T06:38:18.344Z create table asimple_bean ( id bigint auto_increment not null, name varchar(255), @@ -21,6 +22,24 @@ create table oto_account ( constraint pk_oto_account primary key (id) ); +create table addr ( + id bigint auto_increment not null, + employee_id bigint, + name varchar(255), + address_line1 varchar(255), + address_line2 varchar(255), + city varchar(255), + version bigint not null, + constraint pk_addr primary key (id) +); + +create table address ( + oid bigint auto_increment not null, + street varchar(255), + version integer not null, + constraint pk_address primary key (oid) +); + create table o_address ( id smallint auto_increment not null, line_1 varchar(100), @@ -32,22 +51,27 @@ create table o_address ( constraint pk_o_address primary key (id) ); -create table address ( - oid bigint auto_increment not null, - street varchar(255), - version integer not null, - constraint pk_address primary key (oid) +create table album ( + id bigint auto_increment not null, + name varchar(255), + cover_id bigint, + deleted tinyint(1) default 0 not null, + created_at datetime(6) not null, + last_update datetime(6) not null, + constraint uq_album_cover_id unique (cover_id), + constraint pk_album primary key (id) ); -create table animals ( - species varchar(31) not null, +create table animal ( + species varchar(255) not null, id bigint auto_increment not null, shelter_id bigint, version bigint not null, name varchar(255), registration_number varchar(255), date_of_birth date, - constraint pk_animals primary key (id) + dog_size varchar(255), + constraint pk_animal primary key (id) ); create table animal_shelter ( @@ -114,9 +138,45 @@ create table bsimple_with_gen ( constraint pk_bsimple_with_gen primary key (id) ); +create table bsite ( + id varchar(40) not null, + name varchar(255), + constraint pk_bsite primary key (id) +); + +create table bsite_user ( + site_id varchar(40) not null, + user_id varchar(40) not null, + access_level integer, + constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user primary key (site_id,user_id) +); + +create table bsite_user_b ( + site varchar(40) not null, + usr varchar(40) not null, + access_level integer, + constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_b primary key (site,usr) +); + +create table bsite_user_c ( + site_uid varchar(40) not null, + user_uid varchar(40) not null, + access_level integer, + constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_c primary key (site_uid,user_uid) +); + +create table buser ( + id varchar(40) not null, + name varchar(255), + constraint pk_buser primary key (id) +); + create table bwith_qident ( id integer auto_increment not null, - `Name` varchar(255), + `Name` varchar(191), last_updated datetime(6) not null, constraint uq_bwith_qident_name unique (`Name`), constraint pk_bwith_qident primary key (id) @@ -125,6 +185,7 @@ create table bwith_qident ( create table basic_joda_entity ( id bigint auto_increment not null, name varchar(255), + period varchar(50), created datetime(6) not null, updated datetime(6) not null, version datetime(6) not null, @@ -140,14 +201,29 @@ create table bean_with_time_zone ( create table drel_booking ( id bigint auto_increment not null, + booking_uid bigint, agent_invoice bigint, client_invoice bigint, version integer not null, + constraint uq_drel_booking_booking_uid unique (booking_uid), constraint uq_drel_booking_agent_invoice unique (agent_invoice), constraint uq_drel_booking_client_invoice unique (client_invoice), constraint pk_drel_booking primary key (id) ); +create table cinh_root ( + dtype varchar(3) not null, + id integer auto_increment not null, + license_number varchar(255), + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + driver varchar(255), + notes varchar(255), + action varchar(255), + constraint pk_cinh_root primary key (id) +); + create table ckey_assoc ( id integer auto_increment not null, assoc_one varchar(255), @@ -173,7 +249,7 @@ create table ckey_parent ( create table calculation_result ( id integer auto_increment not null, - charge double, + charge double not null, product_configuration_id integer, group_configuration_id integer, constraint pk_calculation_result primary key (id) @@ -208,6 +284,7 @@ create table sp_car_car_wheels ( create table car_accessory ( id integer auto_increment not null, name varchar(255), + fuse_id bigint not null, car_id integer, cretime datetime(6) not null, updtime datetime(6) not null, @@ -215,8 +292,33 @@ create table car_accessory ( constraint pk_car_accessory primary key (id) ); +create table car_fuse ( + id bigint auto_increment not null, + location_code varchar(255), + constraint pk_car_fuse primary key (id) +); + +create table category ( + id bigint auto_increment not null, + name varchar(255), + surveyobjectid bigint, + sequence_number integer not null, + constraint pk_category primary key (id) +); + +create table child_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_child_person primary key (identifier) +); + create table configuration ( - type varchar(31) not null, + type varchar(21) not null, id integer auto_increment not null, name varchar(255), configurations_id integer, @@ -233,8 +335,8 @@ create table configurations ( create table contact ( id integer auto_increment not null, - first_name varchar(255), - last_name varchar(255), + first_name varchar(127), + last_name varchar(127), phone varchar(255), mobile varchar(255), email varchar(255), @@ -268,7 +370,7 @@ create table contact_note ( create table c_conversation ( id bigint auto_increment not null, title varchar(255), - isopen tinyint(1) default 0, + isopen tinyint(1) default 0 not null, group_id bigint, version bigint not null, when_created datetime(6) not null, @@ -282,26 +384,44 @@ create table o_country ( constraint pk_o_country primary key (code) ); +create table cover ( + id bigint auto_increment not null, + s3url varchar(255), + deleted tinyint(1) default 0 not null, + constraint pk_cover primary key (id) +); + create table o_customer ( id integer auto_increment not null, - status varchar(1), + status varchar(1) comment 'status of the customer', name varchar(40) not null, - smallnote varchar(100), - anniversary date, + smallnote varchar(100) comment 'Short notes regarding the customer', + anniversary date comment 'Join date of the customer', billing_address_id smallint, shipping_address_id smallint, cretime datetime(6) not null, updtime datetime(6) not null, version bigint not null, - constraint ck_o_customer_status check (status in ('N','A','I')), + constraint ck_o_customer_status check ( status in ('N','A','I')), constraint pk_o_customer primary key (id) +) comment='Holds external customers'; + +create table dcredit ( + id bigint auto_increment not null, + credit varchar(255), + constraint pk_dcredit primary key (id) +); + +create table dcredit_drol ( + dcredit_id bigint not null, + drol_id bigint not null, + constraint pk_dcredit_drol primary key (dcredit_id,drol_id) ); create table dexh_entity ( oid bigint auto_increment not null, - exhange_rate decimal(38), - exhange_cmoney_amount decimal(38), - exhange_cmoney_currency varchar(3), + exhange varchar(255), + an_enum_type varchar(255), last_updated datetime(6) not null, constraint pk_dexh_entity primary key (oid) ); @@ -311,29 +431,197 @@ create table dperson ( first_name varchar(255), last_name varchar(255), salary decimal(38), - a_amt decimal(38), - a_curr varchar(3), - i_start datetime(6), - i_end datetime(6), constraint pk_dperson primary key (id) ); +create table drol ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_drol primary key (id) +); + +create table drot ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_drot primary key (id) +); + +create table drot_drol ( + drot_id bigint not null, + drol_id bigint not null, + constraint pk_drot_drol primary key (drot_id,drol_id) +); + create table rawinherit_data ( id bigint auto_increment not null, val integer, constraint pk_rawinherit_data primary key (id) ); +create table dfk_cascade ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_cascade primary key (id) +); + +create table dfk_cascade_one ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_dfk_cascade_one primary key (id) +); + +create table dfk_none ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none primary key (id) +); + +create table dfk_none_via_join ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none_via_join primary key (id) +); + +create table dfk_one ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_dfk_one primary key (id) +); + +create table dfk_set_null ( + id bigint auto_increment not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_set_null primary key (id) +); + +create table doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_doc primary key (id) +); + +create table doc_link ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link primary key (doc_id,link_id) +); + +create table doc_link_draft ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link_draft primary key (doc_id,link_id) +); + +create table doc_draft ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_doc_draft primary key (id) +); + +create table document ( + id bigint auto_increment not null, + title varchar(127), + body varchar(255), + organisation_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_document_title unique (title), + constraint pk_document primary key (id) +); + +create table document_draft ( + id bigint auto_increment not null, + title varchar(127), + body varchar(255), + when_publish datetime(6), + organisation_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_document_draft_title unique (title), + constraint pk_document_draft primary key (id) +); + +create table document_media ( + id bigint auto_increment not null, + document_id bigint, + name varchar(255), + description varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_document_media primary key (id) +); + +create table document_media_draft ( + id bigint auto_increment not null, + document_id bigint, + name varchar(255), + description varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_document_media_draft primary key (id) +); + +create table earray_bean ( + id bigint auto_increment not null, + name varchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + statuses varchar(1000), + status2 varchar(1000), + version bigint not null, + constraint pk_earray_bean primary key (id) +); + +create table earray_set_bean ( + id bigint auto_increment not null, + name varchar(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + version bigint not null, + constraint pk_earray_set_bean primary key (id) +); + create table e_basic ( id integer auto_increment not null, status varchar(1), - name varchar(255), + name varchar(127), description varchar(255), some_date datetime(6), - constraint ck_e_basic_status check (status in ('N','A','I')), + constraint ck_e_basic_status check ( status in ('N','A','I')), constraint pk_e_basic primary key (id) ); +create table ebasic_change_log ( + id bigint auto_increment not null, + name varchar(20), + short_description varchar(50), + long_description varchar(100), + who_created varchar(255) not null, + who_modified varchar(255) not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + version bigint not null, + constraint pk_ebasic_change_log primary key (id) +); + create table ebasic_clob ( id bigint auto_increment not null, name varchar(255), @@ -364,6 +652,7 @@ create table e_basicenc ( name varchar(255), description varbinary(80), dob varbinary(20), + status varbinary(20), last_update datetime(6), constraint pk_e_basicenc primary key (id) ); @@ -382,10 +671,41 @@ create table e_basic_enum_id ( status varchar(1) not null, name varchar(255), description varchar(255), - constraint ck_e_basic_enum_id_status check (status in ('N','A','I')), + constraint ck_e_basic_enum_id_status check ( status in ('N','A','I')), constraint pk_e_basic_enum_id primary key (status) ); +create table e_basic_eni ( + id integer auto_increment not null, + status integer, + name varchar(255), + description varchar(255), + some_date datetime(6), + constraint ck_e_basic_eni_status check ( status in (1,2,3)), + constraint pk_e_basic_eni primary key (id) +); + +create table ebasic_hstore ( + id bigint auto_increment not null, + name varchar(255), + map varchar(800), + version bigint not null, + constraint pk_ebasic_hstore primary key (id) +); + +create table ebasic_json_list ( + id bigint auto_increment not null, + name varchar(255), + bean_set varchar(700), + bean_list longtext, + bean_map varchar(700), + plain_bean varchar(500), + flags varchar(50), + tags varchar(100), + version bigint not null, + constraint pk_ebasic_json_list primary key (id) +); + create table ebasic_json_map ( id bigint auto_increment not null, name varchar(255), @@ -410,6 +730,15 @@ create table ebasic_json_map_clob ( constraint pk_ebasic_json_map_clob primary key (id) ); +create table ebasic_json_map_detail ( + id bigint auto_increment not null, + owner_id bigint, + name varchar(255), + content longtext, + version bigint not null, + constraint pk_ebasic_json_map_detail primary key (id) +); + create table ebasic_json_map_json_b ( id bigint auto_increment not null, name varchar(255), @@ -458,12 +787,47 @@ create table ebasic_json_node_varchar ( constraint pk_ebasic_json_node_varchar primary key (id) ); +create table ebasic_json_unmapped ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_ebasic_json_unmapped primary key (id) +); + create table e_basic_ndc ( id integer auto_increment not null, name varchar(255), constraint pk_e_basic_ndc primary key (id) ); +create table ebasic_no_sdchild ( + id bigint auto_increment not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + constraint pk_ebasic_no_sdchild primary key (id) +); + +create table ebasic_sdchild ( + id bigint auto_increment not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_ebasic_sdchild primary key (id) +); + +create table ebasic_soft_delete ( + id bigint auto_increment not null, + name varchar(255), + description varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_ebasic_soft_delete primary key (id) +); + create table e_basicver ( id integer auto_increment not null, name varchar(255), @@ -476,21 +840,36 @@ create table e_basicver ( create table e_basic_withlife ( id bigint auto_increment not null, name varchar(255), + deleted tinyint(1) default 0 not null, version bigint not null, constraint pk_e_basic_withlife primary key (id) ); create table e_basicverucon ( id integer auto_increment not null, - name varchar(255), - other varchar(255), - other_one varchar(255), + name varchar(127), + other varchar(127), + other_one varchar(127), description varchar(255), last_update datetime(6) not null, constraint uq_e_basicverucon_name unique (name), + constraint uq_e_basicverucon_other_other_one unique (other,other_one), constraint pk_e_basicverucon primary key (id) ); +create table e_col_ab ( + id bigint auto_increment not null, + column_a varchar(255), + column_b varchar(255), + constraint pk_e_col_ab primary key (id) +); + +create table ecustom_id ( + id varchar(127) not null, + name varchar(255), + constraint pk_ecustom_id primary key (id) +); + create table eemb_inner ( id integer auto_increment not null, nome_inner varchar(255), @@ -522,6 +901,8 @@ create table egen_props ( odt_updated datetime(6) not null, zdt_created datetime(6) not null, zdt_updated datetime(6) not null, + instant_created datetime(6) not null, + instant_updated datetime(6) not null, long_created bigint not null, long_updated bigint not null, constraint pk_egen_props primary key (id) @@ -535,11 +916,15 @@ create table einvoice ( ship_street varchar(255), ship_suburb varchar(255), ship_city varchar(255), - street varchar(255), - suburb varchar(255), - city varchar(255), + ship_status varchar(3), + bill_street varchar(255), + bill_suburb varchar(255), + bill_city varchar(255), + bill_status varchar(3), version bigint not null, - constraint ck_einvoice_state check (state in (0,1,2)), + constraint ck_einvoice_state check ( state in (0,1,2)), + constraint ck_einvoice_ship_status check ( ship_status in ('ONE','TWO')), + constraint ck_einvoice_bill_status check ( bill_status in ('ONE','TWO')), constraint pk_einvoice primary key (id) ); @@ -599,17 +984,130 @@ create table eperson ( notes varchar(255), street varchar(255), suburb varchar(255), - city varchar(255), + addr_city varchar(255), + addr_status varchar(3), version bigint not null, + constraint ck_eperson_addr_status check ( addr_status in ('ONE','TWO')), constraint pk_eperson primary key (id) ); +create table e_person_online ( + id bigint auto_increment not null, + email varchar(127), + online_status tinyint(1) default 0 not null, + when_updated datetime(6) not null, + constraint uq_e_person_online_email unique (email), + constraint pk_e_person_online primary key (id) +); + create table esimple ( usertypeid integer auto_increment not null, name varchar(255), constraint pk_esimple primary key (usertypeid) ); +create table esoft_del_book ( + id bigint auto_increment not null, + book_title varchar(255), + lend_by_id bigint, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_book primary key (id) +); + +create table esoft_del_book_esoft_del_user ( + esoft_del_book_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_book_esoft_del_user primary key (esoft_del_book_id,esoft_del_user_id) +); + +create table esoft_del_down ( + id bigint auto_increment not null, + esoft_del_mid_id bigint not null, + down varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_down primary key (id) +); + +create table esoft_del_mid ( + id bigint auto_increment not null, + top_id bigint, + mid varchar(255), + up_id bigint, + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_mid primary key (id) +); + +create table esoft_del_one_a ( + id bigint auto_increment not null, + name varchar(255), + oneb_id bigint, + deleted tinyint(1) default 0 not null, + version bigint not null, + constraint uq_esoft_del_one_a_oneb_id unique (oneb_id), + constraint pk_esoft_del_one_a primary key (id) +); + +create table esoft_del_one_b ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_esoft_del_one_b primary key (id) +); + +create table esoft_del_role ( + id bigint auto_increment not null, + role_name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_role primary key (id) +); + +create table esoft_del_role_esoft_del_user ( + esoft_del_role_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_role_esoft_del_user primary key (esoft_del_role_id,esoft_del_user_id) +); + +create table esoft_del_top ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_top primary key (id) +); + +create table esoft_del_up ( + id bigint auto_increment not null, + up varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_up primary key (id) +); + +create table esoft_del_user ( + id bigint auto_increment not null, + user_name varchar(255), + version bigint not null, + deleted tinyint(1) default 0 not null, + constraint pk_esoft_del_user primary key (id) +); + +create table esoft_del_user_esoft_del_role ( + esoft_del_user_id bigint not null, + esoft_del_role_id bigint not null, + constraint pk_esoft_del_user_esoft_del_role primary key (esoft_del_user_id,esoft_del_role_id) +); + +create table esome_convert_type ( + id bigint auto_increment not null, + name varchar(255), + money decimal(38), + constraint pk_esome_convert_type primary key (id) +); + create table esome_type ( id integer auto_increment not null, currency varchar(3), @@ -624,6 +1122,14 @@ create table etrans_many ( constraint pk_etrans_many primary key (id) ); +create table rawinherit_uncle ( + id integer auto_increment not null, + name varchar(255), + parent_id bigint not null, + version bigint not null, + constraint pk_rawinherit_uncle primary key (id) +); + create table evanilla_collection ( id integer auto_increment not null, name varchar(255), @@ -640,11 +1146,11 @@ create table evanilla_collection_detail ( create table ewho_props ( id bigint auto_increment not null, name varchar(255), - who_created varchar(255) not null, - who_modified varchar(255) not null, version bigint not null, when_created datetime(6) not null, when_modified datetime(6) not null, + who_created varchar(255) not null, + who_modified varchar(255) not null, constraint pk_ewho_props primary key (id) ); @@ -671,6 +1177,14 @@ create table td_parent ( constraint pk_td_parent primary key (parent_id) ); +create table empl ( + id bigint auto_increment not null, + name varchar(255), + age integer, + default_address_id bigint, + constraint pk_empl primary key (id) +); + create table feature_desc ( id integer auto_increment not null, name varchar(255), @@ -709,9 +1223,27 @@ create table gen_key_table ( constraint pk_gen_key_table primary key (id) ); +create table grand_parent_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + family_name varchar(255), + address varchar(255), + constraint pk_grand_parent_person primary key (identifier) +); + +create table survey_group ( + id bigint auto_increment not null, + name varchar(255), + categoryobjectid bigint, + sequence_number integer not null, + constraint pk_survey_group primary key (id) +); + create table c_group ( id bigint auto_increment not null, - inactive tinyint(1) default 0, + inactive tinyint(1) default 0 not null, name varchar(255), version bigint not null, when_created datetime(6) not null, @@ -719,6 +1251,58 @@ create table c_group ( constraint pk_c_group primary key (id) ); +create table he_doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_he_doc primary key (id) +); + +create table hx_link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hx_link primary key (id) +); + +create table hx_link_doc ( + hx_link_id bigint not null, + he_doc_id bigint not null, + constraint pk_hx_link_doc primary key (hx_link_id,he_doc_id) +); + +create table hi_doc ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hi_doc primary key (id) +); + +create table hi_link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_hi_link primary key (id) +); + +create table hi_link_doc ( + hi_link_id bigint not null, + hi_doc_id bigint not null, + constraint pk_hi_link_doc primary key (hi_link_id,hi_doc_id) +); + create table imrelated ( id bigint auto_increment not null, name varchar(255), @@ -727,17 +1311,17 @@ create table imrelated ( ); create table imroot ( - dtype varchar(10) not null, + dtype varchar(31) not null, id bigint auto_increment not null, + name varchar(255), title varchar(255), when_title datetime(6), - name varchar(255), constraint pk_imroot primary key (id) ); create table ixresource ( dtype varchar(255), - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_ixresource primary key (id) ); @@ -783,11 +1367,11 @@ create table drel_invoice ( create table item ( customer integer not null, - itemnumber varchar(255) not null, + itemnumber varchar(127) not null, description varchar(255), units varchar(255), - type integer, - region integer, + type integer not null, + region integer not null, date_modified datetime(6), date_created datetime(6), modified_by varchar(255), @@ -796,6 +1380,54 @@ create table item ( constraint pk_item primary key (customer,itemnumber) ); +create table monkey ( + mid bigint auto_increment not null, + name varchar(255), + food_preference varchar(255), + version bigint not null, + constraint pk_monkey primary key (mid) +); + +create table trainer ( + tid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_trainer primary key (tid) +); + +create table trainer_monkey ( + trainer_tid bigint not null, + monkey_mid bigint not null, + constraint uq_trainer_monkey_mid unique (monkey_mid), + constraint pk_trainer_monkey primary key (trainer_tid,monkey_mid) +); + +create table troop ( + pid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_troop primary key (pid) +); + +create table troop_monkey ( + troop_pid bigint not null, + monkey_mid bigint not null, + constraint uq_troop_monkey_mid unique (monkey_mid), + constraint pk_troop_monkey primary key (troop_pid,monkey_mid) +); + +create table l2_cldf_reset_bean ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_l2_cldf_reset_bean primary key (id) +); + +create table l2_cldf_reset_bean_child ( + id bigint auto_increment not null, + parent_id bigint, + constraint pk_l2_cldf_reset_bean_child primary key (id) +); + create table level1 ( id bigint auto_increment not null, name varchar(255), @@ -838,6 +1470,33 @@ create table level4 ( constraint pk_level4 primary key (id) ); +create table link ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + deleted tinyint(1) default 0 not null, + constraint pk_link primary key (id) +); + +create table link_draft ( + id bigint auto_increment not null, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + dirty tinyint(1) default 0 not null, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + deleted tinyint(1) default 0 not null, + constraint pk_link_draft primary key (id) +); + create table la_attr_value ( id integer auto_increment not null, name varchar(255), @@ -866,7 +1525,7 @@ create table non_updateprop ( non_enum varchar(5), name varchar(255), note varchar(255), - constraint ck_non_updateprop_non_enum check (non_enum in ('BEGIN','END')), + constraint ck_non_updateprop_non_enum check ( non_enum in ('BEGIN','END')), constraint pk_non_updateprop primary key (id) ); @@ -889,7 +1548,7 @@ create table mprinter ( create table mprinter_state ( id bigint auto_increment not null, - flags bigint, + flags bigint not null, printer_id bigint, version bigint not null, constraint pk_mprinter_state primary key (id) @@ -939,6 +1598,32 @@ create table muser_type ( constraint pk_muser_type primary key (id) ); +create table mail_box ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mail_box primary key (id) +); + +create table mail_user ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mail_user primary key (id) +); + +create table mail_user_inbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_inbox primary key (mail_user_id,mail_box_id) +); + +create table mail_user_outbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_outbox primary key (mail_user_id,mail_box_id) +); + create table map_super_actual ( id bigint auto_increment not null, name varchar(255), @@ -979,6 +1664,53 @@ create table mnoc_user_mnoc_role ( constraint pk_mnoc_user_mnoc_role primary key (mnoc_user_user_id,mnoc_role_role_id) ); +create table mny_a ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_a primary key (id) +); + +create table mny_b ( + id bigint auto_increment not null, + name varchar(255), + a_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_b primary key (id) +); + +create table mny_b_mny_c ( + mny_b_id bigint not null, + mny_c_id bigint not null, + constraint pk_mny_b_mny_c primary key (mny_b_id,mny_c_id) +); + +create table mny_c ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_mny_c primary key (id) +); + +create table mny_topic ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_mny_topic primary key (id) +); + +create table subtopics ( + topic bigint not null, + subtopic bigint not null, + constraint pk_subtopics primary key (topic,subtopic) +); + create table mp_role ( id bigint auto_increment not null, mp_user_id bigint not null, @@ -993,10 +1725,38 @@ create table mp_user ( constraint pk_mp_user primary key (id) ); +create table ms_many_a ( + aid bigint auto_increment not null, + name varchar(255), + ms_many_a_many_b tinyint(1) default 0 not null, + ms_many_b tinyint(1) default 0 not null, + deleted tinyint(1) default 0 not null, + constraint pk_ms_many_a primary key (aid) +); + +create table ms_many_a_many_b ( + ms_many_a_aid bigint not null, + ms_many_b_bid bigint not null, + constraint pk_ms_many_a_many_b primary key (ms_many_a_aid,ms_many_b_bid) +); + +create table ms_many_b ( + bid bigint auto_increment not null, + name varchar(255), + deleted tinyint(1) default 0 not null, + constraint pk_ms_many_b primary key (bid) +); + +create table ms_many_b_many_a ( + ms_many_b_bid bigint not null, + ms_many_a_aid bigint not null, + constraint pk_ms_many_b_many_a primary key (ms_many_b_bid,ms_many_a_aid) +); + create table my_lob_size ( id integer auto_increment not null, name varchar(255), - my_count integer, + my_count integer not null, my_lob longtext, constraint pk_my_lob_size primary key (id) ); @@ -1033,6 +1793,23 @@ create table o_cached_bean_child ( constraint pk_o_cached_bean_child primary key (id) ); +create table o_cached_natkey ( + id bigint auto_increment not null, + store varchar(255), + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey primary key (id) +); + +create table o_cached_natkey3 ( + id bigint auto_increment not null, + store varchar(255), + code integer not null, + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey3 primary key (id) +); + create table ocar ( id integer auto_increment not null, vin varchar(255), @@ -1043,8 +1820,18 @@ create table ocar ( constraint pk_ocar primary key (id) ); +create table ocompany ( + id integer auto_increment not null, + corp_id varchar(50), + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + constraint uq_ocompany_corp_id unique (corp_id), + constraint pk_ocompany primary key (id) +); + create table oengine ( - engine_id binary(16) not null, + engine_id varchar(40) not null, short_desc varchar(255), car_id integer, version integer not null, @@ -1053,7 +1840,7 @@ create table oengine ( ); create table ogear_box ( - id binary(16) not null, + id varchar(40) not null, box_desc varchar(255), box_size integer, car_id integer, @@ -1062,6 +1849,32 @@ create table ogear_box ( constraint pk_ogear_box primary key (id) ); +create table oroad_show_msg ( + id integer auto_increment not null, + company_id integer not null, + cretime datetime(6) not null, + updtime datetime(6) not null, + version bigint not null, + constraint uq_oroad_show_msg_company_id unique (company_id), + constraint pk_oroad_show_msg primary key (id) +); + +create table om_ordered_detail ( + id bigint auto_increment not null, + name varchar(255), + master_id bigint, + version bigint not null, + sort_order integer, + constraint pk_om_ordered_detail primary key (id) +); + +create table om_ordered_master ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_om_ordered_master primary key (id) +); + create table o_order ( id integer auto_increment not null, status integer, @@ -1070,13 +1883,13 @@ create table o_order ( kcustomer_id integer not null, cretime datetime(6) not null, updtime datetime(6) not null, - constraint ck_o_order_status check (status in (0,1,2,3)), + constraint ck_o_order_status check ( status in (0,1,2,3)), constraint pk_o_order primary key (id) ); create table o_order_detail ( id integer auto_increment not null, - order_id integer, + order_id integer not null, order_qty integer, ship_qty integer, unit_price double, @@ -1087,15 +1900,15 @@ create table o_order_detail ( ); create table s_orders ( - uuid varchar(255) not null, + uuid varchar(40) not null, constraint pk_s_orders primary key (uuid) ); create table s_order_items ( - uuid varchar(255) not null, + uuid varchar(40) not null, product_variant_uuid varchar(255), - order_uuid varchar(255), - quantity integer, + order_uuid varchar(40), + quantity integer not null, amount decimal(38), constraint pk_s_order_items primary key (uuid) ); @@ -1110,6 +1923,27 @@ create table or_order_ship ( constraint pk_or_order_ship primary key (id) ); +create table organisation ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_organisation primary key (id) +); + +create table oto_bchild ( + master_id bigint auto_increment not null, + child varchar(255), + constraint pk_oto_bchild primary key (master_id) +); + +create table oto_bmaster ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_oto_bmaster primary key (id) +); + create table oto_child ( id integer auto_increment not null, name varchar(255), @@ -1118,12 +1952,102 @@ create table oto_child ( constraint pk_oto_child primary key (id) ); +create table oto_cust ( + cid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_oto_cust primary key (cid) +); + +create table oto_cust_address ( + aid bigint auto_increment not null, + line1 varchar(255), + line2 varchar(255), + line3 varchar(255), + customer_cid bigint, + version bigint not null, + constraint uq_oto_cust_address_customer_cid unique (customer_cid), + constraint pk_oto_cust_address primary key (aid) +); + create table oto_master ( id bigint auto_increment not null, name varchar(255), constraint pk_oto_master primary key (id) ); +create table oto_prime ( + pid bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_oto_prime primary key (pid) +); + +create table oto_prime_extra ( + eid bigint not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_prime_extra primary key (eid) +); + +create table oto_th_many ( + id bigint auto_increment not null, + oto_th_top_id bigint not null, + many varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_oto_th_many primary key (id) +); + +create table oto_th_one ( + id bigint auto_increment not null, + one tinyint(1) default 0 not null, + many_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint uq_oto_th_one_many_id unique (many_id), + constraint pk_oto_th_one primary key (id) +); + +create table oto_th_top ( + id bigint auto_increment not null, + topp varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_oto_th_top primary key (id) +); + +create table oto_ubprime ( + pid varchar(40) not null, + name varchar(255), + version bigint not null, + constraint pk_oto_ubprime primary key (pid) +); + +create table oto_ubprime_extra ( + eid varchar(40) not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_ubprime_extra primary key (eid) +); + +create table oto_uprime ( + pid varchar(40) not null, + name varchar(255), + version bigint not null, + constraint pk_oto_uprime primary key (pid) +); + +create table oto_uprime_extra ( + eid varchar(40) not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_uprime_extra primary key (eid) +); + create table pfile ( id integer auto_increment not null, name varchar(255), @@ -1147,7 +2071,7 @@ create table pfile_content ( ); create table paggview ( - pview_id binary(16), + pview_id varchar(40), amount integer not null, constraint uq_paggview_pview_id unique (pview_id) ); @@ -1178,6 +2102,7 @@ create table rawinherit_parent ( type varchar(31) not null, id bigint auto_increment not null, val integer, + more varchar(255), constraint pk_rawinherit_parent primary key (id) ); @@ -1187,6 +2112,17 @@ create table rawinherit_parent_rawinherit_data ( constraint pk_rawinherit_parent_rawinherit_data primary key (rawinherit_parent_id,rawinherit_data_id) ); +create table parent_person ( + identifier integer auto_increment not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_parent_person primary key (identifier) +); + create table c_participation ( id bigint auto_increment not null, rating integer, @@ -1196,12 +2132,12 @@ create table c_participation ( version bigint not null, when_created datetime(6) not null, when_modified datetime(6) not null, - constraint ck_c_participation_type check (type in (0,1)), + constraint ck_c_participation_type check ( type in (0,1)), constraint pk_c_participation primary key (id) ); create table mt_permission ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_mt_permission primary key (id) ); @@ -1248,6 +2184,14 @@ create table phones ( constraint pk_phones primary key (id) ); +create table primary_revision ( + id bigint not null, + revision integer not null, + name varchar(255), + version bigint not null, + constraint pk_primary_revision primary key (id,revision) +); + create table o_product ( id integer auto_increment not null, sku varchar(20), @@ -1258,29 +2202,37 @@ create table o_product ( ); create table pp ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), value varchar(100) not null, constraint pk_pp primary key (id) ); create table pp_to_ww ( - pp_id binary(16) not null, - ww_id binary(16) not null, + pp_id varchar(40) not null, + ww_id varchar(40) not null, constraint pk_pp_to_ww primary key (pp_id,ww_id) ); +create table question ( + id bigint auto_increment not null, + name varchar(255), + groupobjectid bigint, + sequence_number integer not null, + constraint pk_question primary key (id) +); + create table rcustomer ( - company varchar(255) not null, - name varchar(255) not null, + company varchar(127) not null, + name varchar(127) not null, description varchar(255), constraint pk_rcustomer primary key (company,name) ); create table r_orders ( - company varchar(255) not null, + company varchar(127) not null, order_number integer not null, - customername varchar(255), + customername varchar(127), item varchar(255), constraint pk_r_orders primary key (company,order_number) ); @@ -1300,28 +2252,29 @@ create table resourcefile ( constraint pk_resourcefile primary key (id) ); -create table mt_role ( - id binary(16) not null, - name varchar(50), - tenant_id binary(16), - version bigint not null, - constraint pk_mt_role primary key (id) -); - -create table mt_role_permission ( - mt_role_id binary(16) not null, - mt_permission_id binary(16) not null, - constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) -); - create table em_role ( id bigint auto_increment not null, name varchar(255), constraint pk_em_role primary key (id) ); +create table mt_role ( + id varchar(40) not null, + name varchar(50), + tenant_id varchar(40), + version bigint not null, + constraint pk_mt_role primary key (id) +); + +create table mt_role_permission ( + mt_role_id varchar(40) not null, + mt_permission_id varchar(40) not null, + constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) +); + create table f_second ( id bigint auto_increment not null, + mod_name varchar(255), first bigint, title varchar(255), constraint uq_f_second_first unique (first), @@ -1336,7 +2289,7 @@ create table section ( cretime datetime(6) not null, updtime datetime(6) not null, version bigint not null, - constraint ck_section_type check (type in (0,1)), + constraint ck_section_type check ( type in (0,1)), constraint pk_section primary key (id) ); @@ -1366,7 +2319,7 @@ create table some_enum_bean ( id bigint auto_increment not null, some_enum integer, name varchar(255), - constraint ck_some_enum_bean_some_enum check (some_enum in (0,1)), + constraint ck_some_enum_bean_some_enum check ( some_enum in (0,1)), constraint pk_some_enum_bean primary key (id) ); @@ -1391,17 +2344,16 @@ create table some_new_types_bean ( instant datetime(6), zone_id varchar(60), zone_offset varchar(60), + path varchar(255), + period varchar(20), version bigint not null, - constraint ck_some_new_types_bean_dow check (dow in ('1','2','3','4','5','6','7')), - constraint ck_some_new_types_bean_mth check (mth in ('1','2','3','4','5','6','7','8','9','10','11','12')), + constraint ck_some_new_types_bean_dow check ( dow in (1,2,3,4,5,6,7)), + constraint ck_some_new_types_bean_mth check ( mth in (1,2,3,4,5,6,7,8,9,10,11,12)), constraint pk_some_new_types_bean primary key (id) ); create table some_period_bean ( id bigint auto_increment not null, - period_years integer, - period_months integer, - period_days integer, anniversary date, version bigint not null, constraint pk_some_period_bean primary key (id) @@ -1431,6 +2383,12 @@ create table sub_type ( constraint pk_sub_type primary key (sub_type_id) ); +create table survey ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_survey primary key (id) +); + create table tbytes_only ( id integer auto_increment not null, content longblob, @@ -1439,11 +2397,39 @@ create table tbytes_only ( create table tcar ( type varchar(31) not null, - plate_no varchar(255) not null, + plate_no varchar(32) not null, truckload bigint, constraint pk_tcar primary key (plate_no) ); +create table tevent ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + constraint pk_tevent primary key (id) +); + +create table tevent_many ( + id bigint auto_increment not null, + description varchar(255), + event_id bigint, + units integer not null, + amount double not null, + version bigint not null, + constraint pk_tevent_many primary key (id) +); + +create table tevent_one ( + id bigint auto_increment not null, + name varchar(255), + status integer, + event_id bigint, + version bigint not null, + constraint ck_tevent_one_status check ( status in (0,1)), + constraint uq_tevent_one_event_id unique (event_id), + constraint pk_tevent_one primary key (id) +); + create table tint_root ( my_type integer(3) not null, id integer auto_increment not null, @@ -1470,7 +2456,7 @@ create table t_oneb ( id integer auto_increment not null, name varchar(255), description varchar(255), - active tinyint(1) default 0, + active tinyint(1) default 0 not null, constraint pk_t_oneb primary key (id) ); @@ -1478,8 +2464,10 @@ create table t_detail_with_other_namexxxyy ( id integer auto_increment not null, name varchar(255), description varchar(255), - active tinyint(1) default 0, + some_unique_value varchar(127), + active tinyint(1) default 0 not null, master_id integer, + constraint uq_t_detail_with_other_namexxxyy_some_unique_value unique (some_unique_value), constraint pk_t_detail_with_other_namexxxyy primary key (id) ); @@ -1487,7 +2475,7 @@ create table ts_detail_two ( id integer auto_increment not null, name varchar(255), description varchar(255), - active tinyint(1) default 0, + active tinyint(1) default 0 not null, master_id integer, constraint pk_ts_detail_two primary key (id) ); @@ -1496,7 +2484,7 @@ create table t_atable_thatisrelatively ( id integer auto_increment not null, name varchar(255), description varchar(255), - active tinyint(1) default 0, + active tinyint(1) default 0 not null, constraint pk_t_atable_thatisrelatively primary key (id) ); @@ -1504,19 +2492,19 @@ create table ts_master_two ( id integer auto_increment not null, name varchar(255), description varchar(255), - active tinyint(1) default 0, + active tinyint(1) default 0 not null, constraint pk_ts_master_two primary key (id) ); create table tuuid_entity ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_tuuid_entity primary key (id) ); create table twheel ( id bigint auto_increment not null, - owner_plate_no varchar(255) not null, + owner_plate_no varchar(32) not null, constraint pk_twheel primary key (id) ); @@ -1528,16 +2516,20 @@ create table twith_pre_insert ( ); create table mt_tenant ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), version bigint not null, constraint pk_mt_tenant primary key (id) ); -create table sa_tire ( - id bigint auto_increment not null, - version integer not null, - constraint pk_sa_tire primary key (id) +create table test_annotation_base_entity ( + direct varchar(255), + meta varchar(255), + mixed varchar(255), + constraint_annotation varchar(40), + null1 varchar(255) not null, + null2 varchar(255), + null3 varchar(255) ); create table tire ( @@ -1548,6 +2540,12 @@ create table tire ( constraint pk_tire primary key (id) ); +create table sa_tire ( + id bigint auto_increment not null, + version integer not null, + constraint pk_sa_tire primary key (id) +); + create table trip ( id integer auto_increment not null, vehicle_driver_id integer, @@ -1575,6 +2573,14 @@ create table type ( constraint pk_type primary key (customer,type) ); +create table tz_bean ( + id bigint auto_increment not null, + moda varchar(255), + ts datetime(6), + tstz datetime(6), + constraint pk_tz_bean primary key (id) +); + create table ut_detail ( id integer auto_increment not null, utmaster_id integer not null, @@ -1594,22 +2600,29 @@ create table ut_master ( ); create table uuone ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), constraint pk_uuone primary key (id) ); create table uutwo ( - id binary(16) not null, + id varchar(40) not null, name varchar(255), - master_id binary(16), + master_id varchar(40), constraint pk_uutwo primary key (id) ); -create table em_user ( +create table c_user ( id bigint auto_increment not null, + inactive tinyint(1) default 0 not null, name varchar(255), - constraint pk_em_user primary key (id) + email varchar(255), + password_hash varchar(255), + group_id bigint, + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + constraint pk_c_user primary key (id) ); create table tx_user ( @@ -1618,16 +2631,17 @@ create table tx_user ( constraint pk_tx_user primary key (id) ); -create table c_user ( +create table g_user ( id bigint auto_increment not null, - inactive tinyint(1) default 0, - name varchar(255), - email varchar(255), - group_id bigint, + username varchar(255), version bigint not null, - when_created datetime(6) not null, - when_modified datetime(6) not null, - constraint pk_c_user primary key (id) + constraint pk_g_user primary key (id) +); + +create table em_user ( + id bigint auto_increment not null, + name varchar(255), + constraint pk_em_user primary key (id) ); create table oto_user ( @@ -1655,10 +2669,13 @@ create table vehicle ( cretime datetime(6) not null, updtime datetime(6) not null, version bigint not null, - truck_ref_id integer, - capacity double, + siz varchar(1), driver varchar(255), car_ref_id integer, + notes varchar(255), + truck_ref_id integer, + capacity double, + constraint ck_vehicle_siz check ( siz in ('S','M','L','H')), constraint pk_vehicle primary key (id) ); @@ -1694,22 +2711,34 @@ create table sa_wheel ( constraint pk_sa_wheel primary key (id) ); -create table sp_car_wheel ( - id bigint auto_increment not null, - version integer not null, - constraint pk_sp_car_wheel primary key (id) -); - create table wheel ( id bigint auto_increment not null, version integer not null, constraint pk_wheel primary key (id) ); +create table sp_car_wheel ( + id bigint auto_increment not null, + version integer not null, + constraint pk_sp_car_wheel primary key (id) +); + +create table g_who_props_otm ( + id bigint auto_increment not null, + name varchar(255), + version bigint not null, + when_created datetime(6) not null, + when_modified datetime(6) not null, + who_created_id bigint, + who_modified_id bigint, + constraint pk_g_who_props_otm primary key (id) +); + create table with_zero ( id bigint auto_increment not null, name varchar(255), parent_id integer, + lang varchar(2) default 'en' not null, version bigint not null, constraint pk_with_zero primary key (id) ); @@ -1721,8 +2750,8 @@ create table parent ( ); create table wview ( - id binary(16) not null, - name varchar(255) not null, + id varchar(40) not null, + name varchar(127) not null, constraint uq_wview_name unique (name), constraint pk_wview primary key (id) ); @@ -1734,133 +2763,288 @@ create table zones ( constraint pk_zones primary key (id) ); -alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; +create index ix_contact_last_name_first_name on contact (last_name,first_name); +create index ix_e_basic_name on e_basic (name); create index ix_bar_foo_id on bar (foo_id); +alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; + +create index ix_addr_employee_id on addr (employee_id); +alter table addr add constraint fk_addr_employee_id foreign key (employee_id) references empl (id) on delete restrict on update restrict; -alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; create index ix_o_address_country_code on o_address (country_code); +alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; -alter table animals add constraint fk_animals_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; -create index ix_animals_shelter_id on animals (shelter_id); +alter table album add constraint fk_album_cover_id foreign key (cover_id) references cover (id) on delete restrict on update restrict; + +create index ix_animal_shelter_id on animal (shelter_id); +alter table animal add constraint fk_animal_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; -alter table attribute add constraint fk_attribute_attribute_holder_id foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; create index ix_attribute_attribute_holder_id on attribute (attribute_holder_id); +alter table attribute add constraint fk_attribute_attribute_holder_id foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; -alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; create index ix_bbookmark_user_id on bbookmark (user_id); +alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; + +create index ix_bsite_user_site_id on bsite_user (site_id); +alter table bsite_user add constraint fk_bsite_user_site_id foreign key (site_id) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_user_id on bsite_user (user_id); +alter table bsite_user add constraint fk_bsite_user_user_id foreign key (user_id) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_site on bsite_user_b (site); +alter table bsite_user_b add constraint fk_bsite_user_b_site foreign key (site) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_usr on bsite_user_b (usr); +alter table bsite_user_b add constraint fk_bsite_user_b_usr foreign key (usr) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_site_uid on bsite_user_c (site_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_site_uid foreign key (site_uid) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_user_uid on bsite_user_c (user_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_user_uid foreign key (user_uid) references buser (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_agent_invoice foreign key (agent_invoice) references drel_invoice (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_client_invoice foreign key (client_invoice) references drel_invoice (id) on delete restrict on update restrict; -alter table ckey_detail add constraint fk_ckey_detail_ckey_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -create index ix_ckey_detail_one_key_two_key on ckey_detail (one_key,two_key); +create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); +alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_product_configuration_id foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; create index ix_calculation_result_product_configuration_id on calculation_result (product_configuration_id); +alter table calculation_result add constraint fk_calculation_result_product_configuration_id foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_group_configuration_id foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; create index ix_calculation_result_group_configuration_id on calculation_result (group_configuration_id); +alter table calculation_result add constraint fk_calculation_result_group_configuration_id foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; +create index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels (car); alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_car foreign key (car) references sp_car_car (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_car on sp_car_car_wheels (car); +create index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels (wheel); alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_wheel foreign key (wheel) references sp_car_wheel (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_wheel on sp_car_car_wheels (wheel); -alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; +create index ix_car_accessory_fuse_id on car_accessory (fuse_id); +alter table car_accessory add constraint fk_car_accessory_fuse_id foreign key (fuse_id) references car_fuse (id) on delete restrict on update restrict; + create index ix_car_accessory_car_id on car_accessory (car_id); +alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; + +create index ix_category_surveyobjectid on category (surveyobjectid); +alter table category add constraint fk_category_surveyobjectid foreign key (surveyobjectid) references survey (id) on delete restrict on update restrict; + +create index ix_child_person_some_bean_id on child_person (some_bean_id); +alter table child_person add constraint fk_child_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_child_person_parent_identifier on child_person (parent_identifier); +alter table child_person add constraint fk_child_person_parent_identifier foreign key (parent_identifier) references parent_person (identifier) on delete restrict on update restrict; -alter table configuration add constraint fk_configuration_configurations_id foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; create index ix_configuration_configurations_id on configuration (configurations_id); +alter table configuration add constraint fk_configuration_configurations_id foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; create index ix_contact_customer_id on contact (customer_id); +alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; create index ix_contact_group_id on contact (group_id); +alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; -alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; create index ix_contact_note_contact_id on contact_note (contact_id); +alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; -alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_conversation_group_id on c_conversation (group_id); +alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_billing_address_id foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; create index ix_o_customer_billing_address_id on o_customer (billing_address_id); +alter table o_customer add constraint fk_o_customer_billing_address_id foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_shipping_address_id foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; create index ix_o_customer_shipping_address_id on o_customer (shipping_address_id); +alter table o_customer add constraint fk_o_customer_shipping_address_id foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_dcredit on dcredit_drol (dcredit_id); +alter table dcredit_drol add constraint fk_dcredit_drol_dcredit foreign key (dcredit_id) references dcredit (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_drol on dcredit_drol (drol_id); +alter table dcredit_drol add constraint fk_dcredit_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_drot_drol_drot on drot_drol (drot_id); +alter table drot_drol add constraint fk_drot_drol_drot foreign key (drot_id) references drot (id) on delete restrict on update restrict; + +create index ix_drot_drol_drol on drot_drol (drol_id); +alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_dfk_cascade_one_id on dfk_cascade (one_id); +alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade; + +create index ix_dfk_set_null_one_id on dfk_set_null (one_id); +alter table dfk_set_null add constraint fk_dfk_set_null_one_id foreign key (one_id) references dfk_one (id) on delete set null on update set null; + +alter table doc add constraint fk_doc_id foreign key (id) references doc_draft (id) on delete restrict on update restrict; + +create index ix_doc_link_doc on doc_link (doc_id); +alter table doc_link add constraint fk_doc_link_doc foreign key (doc_id) references doc (id) on delete restrict on update restrict; + +create index ix_doc_link_link on doc_link (link_id); +alter table doc_link add constraint fk_doc_link_link foreign key (link_id) references link (id) on delete restrict on update restrict; + +alter table document add constraint fk_document_id foreign key (id) references document_draft (id) on delete restrict on update restrict; + +create index ix_document_organisation_id on document (organisation_id); +alter table document add constraint fk_document_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_draft_organisation_id on document_draft (organisation_id); +alter table document_draft add constraint fk_document_draft_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_media_document_id on document_media (document_id); +alter table document_media add constraint fk_document_media_document_id foreign key (document_id) references document (id) on delete restrict on update restrict; + +create index ix_document_media_draft_document_id on document_media_draft (document_id); +alter table document_media_draft add constraint fk_document_media_draft_document_id foreign key (document_id) references document_draft (id) on delete restrict on update restrict; + +create index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail (owner_id); +alter table ebasic_json_map_detail add constraint fk_ebasic_json_map_detail_owner_id foreign key (owner_id) references ebasic_json_map (id) on delete restrict on update restrict; + +create index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild (owner_id); +alter table ebasic_no_sdchild add constraint fk_ebasic_no_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; + +create index ix_ebasic_sdchild_owner_id on ebasic_sdchild (owner_id); +alter table ebasic_sdchild add constraint fk_ebasic_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; -alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; create index ix_eemb_inner_outer_id on eemb_inner (outer_id); +alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; -alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; create index ix_einvoice_person_id on einvoice (person_id); +alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; -alter table enull_collection_detail add constraint fk_enull_collection_detail_enull_collection_id foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; create index ix_enull_collection_detail_enull_collection_id on enull_collection_detail (enull_collection_id); +alter table enull_collection_detail add constraint fk_enull_collection_detail_enull_collection_id foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; -alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; create index ix_eopt_one_a_b_id on eopt_one_a (b_id); +alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; -alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; create index ix_eopt_one_b_c_id on eopt_one_b (c_id); +alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_lend_by_id on esoft_del_book (lend_by_id); +alter table esoft_del_book add constraint fk_esoft_del_book_lend_by_id foreign key (lend_by_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user (esoft_del_book_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_book foreign key (esoft_del_book_id) references esoft_del_book (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user (esoft_del_user_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down (esoft_del_mid_id); +alter table esoft_del_down add constraint fk_esoft_del_down_esoft_del_mid_id foreign key (esoft_del_mid_id) references esoft_del_mid (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_top_id on esoft_del_mid (top_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_top_id foreign key (top_id) references esoft_del_top (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_up_id on esoft_del_mid (up_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_up_id foreign key (up_id) references esoft_del_up (id) on delete restrict on update restrict; + +alter table esoft_del_one_a add constraint fk_esoft_del_one_a_oneb_id foreign key (oneb_id) references esoft_del_one_b (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user (esoft_del_role_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user (esoft_del_user_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role (esoft_del_user_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role (esoft_del_role_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_rawinherit_uncle_parent_id on rawinherit_uncle (parent_id); +alter table rawinherit_uncle add constraint fk_rawinherit_uncle_parent_id foreign key (parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_evanilla_collection_id foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; create index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail (evanilla_collection_id); +alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_evanilla_collection_id foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; -alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; create index ix_td_child_parent_id on td_child (parent_id); +alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; + +create index ix_empl_default_address_id on empl (default_address_id); +alter table empl add constraint fk_empl_default_address_id foreign key (default_address_id) references addr (id) on delete restrict on update restrict; + +create index ix_grand_parent_person_some_bean_id on grand_parent_person (some_bean_id); +alter table grand_parent_person add constraint fk_grand_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_survey_group_categoryobjectid on survey_group (categoryobjectid); +alter table survey_group add constraint fk_survey_group_categoryobjectid foreign key (categoryobjectid) references category (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_hx_link on hx_link_doc (hx_link_id); +alter table hx_link_doc add constraint fk_hx_link_doc_hx_link foreign key (hx_link_id) references hx_link (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_he_doc on hx_link_doc (he_doc_id); +alter table hx_link_doc add constraint fk_hx_link_doc_he_doc foreign key (he_doc_id) references he_doc (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_link on hi_link_doc (hi_link_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_link foreign key (hi_link_id) references hi_link (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_doc on hi_link_doc (hi_doc_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_doc foreign key (hi_doc_id) references hi_doc (id) on delete restrict on update restrict; -alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; create index ix_imrelated_owner_id on imrelated (owner_id); +alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; -alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; create index ix_info_contact_company_id on info_contact (company_id); +alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table info_customer add constraint fk_info_customer_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table inner_report add constraint fk_inner_report_forecast_id foreign key (forecast_id) references stockforecast (id) on delete restrict on update restrict; -alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; create index ix_drel_invoice_booking on drel_invoice (booking); +alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; -alter table item add constraint fk_item_type foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -create index ix_item_customer_type on item (customer,type); +create index ix_item_etype on item (customer,type); +alter table item add constraint fk_item_etype foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -alter table item add constraint fk_item_region foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; -create index ix_item_customer_region on item (customer,region); +create index ix_item_eregion on item (customer,region); +alter table item add constraint fk_item_eregion foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; +alter table trainer_monkey add constraint fk_trainer_monkey_trainer foreign key (trainer_tid) references trainer (tid) on delete restrict on update restrict; + +alter table trainer_monkey add constraint fk_trainer_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_troop foreign key (troop_pid) references troop (pid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +create index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child (parent_id); +alter table l2_cldf_reset_bean_child add constraint fk_l2_cldf_reset_bean_child_parent_id foreign key (parent_id) references l2_cldf_reset_bean (id) on delete restrict on update restrict; + +create index ix_level1_level4_level1 on level1_level4 (level1_id); alter table level1_level4 add constraint fk_level1_level4_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level4_level1_id on level1_level4 (level1_id); +create index ix_level1_level4_level4 on level1_level4 (level4_id); alter table level1_level4 add constraint fk_level1_level4_level4 foreign key (level4_id) references level4 (id) on delete restrict on update restrict; -create index ix_level1_level4_level4_id on level1_level4 (level4_id); +create index ix_level1_level2_level1 on level1_level2 (level1_id); alter table level1_level2 add constraint fk_level1_level2_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level2_level1_id on level1_level2 (level1_id); +create index ix_level1_level2_level2 on level1_level2 (level2_id); alter table level1_level2 add constraint fk_level1_level2_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level1_level2_level2_id on level1_level2 (level2_id); +create index ix_level2_level3_level2 on level2_level3 (level2_id); alter table level2_level3 add constraint fk_level2_level3_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level2_level3_level2_id on level2_level3 (level2_id); +create index ix_level2_level3_level3 on level2_level3 (level3_id); alter table level2_level3 add constraint fk_level2_level3_level3 foreign key (level3_id) references level3 (id) on delete restrict on update restrict; -create index ix_level2_level3_level3_id on level2_level3 (level3_id); +alter table link add constraint fk_link_id foreign key (id) references link_draft (id) on delete restrict on update restrict; + +create index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute (la_attr_value_id); alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_attr_value foreign key (la_attr_value_id) references la_attr_value (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_la_attr_value_id on la_attr_value_attribute (la_attr_value_id); +create index ix_la_attr_value_attribute_attribute on la_attr_value_attribute (attribute_id); alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_attribute foreign key (attribute_id) references attribute (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_attribute_id on la_attr_value_attribute (attribute_id); -alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; create index ix_mprinter_current_state_id on mprinter (current_state_id); +alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_cyan_id foreign key (last_swap_cyan_id) references mprinter_state (id) on delete restrict on update restrict; @@ -1870,205 +3054,407 @@ alter table mprinter add constraint fk_mprinter_last_swap_yellow_id foreign key alter table mprinter add constraint fk_mprinter_last_swap_black_id foreign key (last_swap_black_id) references mprinter_state (id) on delete restrict on update restrict; -alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; create index ix_mprinter_state_printer_id on mprinter_state (printer_id); +alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; -alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; create index ix_mprofile_picture_id on mprofile (picture_id); +alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; +create index ix_mrole_muser_mrole on mrole_muser (mrole_roleid); alter table mrole_muser add constraint fk_mrole_muser_mrole foreign key (mrole_roleid) references mrole (roleid) on delete restrict on update restrict; -create index ix_mrole_muser_mrole_roleid on mrole_muser (mrole_roleid); +create index ix_mrole_muser_muser on mrole_muser (muser_userid); alter table mrole_muser add constraint fk_mrole_muser_muser foreign key (muser_userid) references muser (userid) on delete restrict on update restrict; -create index ix_mrole_muser_muser_userid on mrole_muser (muser_userid); -alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; create index ix_muser_user_type_id on muser (user_type_id); +alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_user on mail_user_inbox (mail_user_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_box on mail_user_inbox (mail_box_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_user on mail_user_outbox (mail_user_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_box on mail_user_outbox (mail_box_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; create index ix_c_message_conversation_id on c_message (conversation_id); +alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_message_user_id on c_message (user_id); +alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; +create index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role (mnoc_user_user_id); alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_user foreign key (mnoc_user_user_id) references mnoc_user (user_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_user_user_id on mnoc_user_mnoc_role (mnoc_user_user_id); +create index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role (mnoc_role_role_id); alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_role foreign key (mnoc_role_role_id) references mnoc_role (role_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_role_role_id on mnoc_user_mnoc_role (mnoc_role_role_id); -alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; +create index ix_mny_b_a_id on mny_b (a_id); +alter table mny_b add constraint fk_mny_b_a_id foreign key (a_id) references mny_a (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_b on mny_b_mny_c (mny_b_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_b foreign key (mny_b_id) references mny_b (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_c on mny_b_mny_c (mny_c_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_c foreign key (mny_c_id) references mny_c (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_1 on subtopics (topic); +alter table subtopics add constraint fk_subtopics_mny_topic_1 foreign key (topic) references mny_topic (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_2 on subtopics (subtopic); +alter table subtopics add constraint fk_subtopics_mny_topic_2 foreign key (subtopic) references mny_topic (id) on delete restrict on update restrict; + create index ix_mp_role_mp_user_id on mp_role (mp_user_id); +alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; + +create index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b (ms_many_a_aid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; + +create index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b (ms_many_b_bid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; + +create index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a (ms_many_b_bid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; + +create index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a (ms_many_a_aid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; -alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_parent_id foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; create index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many (parent_id); +alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_parent_id foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; +create index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country (o_cached_bean_id); alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_cached_bean foreign key (o_cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_cached_bean_id on o_cached_bean_country (o_cached_bean_id); +create index ix_o_cached_bean_country_o_country on o_cached_bean_country (o_country_code); alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_country foreign key (o_country_code) references o_country (code) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_country_code on o_cached_bean_country (o_country_code); -alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_bean_id foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; create index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child (cached_bean_id); +alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_bean_id foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; alter table oengine add constraint fk_oengine_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; alter table ogear_box add constraint fk_ogear_box_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; -alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; +alter table oroad_show_msg add constraint fk_oroad_show_msg_company_id foreign key (company_id) references ocompany (id) on delete restrict on update restrict; + +create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id); +alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id) on delete restrict on update restrict; + create index ix_o_order_kcustomer_id on o_order (kcustomer_id); +alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_o_order_detail_order_id on o_order_detail (order_id); +alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; create index ix_o_order_detail_product_id on o_order_detail (product_id); +alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; -alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; create index ix_s_order_items_order_uuid on s_order_items (order_uuid); +alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; -alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_or_order_ship_order_id on or_order_ship (order_id); +alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; + +alter table oto_bchild add constraint fk_oto_bchild_master_id foreign key (master_id) references oto_bmaster (id) on delete restrict on update restrict; alter table oto_child add constraint fk_oto_child_master_id foreign key (master_id) references oto_master (id) on delete restrict on update restrict; +alter table oto_cust_address add constraint fk_oto_cust_address_customer_cid foreign key (customer_cid) references oto_cust (cid) on delete restrict on update restrict; + +alter table oto_prime_extra add constraint fk_oto_prime_extra_eid foreign key (eid) references oto_prime (pid) on delete restrict on update restrict; + +create index ix_oto_th_many_oto_th_top_id on oto_th_many (oto_th_top_id); +alter table oto_th_many add constraint fk_oto_th_many_oto_th_top_id foreign key (oto_th_top_id) references oto_th_top (id) on delete restrict on update restrict; + +alter table oto_th_one add constraint fk_oto_th_one_many_id foreign key (many_id) references oto_th_many (id) on delete restrict on update restrict; + +alter table oto_ubprime_extra add constraint fk_oto_ubprime_extra_eid foreign key (eid) references oto_ubprime (pid) on delete restrict on update restrict; + +alter table oto_uprime_extra add constraint fk_oto_uprime_extra_eid foreign key (eid) references oto_uprime (pid) on delete restrict on update restrict; + alter table pfile add constraint fk_pfile_file_content_id foreign key (file_content_id) references pfile_content (id) on delete restrict on update restrict; alter table pfile add constraint fk_pfile_file_content2_id foreign key (file_content2_id) references pfile_content (id) on delete restrict on update restrict; alter table paggview add constraint fk_paggview_pview_id foreign key (pview_id) references pp (id) on delete restrict on update restrict; -alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; create index ix_pallet_location_zone_sid on pallet_location (zone_sid); +alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; alter table parcel_location add constraint fk_parcel_location_parcelid foreign key (parcelid) references parcel (parcelid) on delete restrict on update restrict; +create index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data (rawinherit_parent_id); alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_parent foreign key (rawinherit_parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinherit_data_rawinherit_parent_id on rawinherit_parent_rawinherit_data (rawinherit_parent_id); +create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id); alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinherit_data_rawinherit_data_id on rawinherit_parent_rawinherit_data (rawinherit_data_id); -alter table c_participation add constraint fk_c_participation_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; +create index ix_parent_person_some_bean_id on parent_person (some_bean_id); +alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_parent_person_parent_identifier on parent_person (parent_identifier); +alter table parent_person add constraint fk_parent_person_parent_identifier foreign key (parent_identifier) references grand_parent_person (identifier) on delete restrict on update restrict; + create index ix_c_participation_conversation_id on c_participation (conversation_id); +alter table c_participation add constraint fk_c_participation_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_participation_user_id on c_participation (user_id); +alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; alter table persistent_file_content add constraint fk_persistent_file_content_persistent_file_id foreign key (persistent_file_id) references persistent_file (id) on delete restrict on update restrict; -alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; create index ix_person_default_address_oid on person (default_address_oid); +alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; -alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; +create index ix_pp_to_ww_pp on pp_to_ww (pp_id); alter table pp_to_ww add constraint fk_pp_to_ww_pp foreign key (pp_id) references pp (id) on delete restrict on update restrict; -create index ix_pp_to_ww_pp_id on pp_to_ww (pp_id); +create index ix_pp_to_ww_wview on pp_to_ww (ww_id); alter table pp_to_ww add constraint fk_pp_to_ww_wview foreign key (ww_id) references wview (id) on delete restrict on update restrict; -create index ix_pp_to_ww_ww_id on pp_to_ww (ww_id); -alter table r_orders add constraint fk_r_orders_rcustomer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; -create index ix_r_orders_company_customername on r_orders (company,customername); +create index ix_question_groupobjectid on question (groupobjectid); +alter table question add constraint fk_question_groupobjectid foreign key (groupobjectid) references survey_group (id) on delete restrict on update restrict; + +create index ix_r_orders_customer on r_orders (company,customername); +alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; -alter table resourcefile add constraint fk_resourcefile_parentresourcefileid foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; create index ix_resourcefile_parentresourcefileid on resourcefile (parentresourcefileid); +alter table resourcefile add constraint fk_resourcefile_parentresourcefileid foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; -alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; create index ix_mt_role_tenant_id on mt_role (tenant_id); +alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; +create index ix_mt_role_permission_mt_role on mt_role_permission (mt_role_id); alter table mt_role_permission add constraint fk_mt_role_permission_mt_role foreign key (mt_role_id) references mt_role (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_role_id on mt_role_permission (mt_role_id); +create index ix_mt_role_permission_mt_permission on mt_role_permission (mt_permission_id); alter table mt_role_permission add constraint fk_mt_role_permission_mt_permission foreign key (mt_permission_id) references mt_permission (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_permission_id on mt_role_permission (mt_permission_id); alter table f_second add constraint fk_f_second_first foreign key (first) references f_first (id) on delete restrict on update restrict; -alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; create index ix_section_article_id on section (article_id); +alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; -alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; create index ix_self_parent_parent_id on self_parent (parent_id); +alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; -alter table self_ref_customer add constraint fk_self_ref_customer_referred_by_id foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; create index ix_self_ref_customer_referred_by_id on self_ref_customer (referred_by_id); +alter table self_ref_customer add constraint fk_self_ref_customer_referred_by_id foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; -alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; create index ix_self_ref_example_parent_id on self_ref_example (parent_id); +alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; -alter table stockforecast add constraint fk_stockforecast_inner_report_id foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; create index ix_stockforecast_inner_report_id on stockforecast (inner_report_id); +alter table stockforecast add constraint fk_stockforecast_inner_report_id foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; -alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; create index ix_sub_section_section_id on sub_section (section_id); +alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; + +create index ix_tevent_many_event_id on tevent_many (event_id); +alter table tevent_many add constraint fk_tevent_many_event_id foreign key (event_id) references tevent_one (id) on delete restrict on update restrict; + +alter table tevent_one add constraint fk_tevent_one_event_id foreign key (event_id) references tevent (id) on delete restrict on update restrict; -alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexxxyy_master_id foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; create index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy (master_id); +alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexxxyy_master_id foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; -alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; create index ix_ts_detail_two_master_id on ts_detail_two (master_id); +alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; -alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; create index ix_twheel_owner_plate_no on twheel (owner_plate_no); +alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; alter table tire add constraint fk_tire_wheel foreign key (wheel) references wheel (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; create index ix_trip_vehicle_driver_id on trip (vehicle_driver_id); +alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_trip_address_id on trip (address_id); +alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; create index ix_type_sub_type_id on type (sub_type_id); +alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; -alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; create index ix_ut_detail_utmaster_id on ut_detail (utmaster_id); +alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; -alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; create index ix_uutwo_master_id on uutwo (master_id); +alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; -alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_user_group_id on c_user (group_id); +alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; alter table oto_user add constraint fk_oto_user_account_id foreign key (account_id) references oto_account (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; create index ix_em_user_role_user_id on em_user_role (user_id); +alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; create index ix_em_user_role_role_id on em_user_role (role_id); +alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; -alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); - -alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; create index ix_vehicle_car_ref_id on vehicle (car_ref_id); +alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; + +create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); +alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; create index ix_vehicle_driver_vehicle_id on vehicle_driver (vehicle_id); +alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_vehicle_driver_address_id on vehicle_driver (address_id); +alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; create index ix_warehouses_officezoneid on warehouses (officezoneid); +alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; +create index ix_warehousesshippingzones_warehouses on warehousesshippingzones (warehouseid); alter table warehousesshippingzones add constraint fk_warehousesshippingzones_warehouses foreign key (warehouseid) references warehouses (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_warehouseid on warehousesshippingzones (warehouseid); +create index ix_warehousesshippingzones_zones on warehousesshippingzones (shippingzoneid); alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zones foreign key (shippingzoneid) references zones (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_shippingzoneid on warehousesshippingzones (shippingzoneid); -alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; create index ix_sa_wheel_tire on sa_wheel (tire); +alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; -alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; create index ix_sa_wheel_car on sa_wheel (car); +alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_created_id on g_who_props_otm (who_created_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_created_id foreign key (who_created_id) references g_user (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_modified_id on g_who_props_otm (who_modified_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_modified_id foreign key (who_modified_id) references g_user (id) on delete restrict on update restrict; -alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; create index ix_with_zero_parent_id on with_zero (parent_id); +alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; +alter table hx_link add column sys_period_start datetime(6) default now(6); +alter table hx_link add column sys_period_end datetime(6); +update hx_link set sys_period_start = when_created; +create table hx_link_history( + id bigint, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hx_link_with_history as select * from hx_link union all select * from hx_link_history; + +delimiter $$ +create trigger hx_link_history_upd before update on hx_link for each row begin + insert into hx_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hx_link_history_del before delete on hx_link for each row begin + insert into hx_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); +end$$ +alter table hi_link add column sys_period_start datetime(6) default now(6); +alter table hi_link add column sys_period_end datetime(6); +update hi_link set sys_period_start = when_created; +create table hi_link_history( + id bigint, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hi_link_with_history as select * from hi_link union all select * from hi_link_history; + +delimiter $$ +create trigger hi_link_history_upd before update on hi_link for each row begin + insert into hi_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hi_link_history_del before delete on hi_link for each row begin + insert into hi_link_history (sys_period_start,sys_period_end,id, name, location, comments, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); +end$$ +alter table hi_link_doc add column sys_period_start datetime(6) default now(6); +alter table hi_link_doc add column sys_period_end datetime(6); +create table hi_link_doc_history( + hi_link_id bigint, + hi_doc_id bigint, + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view hi_link_doc_with_history as select * from hi_link_doc union all select * from hi_link_doc_history; + +delimiter $$ +create trigger hi_link_doc_history_upd before update on hi_link_doc for each row begin + insert into hi_link_doc_history (sys_period_start,sys_period_end,hi_link_id, hi_doc_id) values (OLD.sys_period_start, now(6),OLD.hi_link_id, OLD.hi_doc_id); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger hi_link_doc_history_del before delete on hi_link_doc for each row begin + insert into hi_link_doc_history (sys_period_start,sys_period_end,hi_link_id, hi_doc_id) values (OLD.sys_period_start, now(6),OLD.hi_link_id, OLD.hi_doc_id); +end$$ +alter table link add column sys_period_start datetime(6) default now(6); +alter table link add column sys_period_end datetime(6); +update link set sys_period_start = when_created; +create table link_history( + id bigint, + name varchar(255), + location varchar(255), + when_publish datetime(6), + link_comment varchar(255), + version bigint, + when_created datetime(6), + when_modified datetime(6), + deleted tinyint(1), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view link_with_history as select * from link union all select * from link_history; + +delimiter $$ +create trigger link_history_upd before update on link for each row begin + insert into link_history (sys_period_start,sys_period_end,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger link_history_del before delete on link for each row begin + insert into link_history (sys_period_start,sys_period_end,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (OLD.sys_period_start, now(6),OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); +end$$ +alter table c_user add column sys_period_start datetime(6) default now(6); +alter table c_user add column sys_period_end datetime(6); +update c_user set sys_period_start = when_created; +create table c_user_history( + id bigint, + inactive tinyint(1), + name varchar(255), + email varchar(255), + password_hash varchar(255), + group_id bigint, + version bigint, + when_created datetime(6), + when_modified datetime(6), + sys_period_start datetime(6), + sys_period_end datetime(6) +); +create view c_user_with_history as select * from c_user union all select * from c_user_history; + +delimiter $$ +create trigger c_user_history_upd before update on c_user for each row begin + insert into c_user_history (sys_period_start,sys_period_end,id, inactive, name, email, group_id, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); + set NEW.sys_period_start = now(6); +end$$ +delimiter $$ +create trigger c_user_history_del before delete on c_user for each row begin + insert into c_user_history (sys_period_start,sys_period_end,id, inactive, name, email, group_id, version, when_created, when_modified) values (OLD.sys_period_start, now(6),OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); +end$$ diff --git a/src/test/ddl-review/mysql-drop-all.sql b/src/test/ddl-review/mysql-drop-all.sql index 592b8a5e6..5be3cc07a 100644 --- a/src/test/ddl-review/mysql-drop-all.sql +++ b/src/test/ddl-review/mysql-drop-all.sql @@ -1,11 +1,17 @@ +-- Generated by ebean unknown at 2018-03-08T06:38:18.344Z alter table bar drop foreign key fk_bar_foo_id; drop index ix_bar_foo_id on bar; +alter table addr drop foreign key fk_addr_employee_id; +drop index ix_addr_employee_id on addr; + alter table o_address drop foreign key fk_o_address_country_code; drop index ix_o_address_country_code on o_address; -alter table animals drop foreign key fk_animals_shelter_id; -drop index ix_animals_shelter_id on animals; +alter table album drop foreign key fk_album_cover_id; + +alter table animal drop foreign key fk_animal_shelter_id; +drop index ix_animal_shelter_id on animal; alter table attribute drop foreign key fk_attribute_attribute_holder_id; drop index ix_attribute_attribute_holder_id on attribute; @@ -13,12 +19,30 @@ drop index ix_attribute_attribute_holder_id on attribute; alter table bbookmark drop foreign key fk_bbookmark_user_id; drop index ix_bbookmark_user_id on bbookmark; +alter table bsite_user drop foreign key fk_bsite_user_site_id; +drop index ix_bsite_user_site_id on bsite_user; + +alter table bsite_user drop foreign key fk_bsite_user_user_id; +drop index ix_bsite_user_user_id on bsite_user; + +alter table bsite_user_b drop foreign key fk_bsite_user_b_site; +drop index ix_bsite_user_b_site on bsite_user_b; + +alter table bsite_user_b drop foreign key fk_bsite_user_b_usr; +drop index ix_bsite_user_b_usr on bsite_user_b; + +alter table bsite_user_c drop foreign key fk_bsite_user_c_site_uid; +drop index ix_bsite_user_c_site_uid on bsite_user_c; + +alter table bsite_user_c drop foreign key fk_bsite_user_c_user_uid; +drop index ix_bsite_user_c_user_uid on bsite_user_c; + alter table drel_booking drop foreign key fk_drel_booking_agent_invoice; alter table drel_booking drop foreign key fk_drel_booking_client_invoice; -alter table ckey_detail drop foreign key fk_ckey_detail_ckey_parent; -drop index ix_ckey_detail_one_key_two_key on ckey_detail; +alter table ckey_detail drop foreign key fk_ckey_detail_parent; +drop index ix_ckey_detail_parent on ckey_detail; alter table ckey_parent drop foreign key fk_ckey_parent_assoc_id; drop index ix_ckey_parent_assoc_id on ckey_parent; @@ -30,14 +54,26 @@ alter table calculation_result drop foreign key fk_calculation_result_group_conf drop index ix_calculation_result_group_configuration_id on calculation_result; alter table sp_car_car_wheels drop foreign key fk_sp_car_car_wheels_sp_car_car; -drop index ix_sp_car_car_wheels_car on sp_car_car_wheels; +drop index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels; alter table sp_car_car_wheels drop foreign key fk_sp_car_car_wheels_sp_car_wheel; -drop index ix_sp_car_car_wheels_wheel on sp_car_car_wheels; +drop index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels; + +alter table car_accessory drop foreign key fk_car_accessory_fuse_id; +drop index ix_car_accessory_fuse_id on car_accessory; alter table car_accessory drop foreign key fk_car_accessory_car_id; drop index ix_car_accessory_car_id on car_accessory; +alter table category drop foreign key fk_category_surveyobjectid; +drop index ix_category_surveyobjectid on category; + +alter table child_person drop foreign key fk_child_person_some_bean_id; +drop index ix_child_person_some_bean_id on child_person; + +alter table child_person drop foreign key fk_child_person_parent_identifier; +drop index ix_child_person_parent_identifier on child_person; + alter table configuration drop foreign key fk_configuration_configurations_id; drop index ix_configuration_configurations_id on configuration; @@ -59,6 +95,55 @@ drop index ix_o_customer_billing_address_id on o_customer; alter table o_customer drop foreign key fk_o_customer_shipping_address_id; drop index ix_o_customer_shipping_address_id on o_customer; +alter table dcredit_drol drop foreign key fk_dcredit_drol_dcredit; +drop index ix_dcredit_drol_dcredit on dcredit_drol; + +alter table dcredit_drol drop foreign key fk_dcredit_drol_drol; +drop index ix_dcredit_drol_drol on dcredit_drol; + +alter table drot_drol drop foreign key fk_drot_drol_drot; +drop index ix_drot_drol_drot on drot_drol; + +alter table drot_drol drop foreign key fk_drot_drol_drol; +drop index ix_drot_drol_drol on drot_drol; + +alter table dfk_cascade drop foreign key fk_dfk_cascade_one_id; +drop index ix_dfk_cascade_one_id on dfk_cascade; + +alter table dfk_set_null drop foreign key fk_dfk_set_null_one_id; +drop index ix_dfk_set_null_one_id on dfk_set_null; + +alter table doc drop foreign key fk_doc_id; + +alter table doc_link drop foreign key fk_doc_link_doc; +drop index ix_doc_link_doc on doc_link; + +alter table doc_link drop foreign key fk_doc_link_link; +drop index ix_doc_link_link on doc_link; + +alter table document drop foreign key fk_document_id; + +alter table document drop foreign key fk_document_organisation_id; +drop index ix_document_organisation_id on document; + +alter table document_draft drop foreign key fk_document_draft_organisation_id; +drop index ix_document_draft_organisation_id on document_draft; + +alter table document_media drop foreign key fk_document_media_document_id; +drop index ix_document_media_document_id on document_media; + +alter table document_media_draft drop foreign key fk_document_media_draft_document_id; +drop index ix_document_media_draft_document_id on document_media_draft; + +alter table ebasic_json_map_detail drop foreign key fk_ebasic_json_map_detail_owner_id; +drop index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail; + +alter table ebasic_no_sdchild drop foreign key fk_ebasic_no_sdchild_owner_id; +drop index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild; + +alter table ebasic_sdchild drop foreign key fk_ebasic_sdchild_owner_id; +drop index ix_ebasic_sdchild_owner_id on ebasic_sdchild; + alter table eemb_inner drop foreign key fk_eemb_inner_outer_id; drop index ix_eemb_inner_outer_id on eemb_inner; @@ -74,12 +159,68 @@ drop index ix_eopt_one_a_b_id on eopt_one_a; alter table eopt_one_b drop foreign key fk_eopt_one_b_c_id; drop index ix_eopt_one_b_c_id on eopt_one_b; +alter table esoft_del_book drop foreign key fk_esoft_del_book_lend_by_id; +drop index ix_esoft_del_book_lend_by_id on esoft_del_book; + +alter table esoft_del_book_esoft_del_user drop foreign key fk_esoft_del_book_esoft_del_user_esoft_del_book; +drop index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user; + +alter table esoft_del_book_esoft_del_user drop foreign key fk_esoft_del_book_esoft_del_user_esoft_del_user; +drop index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user; + +alter table esoft_del_down drop foreign key fk_esoft_del_down_esoft_del_mid_id; +drop index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down; + +alter table esoft_del_mid drop foreign key fk_esoft_del_mid_top_id; +drop index ix_esoft_del_mid_top_id on esoft_del_mid; + +alter table esoft_del_mid drop foreign key fk_esoft_del_mid_up_id; +drop index ix_esoft_del_mid_up_id on esoft_del_mid; + +alter table esoft_del_one_a drop foreign key fk_esoft_del_one_a_oneb_id; + +alter table esoft_del_role_esoft_del_user drop foreign key fk_esoft_del_role_esoft_del_user_esoft_del_role; +drop index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user; + +alter table esoft_del_role_esoft_del_user drop foreign key fk_esoft_del_role_esoft_del_user_esoft_del_user; +drop index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user; + +alter table esoft_del_user_esoft_del_role drop foreign key fk_esoft_del_user_esoft_del_role_esoft_del_user; +drop index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role; + +alter table esoft_del_user_esoft_del_role drop foreign key fk_esoft_del_user_esoft_del_role_esoft_del_role; +drop index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role; + +alter table rawinherit_uncle drop foreign key fk_rawinherit_uncle_parent_id; +drop index ix_rawinherit_uncle_parent_id on rawinherit_uncle; + alter table evanilla_collection_detail drop foreign key fk_evanilla_collection_detail_evanilla_collection_id; drop index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail; alter table td_child drop foreign key fk_td_child_parent_id; drop index ix_td_child_parent_id on td_child; +alter table empl drop foreign key fk_empl_default_address_id; +drop index ix_empl_default_address_id on empl; + +alter table grand_parent_person drop foreign key fk_grand_parent_person_some_bean_id; +drop index ix_grand_parent_person_some_bean_id on grand_parent_person; + +alter table survey_group drop foreign key fk_survey_group_categoryobjectid; +drop index ix_survey_group_categoryobjectid on survey_group; + +alter table hx_link_doc drop foreign key fk_hx_link_doc_hx_link; +drop index ix_hx_link_doc_hx_link on hx_link_doc; + +alter table hx_link_doc drop foreign key fk_hx_link_doc_he_doc; +drop index ix_hx_link_doc_he_doc on hx_link_doc; + +alter table hi_link_doc drop foreign key fk_hi_link_doc_hi_link; +drop index ix_hi_link_doc_hi_link on hi_link_doc; + +alter table hi_link_doc drop foreign key fk_hi_link_doc_hi_doc; +drop index ix_hi_link_doc_hi_doc on hi_link_doc; + alter table imrelated drop foreign key fk_imrelated_owner_id; drop index ix_imrelated_owner_id on imrelated; @@ -93,35 +234,48 @@ alter table inner_report drop foreign key fk_inner_report_forecast_id; alter table drel_invoice drop foreign key fk_drel_invoice_booking; drop index ix_drel_invoice_booking on drel_invoice; -alter table item drop foreign key fk_item_type; -drop index ix_item_customer_type on item; +alter table item drop foreign key fk_item_etype; +drop index ix_item_etype on item; -alter table item drop foreign key fk_item_region; -drop index ix_item_customer_region on item; +alter table item drop foreign key fk_item_eregion; +drop index ix_item_eregion on item; + +alter table trainer_monkey drop foreign key fk_trainer_monkey_trainer; + +alter table trainer_monkey drop foreign key fk_trainer_monkey_monkey; + +alter table troop_monkey drop foreign key fk_troop_monkey_troop; + +alter table troop_monkey drop foreign key fk_troop_monkey_monkey; + +alter table l2_cldf_reset_bean_child drop foreign key fk_l2_cldf_reset_bean_child_parent_id; +drop index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child; alter table level1_level4 drop foreign key fk_level1_level4_level1; -drop index ix_level1_level4_level1_id on level1_level4; +drop index ix_level1_level4_level1 on level1_level4; alter table level1_level4 drop foreign key fk_level1_level4_level4; -drop index ix_level1_level4_level4_id on level1_level4; +drop index ix_level1_level4_level4 on level1_level4; alter table level1_level2 drop foreign key fk_level1_level2_level1; -drop index ix_level1_level2_level1_id on level1_level2; +drop index ix_level1_level2_level1 on level1_level2; alter table level1_level2 drop foreign key fk_level1_level2_level2; -drop index ix_level1_level2_level2_id on level1_level2; +drop index ix_level1_level2_level2 on level1_level2; alter table level2_level3 drop foreign key fk_level2_level3_level2; -drop index ix_level2_level3_level2_id on level2_level3; +drop index ix_level2_level3_level2 on level2_level3; alter table level2_level3 drop foreign key fk_level2_level3_level3; -drop index ix_level2_level3_level3_id on level2_level3; +drop index ix_level2_level3_level3 on level2_level3; + +alter table link drop foreign key fk_link_id; alter table la_attr_value_attribute drop foreign key fk_la_attr_value_attribute_la_attr_value; -drop index ix_la_attr_value_attribute_la_attr_value_id on la_attr_value_attribute; +drop index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute; alter table la_attr_value_attribute drop foreign key fk_la_attr_value_attribute_attribute; -drop index ix_la_attr_value_attribute_attribute_id on la_attr_value_attribute; +drop index ix_la_attr_value_attribute_attribute on la_attr_value_attribute; alter table mprinter drop foreign key fk_mprinter_current_state_id; drop index ix_mprinter_current_state_id on mprinter; @@ -141,14 +295,26 @@ alter table mprofile drop foreign key fk_mprofile_picture_id; drop index ix_mprofile_picture_id on mprofile; alter table mrole_muser drop foreign key fk_mrole_muser_mrole; -drop index ix_mrole_muser_mrole_roleid on mrole_muser; +drop index ix_mrole_muser_mrole on mrole_muser; alter table mrole_muser drop foreign key fk_mrole_muser_muser; -drop index ix_mrole_muser_muser_userid on mrole_muser; +drop index ix_mrole_muser_muser on mrole_muser; alter table muser drop foreign key fk_muser_user_type_id; drop index ix_muser_user_type_id on muser; +alter table mail_user_inbox drop foreign key fk_mail_user_inbox_mail_user; +drop index ix_mail_user_inbox_mail_user on mail_user_inbox; + +alter table mail_user_inbox drop foreign key fk_mail_user_inbox_mail_box; +drop index ix_mail_user_inbox_mail_box on mail_user_inbox; + +alter table mail_user_outbox drop foreign key fk_mail_user_outbox_mail_user; +drop index ix_mail_user_outbox_mail_user on mail_user_outbox; + +alter table mail_user_outbox drop foreign key fk_mail_user_outbox_mail_box; +drop index ix_mail_user_outbox_mail_box on mail_user_outbox; + alter table c_message drop foreign key fk_c_message_conversation_id; drop index ix_c_message_conversation_id on c_message; @@ -156,22 +322,49 @@ alter table c_message drop foreign key fk_c_message_user_id; drop index ix_c_message_user_id on c_message; alter table mnoc_user_mnoc_role drop foreign key fk_mnoc_user_mnoc_role_mnoc_user; -drop index ix_mnoc_user_mnoc_role_mnoc_user_user_id on mnoc_user_mnoc_role; +drop index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role; alter table mnoc_user_mnoc_role drop foreign key fk_mnoc_user_mnoc_role_mnoc_role; -drop index ix_mnoc_user_mnoc_role_mnoc_role_role_id on mnoc_user_mnoc_role; +drop index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role; + +alter table mny_b drop foreign key fk_mny_b_a_id; +drop index ix_mny_b_a_id on mny_b; + +alter table mny_b_mny_c drop foreign key fk_mny_b_mny_c_mny_b; +drop index ix_mny_b_mny_c_mny_b on mny_b_mny_c; + +alter table mny_b_mny_c drop foreign key fk_mny_b_mny_c_mny_c; +drop index ix_mny_b_mny_c_mny_c on mny_b_mny_c; + +alter table subtopics drop foreign key fk_subtopics_mny_topic_1; +drop index ix_subtopics_mny_topic_1 on subtopics; + +alter table subtopics drop foreign key fk_subtopics_mny_topic_2; +drop index ix_subtopics_mny_topic_2 on subtopics; alter table mp_role drop foreign key fk_mp_role_mp_user_id; drop index ix_mp_role_mp_user_id on mp_role; +alter table ms_many_a_many_b drop foreign key fk_ms_many_a_many_b_ms_many_a; +drop index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b; + +alter table ms_many_a_many_b drop foreign key fk_ms_many_a_many_b_ms_many_b; +drop index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b; + +alter table ms_many_b_many_a drop foreign key fk_ms_many_b_many_a_ms_many_b; +drop index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a; + +alter table ms_many_b_many_a drop foreign key fk_ms_many_b_many_a_ms_many_a; +drop index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a; + alter table my_lob_size_join_many drop foreign key fk_my_lob_size_join_many_parent_id; drop index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many; alter table o_cached_bean_country drop foreign key fk_o_cached_bean_country_o_cached_bean; -drop index ix_o_cached_bean_country_o_cached_bean_id on o_cached_bean_country; +drop index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country; alter table o_cached_bean_country drop foreign key fk_o_cached_bean_country_o_country; -drop index ix_o_cached_bean_country_o_country_code on o_cached_bean_country; +drop index ix_o_cached_bean_country_o_country on o_cached_bean_country; alter table o_cached_bean_child drop foreign key fk_o_cached_bean_child_cached_bean_id; drop index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child; @@ -180,6 +373,11 @@ alter table oengine drop foreign key fk_oengine_car_id; alter table ogear_box drop foreign key fk_ogear_box_car_id; +alter table oroad_show_msg drop foreign key fk_oroad_show_msg_company_id; + +alter table om_ordered_detail drop foreign key fk_om_ordered_detail_master_id; +drop index ix_om_ordered_detail_master_id on om_ordered_detail; + alter table o_order drop foreign key fk_o_order_kcustomer_id; drop index ix_o_order_kcustomer_id on o_order; @@ -195,8 +393,23 @@ drop index ix_s_order_items_order_uuid on s_order_items; alter table or_order_ship drop foreign key fk_or_order_ship_order_id; drop index ix_or_order_ship_order_id on or_order_ship; +alter table oto_bchild drop foreign key fk_oto_bchild_master_id; + alter table oto_child drop foreign key fk_oto_child_master_id; +alter table oto_cust_address drop foreign key fk_oto_cust_address_customer_cid; + +alter table oto_prime_extra drop foreign key fk_oto_prime_extra_eid; + +alter table oto_th_many drop foreign key fk_oto_th_many_oto_th_top_id; +drop index ix_oto_th_many_oto_th_top_id on oto_th_many; + +alter table oto_th_one drop foreign key fk_oto_th_one_many_id; + +alter table oto_ubprime_extra drop foreign key fk_oto_ubprime_extra_eid; + +alter table oto_uprime_extra drop foreign key fk_oto_uprime_extra_eid; + alter table pfile drop foreign key fk_pfile_file_content_id; alter table pfile drop foreign key fk_pfile_file_content2_id; @@ -209,10 +422,16 @@ drop index ix_pallet_location_zone_sid on pallet_location; alter table parcel_location drop foreign key fk_parcel_location_parcelid; alter table rawinherit_parent_rawinherit_data drop foreign key fk_rawinherit_parent_rawinherit_data_rawinherit_parent; -drop index ix_rawinherit_parent_rawinherit_data_rawinherit_parent_id on rawinherit_parent_rawinherit_data; +drop index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data; alter table rawinherit_parent_rawinherit_data drop foreign key fk_rawinherit_parent_rawinherit_data_rawinherit_data; -drop index ix_rawinherit_parent_rawinherit_data_rawinherit_data_id on rawinherit_parent_rawinherit_data; +drop index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data; + +alter table parent_person drop foreign key fk_parent_person_some_bean_id; +drop index ix_parent_person_some_bean_id on parent_person; + +alter table parent_person drop foreign key fk_parent_person_parent_identifier; +drop index ix_parent_person_parent_identifier on parent_person; alter table c_participation drop foreign key fk_c_participation_conversation_id; drop index ix_c_participation_conversation_id on c_participation; @@ -229,13 +448,16 @@ alter table phones drop foreign key fk_phones_person_id; drop index ix_phones_person_id on phones; alter table pp_to_ww drop foreign key fk_pp_to_ww_pp; -drop index ix_pp_to_ww_pp_id on pp_to_ww; +drop index ix_pp_to_ww_pp on pp_to_ww; alter table pp_to_ww drop foreign key fk_pp_to_ww_wview; -drop index ix_pp_to_ww_ww_id on pp_to_ww; +drop index ix_pp_to_ww_wview on pp_to_ww; -alter table r_orders drop foreign key fk_r_orders_rcustomer; -drop index ix_r_orders_company_customername on r_orders; +alter table question drop foreign key fk_question_groupobjectid; +drop index ix_question_groupobjectid on question; + +alter table r_orders drop foreign key fk_r_orders_customer; +drop index ix_r_orders_customer on r_orders; alter table resourcefile drop foreign key fk_resourcefile_parentresourcefileid; drop index ix_resourcefile_parentresourcefileid on resourcefile; @@ -244,10 +466,10 @@ alter table mt_role drop foreign key fk_mt_role_tenant_id; drop index ix_mt_role_tenant_id on mt_role; alter table mt_role_permission drop foreign key fk_mt_role_permission_mt_role; -drop index ix_mt_role_permission_mt_role_id on mt_role_permission; +drop index ix_mt_role_permission_mt_role on mt_role_permission; alter table mt_role_permission drop foreign key fk_mt_role_permission_mt_permission; -drop index ix_mt_role_permission_mt_permission_id on mt_role_permission; +drop index ix_mt_role_permission_mt_permission on mt_role_permission; alter table f_second drop foreign key fk_f_second_first; @@ -269,6 +491,11 @@ drop index ix_stockforecast_inner_report_id on stockforecast; alter table sub_section drop foreign key fk_sub_section_section_id; drop index ix_sub_section_section_id on sub_section; +alter table tevent_many drop foreign key fk_tevent_many_event_id; +drop index ix_tevent_many_event_id on tevent_many; + +alter table tevent_one drop foreign key fk_tevent_one_event_id; + alter table t_detail_with_other_namexxxyy drop foreign key fk_t_detail_with_other_namexxxyy_master_id; drop index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy; @@ -306,12 +533,12 @@ drop index ix_em_user_role_user_id on em_user_role; alter table em_user_role drop foreign key fk_em_user_role_role_id; drop index ix_em_user_role_role_id on em_user_role; -alter table vehicle drop foreign key fk_vehicle_truck_ref_id; -drop index ix_vehicle_truck_ref_id on vehicle; - alter table vehicle drop foreign key fk_vehicle_car_ref_id; drop index ix_vehicle_car_ref_id on vehicle; +alter table vehicle drop foreign key fk_vehicle_truck_ref_id; +drop index ix_vehicle_truck_ref_id on vehicle; + alter table vehicle_driver drop foreign key fk_vehicle_driver_vehicle_id; drop index ix_vehicle_driver_vehicle_id on vehicle_driver; @@ -322,10 +549,10 @@ alter table warehouses drop foreign key fk_warehouses_officezoneid; drop index ix_warehouses_officezoneid on warehouses; alter table warehousesshippingzones drop foreign key fk_warehousesshippingzones_warehouses; -drop index ix_warehousesshippingzones_warehouseid on warehousesshippingzones; +drop index ix_warehousesshippingzones_warehouses on warehousesshippingzones; alter table warehousesshippingzones drop foreign key fk_warehousesshippingzones_zones; -drop index ix_warehousesshippingzones_shippingzoneid on warehousesshippingzones; +drop index ix_warehousesshippingzones_zones on warehousesshippingzones; alter table sa_wheel drop foreign key fk_sa_wheel_tire; drop index ix_sa_wheel_tire on sa_wheel; @@ -333,6 +560,12 @@ drop index ix_sa_wheel_tire on sa_wheel; alter table sa_wheel drop foreign key fk_sa_wheel_car; drop index ix_sa_wheel_car on sa_wheel; +alter table g_who_props_otm drop foreign key fk_g_who_props_otm_who_created_id; +drop index ix_g_who_props_otm_who_created_id on g_who_props_otm; + +alter table g_who_props_otm drop foreign key fk_g_who_props_otm_who_modified_id; +drop index ix_g_who_props_otm_who_modified_id on g_who_props_otm; + alter table with_zero drop foreign key fk_with_zero_parent_id; drop index ix_with_zero_parent_id on with_zero; @@ -342,11 +575,15 @@ drop table if exists bar; drop table if exists oto_account; -drop table if exists o_address; +drop table if exists addr; drop table if exists address; -drop table if exists animals; +drop table if exists o_address; + +drop table if exists album; + +drop table if exists animal; drop table if exists animal_shelter; @@ -364,6 +601,16 @@ drop table if exists bbookmark_user; drop table if exists bsimple_with_gen; +drop table if exists bsite; + +drop table if exists bsite_user; + +drop table if exists bsite_user_b; + +drop table if exists bsite_user_c; + +drop table if exists buser; + drop table if exists bwith_qident; drop table if exists basic_joda_entity; @@ -372,6 +619,8 @@ drop table if exists bean_with_time_zone; drop table if exists drel_booking; +drop table if exists cinh_root; + drop table if exists ckey_assoc; drop table if exists ckey_detail; @@ -390,6 +639,12 @@ drop table if exists sp_car_car_wheels; drop table if exists car_accessory; +drop table if exists car_fuse; + +drop table if exists category; + +drop table if exists child_person; + drop table if exists configuration; drop table if exists configurations; @@ -404,16 +659,62 @@ drop table if exists c_conversation; drop table if exists o_country; +drop table if exists cover; + drop table if exists o_customer; +drop table if exists dcredit; + +drop table if exists dcredit_drol; + drop table if exists dexh_entity; drop table if exists dperson; +drop table if exists drol; + +drop table if exists drot; + +drop table if exists drot_drol; + drop table if exists rawinherit_data; +drop table if exists dfk_cascade; + +drop table if exists dfk_cascade_one; + +drop table if exists dfk_none; + +drop table if exists dfk_none_via_join; + +drop table if exists dfk_one; + +drop table if exists dfk_set_null; + +drop table if exists doc; + +drop table if exists doc_link; + +drop table if exists doc_link_draft; + +drop table if exists doc_draft; + +drop table if exists document; + +drop table if exists document_draft; + +drop table if exists document_media; + +drop table if exists document_media_draft; + +drop table if exists earray_bean; + +drop table if exists earray_set_bean; + drop table if exists e_basic; +drop table if exists ebasic_change_log; + drop table if exists ebasic_clob; drop table if exists ebasic_clob_fetch_eager; @@ -426,12 +727,20 @@ drop table if exists e_basicenc_bin; drop table if exists e_basic_enum_id; +drop table if exists e_basic_eni; + +drop table if exists ebasic_hstore; + +drop table if exists ebasic_json_list; + drop table if exists ebasic_json_map; drop table if exists ebasic_json_map_blob; drop table if exists ebasic_json_map_clob; +drop table if exists ebasic_json_map_detail; + drop table if exists ebasic_json_map_json_b; drop table if exists ebasic_json_map_varchar; @@ -444,14 +753,26 @@ drop table if exists ebasic_json_node_json_b; drop table if exists ebasic_json_node_varchar; +drop table if exists ebasic_json_unmapped; + drop table if exists e_basic_ndc; +drop table if exists ebasic_no_sdchild; + +drop table if exists ebasic_sdchild; + +drop table if exists ebasic_soft_delete; + drop table if exists e_basicver; drop table if exists e_basic_withlife; drop table if exists e_basicverucon; +drop table if exists e_col_ab; + +drop table if exists ecustom_id; + drop table if exists eemb_inner; drop table if exists eemb_outer; @@ -474,12 +795,42 @@ drop table if exists eopt_one_c; drop table if exists eperson; +drop table if exists e_person_online; + drop table if exists esimple; +drop table if exists esoft_del_book; + +drop table if exists esoft_del_book_esoft_del_user; + +drop table if exists esoft_del_down; + +drop table if exists esoft_del_mid; + +drop table if exists esoft_del_one_a; + +drop table if exists esoft_del_one_b; + +drop table if exists esoft_del_role; + +drop table if exists esoft_del_role_esoft_del_user; + +drop table if exists esoft_del_top; + +drop table if exists esoft_del_up; + +drop table if exists esoft_del_user; + +drop table if exists esoft_del_user_esoft_del_role; + +drop table if exists esome_convert_type; + drop table if exists esome_type; drop table if exists etrans_many; +drop table if exists rawinherit_uncle; + drop table if exists evanilla_collection; drop table if exists evanilla_collection_detail; @@ -492,6 +843,8 @@ drop table if exists td_child; drop table if exists td_parent; +drop table if exists empl; + drop table if exists feature_desc; drop table if exists f_first; @@ -504,8 +857,45 @@ drop table if exists gen_key_sequence; drop table if exists gen_key_table; +drop table if exists grand_parent_person; + +drop table if exists survey_group; + drop table if exists c_group; +drop table if exists he_doc; + +drop trigger hx_link_history_upd; +drop trigger hx_link_history_del; +drop view hx_link_with_history; +alter table hx_link drop column sys_period_start; +alter table hx_link drop column sys_period_end; +drop table hx_link_history; + +drop table if exists hx_link; + +drop table if exists hx_link_doc; + +drop table if exists hi_doc; + +drop trigger hi_link_history_upd; +drop trigger hi_link_history_del; +drop view hi_link_with_history; +alter table hi_link drop column sys_period_start; +alter table hi_link drop column sys_period_end; +drop table hi_link_history; + +drop table if exists hi_link; + +drop trigger hi_link_doc_history_upd; +drop trigger hi_link_doc_history_del; +drop view hi_link_doc_with_history; +alter table hi_link_doc drop column sys_period_start; +alter table hi_link_doc drop column sys_period_end; +drop table hi_link_doc_history; + +drop table if exists hi_link_doc; + drop table if exists imrelated; drop table if exists imroot; @@ -524,6 +914,20 @@ drop table if exists drel_invoice; drop table if exists item; +drop table if exists monkey; + +drop table if exists trainer; + +drop table if exists trainer_monkey; + +drop table if exists troop; + +drop table if exists troop_monkey; + +drop table if exists l2_cldf_reset_bean; + +drop table if exists l2_cldf_reset_bean_child; + drop table if exists level1; drop table if exists level1_level4; @@ -538,6 +942,17 @@ drop table if exists level3; drop table if exists level4; +drop trigger link_history_upd; +drop trigger link_history_del; +drop view link_with_history; +alter table link drop column sys_period_start; +alter table link drop column sys_period_end; +drop table link_history; + +drop table if exists link; + +drop table if exists link_draft; + drop table if exists la_attr_value; drop table if exists la_attr_value_attribute; @@ -564,6 +979,14 @@ drop table if exists muser; drop table if exists muser_type; +drop table if exists mail_box; + +drop table if exists mail_user; + +drop table if exists mail_user_inbox; + +drop table if exists mail_user_outbox; + drop table if exists map_super_actual; drop table if exists c_message; @@ -574,10 +997,30 @@ drop table if exists mnoc_user; drop table if exists mnoc_user_mnoc_role; +drop table if exists mny_a; + +drop table if exists mny_b; + +drop table if exists mny_b_mny_c; + +drop table if exists mny_c; + +drop table if exists mny_topic; + +drop table if exists subtopics; + drop table if exists mp_role; drop table if exists mp_user; +drop table if exists ms_many_a; + +drop table if exists ms_many_a_many_b; + +drop table if exists ms_many_b; + +drop table if exists ms_many_b_many_a; + drop table if exists my_lob_size; drop table if exists my_lob_size_join_many; @@ -590,12 +1033,24 @@ drop table if exists o_cached_bean_country; drop table if exists o_cached_bean_child; +drop table if exists o_cached_natkey; + +drop table if exists o_cached_natkey3; + drop table if exists ocar; +drop table if exists ocompany; + drop table if exists oengine; drop table if exists ogear_box; +drop table if exists oroad_show_msg; + +drop table if exists om_ordered_detail; + +drop table if exists om_ordered_master; + drop table if exists o_order; drop table if exists o_order_detail; @@ -606,10 +1061,38 @@ drop table if exists s_order_items; drop table if exists or_order_ship; +drop table if exists organisation; + +drop table if exists oto_bchild; + +drop table if exists oto_bmaster; + drop table if exists oto_child; +drop table if exists oto_cust; + +drop table if exists oto_cust_address; + drop table if exists oto_master; +drop table if exists oto_prime; + +drop table if exists oto_prime_extra; + +drop table if exists oto_th_many; + +drop table if exists oto_th_one; + +drop table if exists oto_th_top; + +drop table if exists oto_ubprime; + +drop table if exists oto_ubprime_extra; + +drop table if exists oto_uprime; + +drop table if exists oto_uprime_extra; + drop table if exists pfile; drop table if exists pfile_content; @@ -626,6 +1109,8 @@ drop table if exists rawinherit_parent; drop table if exists rawinherit_parent_rawinherit_data; +drop table if exists parent_person; + drop table if exists c_participation; drop table if exists mt_permission; @@ -640,12 +1125,16 @@ drop table if exists person; drop table if exists phones; +drop table if exists primary_revision; + drop table if exists o_product; drop table if exists pp; drop table if exists pp_to_ww; +drop table if exists question; + drop table if exists rcustomer; drop table if exists r_orders; @@ -654,12 +1143,12 @@ drop table if exists region; drop table if exists resourcefile; +drop table if exists em_role; + drop table if exists mt_role; drop table if exists mt_role_permission; -drop table if exists em_role; - drop table if exists f_second; drop table if exists section; @@ -684,10 +1173,18 @@ drop table if exists sub_section; drop table if exists sub_type; +drop table if exists survey; + drop table if exists tbytes_only; drop table if exists tcar; +drop table if exists tevent; + +drop table if exists tevent_many; + +drop table if exists tevent_one; + drop table if exists tint_root; drop table if exists tjoda_entity; @@ -712,16 +1209,20 @@ drop table if exists twith_pre_insert; drop table if exists mt_tenant; -drop table if exists sa_tire; +drop table if exists test_annotation_base_entity; drop table if exists tire; +drop table if exists sa_tire; + drop table if exists trip; drop table if exists truck_ref; drop table if exists type; +drop table if exists tz_bean; + drop table if exists ut_detail; drop table if exists ut_master; @@ -730,11 +1231,20 @@ drop table if exists uuone; drop table if exists uutwo; -drop table if exists em_user; +drop trigger c_user_history_upd; +drop trigger c_user_history_del; +drop view c_user_with_history; +alter table c_user drop column sys_period_start; +alter table c_user drop column sys_period_end; +drop table c_user_history; + +drop table if exists c_user; drop table if exists tx_user; -drop table if exists c_user; +drop table if exists g_user; + +drop table if exists em_user; drop table if exists oto_user; @@ -750,9 +1260,11 @@ drop table if exists warehousesshippingzones; drop table if exists sa_wheel; +drop table if exists wheel; + drop table if exists sp_car_wheel; -drop table if exists wheel; +drop table if exists g_who_props_otm; drop table if exists with_zero; @@ -762,3 +1274,5 @@ drop table if exists wview; drop table if exists zones; +drop index ix_contact_last_name_first_name on contact; +drop index ix_e_basic_name on e_basic; diff --git a/src/test/ddl-review/oracle-create-all.sql b/src/test/ddl-review/oracle-create-all.sql index 5dc24914c..b5eee44f8 100644 --- a/src/test/ddl-review/oracle-create-all.sql +++ b/src/test/ddl-review/oracle-create-all.sql @@ -24,6 +24,26 @@ create table oto_account ( ); create sequence oto_account_seq; +create table addr ( + id number(19) not null, + employee_id number(19), + name varchar2(255), + address_line1 varchar2(255), + address_line2 varchar2(255), + city varchar2(255), + version number(19) not null, + constraint pk_addr primary key (id) +); +create sequence addr_seq; + +create table address ( + oid number(19) not null, + street varchar2(255), + version number(10) not null, + constraint pk_address primary key (oid) +); +create sequence address_seq; + create table o_address ( id number(5) not null, line_1 varchar2(100), @@ -36,25 +56,30 @@ create table o_address ( ); create sequence o_address_seq; -create table address ( - oid number(19) not null, - street varchar2(255), - version number(10) not null, - constraint pk_address primary key (oid) +create table album ( + id number(19) not null, + name varchar2(255), + cover_id number(19), + deleted number(1) default 0 not null, + created_at timestamp not null, + last_update timestamp not null, + constraint uq_album_cover_id unique (cover_id), + constraint pk_album primary key (id) ); -create sequence address_seq; +create sequence album_seq; -create table animals ( - species varchar2(31) not null, +create table animal ( + species varchar2(255) not null, id number(19) not null, shelter_id number(19), version number(19) not null, name varchar2(255), registration_number varchar2(255), date_of_birth date, - constraint pk_animals primary key (id) + dog_size varchar2(255), + constraint pk_animal primary key (id) ); -create sequence animals_seq; +create sequence animal_seq; create table animal_shelter ( id number(19) not null, @@ -128,9 +153,45 @@ create table bsimple_with_gen ( ); create sequence bsimple_with_gen_seq; +create table bsite ( + id varchar2(40) not null, + name varchar2(255), + constraint pk_bsite primary key (id) +); + +create table bsite_user ( + site_id varchar2(40) not null, + user_id varchar2(40) not null, + access_level number(10), + constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user primary key (site_id,user_id) +); + +create table bsite_user_b ( + site varchar2(40) not null, + usr varchar2(40) not null, + access_level number(10), + constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_b primary key (site,usr) +); + +create table bsite_user_c ( + site_uid varchar2(40) not null, + user_uid varchar2(40) not null, + access_level number(10), + constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_c primary key (site_uid,user_uid) +); + +create table buser ( + id varchar2(40) not null, + name varchar2(255), + constraint pk_buser primary key (id) +); + create table bwith_qident ( id number(10) not null, - "Name" varchar2(255), + "Name" varchar2(191), last_updated timestamp not null, constraint uq_bwith_qident_name unique ("Name"), constraint pk_bwith_qident primary key (id) @@ -157,15 +218,31 @@ create sequence bean_with_time_zone_seq; create table drel_booking ( id number(19) not null, + booking_uid number(19), agent_invoice number(19), client_invoice number(19), version number(10) not null, + constraint uq_drel_booking_booking_uid unique (booking_uid), constraint uq_drel_booking_agent_invoice unique (agent_invoice), - constraint uq_drel_booking_client_invo_2 unique (client_invoice), + constraint uq_drl_bkng_clnt_nvc unique (client_invoice), constraint pk_drel_booking primary key (id) ); create sequence drel_booking_seq; +create table cinh_root ( + dtype varchar2(3) not null, + id number(10) not null, + license_number varchar2(255), + cretime timestamp not null, + updtime timestamp not null, + version number(19) not null, + driver varchar2(255), + notes varchar2(255), + action varchar2(255), + constraint pk_cinh_root primary key (id) +); +create sequence cinh_root_seq; + create table ckey_assoc ( id number(10) not null, assoc_one varchar2(255), @@ -193,7 +270,7 @@ create table ckey_parent ( create table calculation_result ( id number(10) not null, - charge number(19,4), + charge number(19,4) not null, product_configuration_id number(10), group_configuration_id number(10), constraint pk_calculation_result primary key (id) @@ -231,6 +308,7 @@ create table sp_car_car_wheels ( create table car_accessory ( id number(10) not null, name varchar2(255), + fuse_id number(19) not null, car_id number(10), cretime timestamp not null, updtime timestamp not null, @@ -239,8 +317,36 @@ create table car_accessory ( ); create sequence car_accessory_seq; +create table car_fuse ( + id number(19) not null, + location_code varchar2(255), + constraint pk_car_fuse primary key (id) +); +create sequence car_fuse_seq; + +create table category ( + id number(19) not null, + name varchar2(255), + surveyobjectid number(19), + sequence_number number(10) not null, + constraint pk_category primary key (id) +); +create sequence category_seq; + +create table child_person ( + identifier number(10) not null, + name varchar2(255), + age number(10), + some_bean_id number(10), + parent_identifier number(10), + family_name varchar2(255), + address varchar2(255), + constraint pk_child_person primary key (identifier) +); +create sequence child_person_seq; + create table configuration ( - type varchar2(31) not null, + type varchar2(21) not null, id number(10) not null, name varchar2(255), configurations_id number(10), @@ -259,8 +365,8 @@ create sequence configurations_seq; create table contact ( id number(10) not null, - first_name varchar2(255), - last_name varchar2(255), + first_name varchar2(127), + last_name varchar2(127), phone varchar2(255), mobile varchar2(255), email varchar2(255), @@ -297,7 +403,7 @@ create sequence contact_note_seq; create table c_conversation ( id number(19) not null, title varchar2(255), - isopen number(1), + isopen number(1) default 0 not null, group_id number(19), version number(19) not null, when_created timestamp not null, @@ -312,6 +418,14 @@ create table o_country ( constraint pk_o_country primary key (code) ); +create table cover ( + id number(19) not null, + s3url varchar2(255), + deleted number(1) default 0 not null, + constraint pk_cover primary key (id) +); +create sequence cover_seq; + create table o_customer ( id number(10) not null, status varchar2(1), @@ -323,16 +437,31 @@ create table o_customer ( cretime timestamp not null, updtime timestamp not null, version number(19) not null, - constraint ck_o_customer_status check (status in ('N','A','I')), + constraint ck_o_customer_status check ( status in ('N','A','I')), constraint pk_o_customer primary key (id) ); +comment on table o_customer is 'Holds external customers'; +comment on column o_customer.status is 'status of the customer'; +comment on column o_customer.smallnote is 'Short notes regarding the customer'; +comment on column o_customer.anniversary is 'Join date of the customer'; create sequence o_customer_seq; +create table dcredit ( + id number(19) not null, + credit varchar2(255), + constraint pk_dcredit primary key (id) +); +create sequence dcredit_seq; + +create table dcredit_drol ( + dcredit_id number(19) not null, + drol_id number(19) not null, + constraint pk_dcredit_drol primary key (dcredit_id,drol_id) +); + create table dexh_entity ( oid number(19) not null, - exhange_rate number(38), - exhange_cmoney_amount number(38), - exhange_cmoney_currency varchar2(3), + exhange varchar2(255), last_updated timestamp not null, constraint pk_dexh_entity primary key (oid) ); @@ -343,14 +472,30 @@ create table dperson ( first_name varchar2(255), last_name varchar2(255), salary number(38), - a_amt number(38), - a_curr varchar2(3), - i_start timestamp, - i_end timestamp, constraint pk_dperson primary key (id) ); create sequence dperson_seq; +create table drol ( + id number(19) not null, + name varchar2(255), + constraint pk_drol primary key (id) +); +create sequence drol_seq; + +create table drot ( + id number(19) not null, + name varchar2(255), + constraint pk_drot primary key (id) +); +create sequence drot_seq; + +create table drot_drol ( + drot_id number(19) not null, + drol_id number(19) not null, + constraint pk_drot_drol primary key (drot_id,drol_id) +); + create table rawinherit_data ( id number(19) not null, val number(10), @@ -358,17 +503,186 @@ create table rawinherit_data ( ); create sequence rawinherit_data_seq; +create table dfk_cascade ( + id number(19) not null, + name varchar2(255), + one_id number(19), + constraint pk_dfk_cascade primary key (id) +); +create sequence dfk_cascade_seq; + +create table dfk_cascade_one ( + id number(19) not null, + name varchar2(255), + constraint pk_dfk_cascade_one primary key (id) +); +create sequence dfk_cascade_one_seq; + +create table dfk_none ( + id number(19) not null, + name varchar2(255), + one_id number(19), + constraint pk_dfk_none primary key (id) +); +create sequence dfk_none_seq; + +create table dfk_none_via_join ( + id number(19) not null, + name varchar2(255), + one_id number(19), + constraint pk_dfk_none_via_join primary key (id) +); +create sequence dfk_none_via_join_seq; + +create table dfk_one ( + id number(19) not null, + name varchar2(255), + constraint pk_dfk_one primary key (id) +); +create sequence dfk_one_seq; + +create table dfk_set_null ( + id number(19) not null, + name varchar2(255), + one_id number(19), + constraint pk_dfk_set_null primary key (id) +); +create sequence dfk_set_null_seq; + +create table doc ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_doc primary key (id) +); +create sequence doc_seq; + +create table doc_link ( + doc_id number(19) not null, + link_id number(19) not null, + constraint pk_doc_link primary key (doc_id,link_id) +); + +create table doc_link_draft ( + doc_id number(19) not null, + link_id number(19) not null, + constraint pk_doc_link_draft primary key (doc_id,link_id) +); + +create table doc_draft ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_doc_draft primary key (id) +); +create sequence doc_draft_seq; + +create table document ( + id number(19) not null, + title varchar2(127), + body varchar2(255), + organisation_id number(19), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint uq_document_title unique (title), + constraint pk_document primary key (id) +); +create sequence document_seq; + +create table document_draft ( + id number(19) not null, + title varchar2(127), + body varchar2(255), + when_publish timestamp, + organisation_id number(19), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint uq_document_draft_title unique (title), + constraint pk_document_draft primary key (id) +); +create sequence document_draft_seq; + +create table document_media ( + id number(19) not null, + document_id number(19), + name varchar2(255), + description varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_document_media primary key (id) +); +create sequence document_media_seq; + +create table document_media_draft ( + id number(19) not null, + document_id number(19), + name varchar2(255), + description varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_document_media_draft primary key (id) +); +create sequence document_media_draft_seq; + +create table earray_bean ( + id number(19) not null, + name varchar2(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + statuses varchar(1000), + status2 varchar(1000), + version number(19) not null, + constraint pk_earray_bean primary key (id) +); +create sequence earray_bean_seq; + +create table earray_set_bean ( + id number(19) not null, + name varchar2(255), + phone_numbers varchar(300), + uids varchar(1000), + other_ids varchar(1000), + doubs varchar(1000), + version number(19) not null, + constraint pk_earray_set_bean primary key (id) +); +create sequence earray_set_bean_seq; + create table e_basic ( id number(10) not null, status varchar2(1), - name varchar2(255), + name varchar2(127), description varchar2(255), some_date timestamp, - constraint ck_e_basic_status check (status in ('N','A','I')), + constraint ck_e_basic_status check ( status in ('N','A','I')), constraint pk_e_basic primary key (id) ); create sequence e_basic_seq; +create table ebasic_change_log ( + id number(19) not null, + name varchar2(20), + short_description varchar2(50), + long_description varchar2(100), + who_created varchar2(255) not null, + who_modified varchar2(255) not null, + when_created timestamp not null, + when_modified timestamp not null, + version number(19) not null, + constraint pk_ebasic_change_log primary key (id) +); +create sequence ebasic_change_log_seq; + create table ebasic_clob ( id number(19) not null, name varchar2(255), @@ -402,6 +716,7 @@ create table e_basicenc ( name varchar2(255), description raw(80), dob raw(20), + status raw(20), last_update timestamp, constraint pk_e_basicenc primary key (id) ); @@ -422,10 +737,44 @@ create table e_basic_enum_id ( status varchar2(1) not null, name varchar2(255), description varchar2(255), - constraint ck_e_basic_enum_id_status check (status in ('N','A','I')), + constraint ck_e_basic_enum_id_status check ( status in ('N','A','I')), constraint pk_e_basic_enum_id primary key (status) ); +create table e_basic_eni ( + id number(10) not null, + status number(10), + name varchar2(255), + description varchar2(255), + some_date timestamp, + constraint ck_e_basic_eni_status check ( status in (1,2,3)), + constraint pk_e_basic_eni primary key (id) +); +create sequence e_basic_eni_seq; + +create table ebasic_hstore ( + id number(19) not null, + name varchar2(255), + map varchar2(800), + version number(19) not null, + constraint pk_ebasic_hstore primary key (id) +); +create sequence ebasic_hstore_seq; + +create table ebasic_json_list ( + id number(19) not null, + name varchar2(255), + bean_set varchar2(700), + bean_list clob, + bean_map varchar2(700), + plain_bean varchar2(500), + flags varchar2(50), + tags varchar2(100), + version number(19) not null, + constraint pk_ebasic_json_list primary key (id) +); +create sequence ebasic_json_list_seq; + create table ebasic_json_map ( id number(19) not null, name varchar2(255), @@ -453,6 +802,16 @@ create table ebasic_json_map_clob ( ); create sequence ebasic_json_map_clob_seq; +create table ebasic_json_map_detail ( + id number(19) not null, + owner_id number(19), + name varchar2(255), + content clob, + version number(19) not null, + constraint pk_ebasic_json_map_detail primary key (id) +); +create sequence ebasic_json_map_detail_seq; + create table ebasic_json_map_json_b ( id number(19) not null, name varchar2(255), @@ -507,6 +866,14 @@ create table ebasic_json_node_varchar ( ); create sequence ebasic_json_node_varchar_seq; +create table ebasic_json_unmapped ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_ebasic_json_unmapped primary key (id) +); +create sequence ebasic_json_unmapped_seq; + create table e_basic_ndc ( id number(10) not null, name varchar2(255), @@ -514,6 +881,37 @@ create table e_basic_ndc ( ); create sequence e_basic_ndc_seq; +create table ebasic_no_sdchild ( + id number(19) not null, + owner_id number(19) not null, + child_name varchar2(255), + amount number(19) not null, + version number(19) not null, + constraint pk_ebasic_no_sdchild primary key (id) +); +create sequence ebasic_no_sdchild_seq; + +create table ebasic_sdchild ( + id number(19) not null, + owner_id number(19) not null, + child_name varchar2(255), + amount number(19) not null, + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_ebasic_sdchild primary key (id) +); +create sequence ebasic_sdchild_seq; + +create table ebasic_soft_delete ( + id number(19) not null, + name varchar2(255), + description varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_ebasic_soft_delete primary key (id) +); +create sequence ebasic_soft_delete_seq; + create table e_basicver ( id number(10) not null, name varchar2(255), @@ -527,6 +925,7 @@ create sequence e_basicver_seq; create table e_basic_withlife ( id number(19) not null, name varchar2(255), + deleted number(1) default 0 not null, version number(19) not null, constraint pk_e_basic_withlife primary key (id) ); @@ -534,16 +933,31 @@ create sequence e_basic_withlife_seq; create table e_basicverucon ( id number(10) not null, - name varchar2(255), - other varchar2(255), - other_one varchar2(255), + name varchar2(127), + other varchar2(127), + other_one varchar2(127), description varchar2(255), last_update timestamp not null, constraint uq_e_basicverucon_name unique (name), + constraint uq_e_bscvrcn_thr_thr_n unique (other,other_one), constraint pk_e_basicverucon primary key (id) ); create sequence e_basicverucon_seq; +create table e_col_ab ( + id number(19) not null, + column_a varchar2(255), + column_b varchar2(255), + constraint pk_e_col_ab primary key (id) +); +create sequence e_col_ab_seq; + +create table ecustom_id ( + id varchar2(127) not null, + name varchar2(255), + constraint pk_ecustom_id primary key (id) +); + create table eemb_inner ( id number(10) not null, nome_inner varchar2(255), @@ -577,6 +991,8 @@ create table egen_props ( odt_updated timestamp not null, zdt_created timestamp not null, zdt_updated timestamp not null, + instant_created timestamp not null, + instant_updated timestamp not null, long_created number(19) not null, long_updated number(19) not null, constraint pk_egen_props primary key (id) @@ -591,11 +1007,15 @@ create table einvoice ( ship_street varchar2(255), ship_suburb varchar2(255), ship_city varchar2(255), - street varchar2(255), - suburb varchar2(255), - city varchar2(255), + ship_status varchar2(3), + bill_street varchar2(255), + bill_suburb varchar2(255), + bill_city varchar2(255), + bill_status varchar2(3), version number(19) not null, - constraint ck_einvoice_state check (state in (0,1,2)), + constraint ck_einvoice_state check ( state in (0,1,2)), + constraint ck_einvoice_ship_status check ( ship_status in ('ONE','TWO')), + constraint ck_einvoice_bill_status check ( bill_status in ('ONE','TWO')), constraint pk_einvoice primary key (id) ); create sequence einvoice_seq; @@ -662,18 +1082,122 @@ create table eperson ( notes varchar2(255), street varchar2(255), suburb varchar2(255), - city varchar2(255), + addr_city varchar2(255), + addr_status varchar2(3), version number(19) not null, + constraint ck_eperson_addr_status check ( addr_status in ('ONE','TWO')), constraint pk_eperson primary key (id) ); create sequence eperson_seq; +create table e_person_online ( + id number(19) not null, + email varchar2(127), + online_status number(1) default 0 not null, + when_updated timestamp not null, + constraint uq_e_person_online_email unique (email), + constraint pk_e_person_online primary key (id) +); +create sequence e_person_online_seq; + create table esimple ( - usertypeid number(10) not null, + usertypeid number(10) generated always as identity not null, name varchar2(255), constraint pk_esimple primary key (usertypeid) ); -create sequence esimple_seq; + +create table esoft_del_book ( + id number(19) not null, + book_title varchar2(255), + lend_by_id number(19), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_book primary key (id) +); +create sequence esoft_del_book_seq; + +create table esoft_del_book_esoft_del_user ( + esoft_del_book_id number(19) not null, + esoft_del_user_id number(19) not null, + constraint pk_esft_dl_bk_sft_dl_sr primary key (esoft_del_book_id,esoft_del_user_id) +); + +create table esoft_del_down ( + id number(19) not null, + esoft_del_mid_id number(19) not null, + down varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_down primary key (id) +); +create sequence esoft_del_down_seq; + +create table esoft_del_mid ( + id number(19) not null, + top_id number(19), + mid varchar2(255), + up_id number(19), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_mid primary key (id) +); +create sequence esoft_del_mid_seq; + +create table esoft_del_role ( + id number(19) not null, + role_name varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_role primary key (id) +); +create sequence esoft_del_role_seq; + +create table esoft_del_role_esoft_del_user ( + esoft_del_role_id number(19) not null, + esoft_del_user_id number(19) not null, + constraint pk_esft_dl_rl_sft_dl_sr primary key (esoft_del_role_id,esoft_del_user_id) +); + +create table esoft_del_top ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_top primary key (id) +); +create sequence esoft_del_top_seq; + +create table esoft_del_up ( + id number(19) not null, + up varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_up primary key (id) +); +create sequence esoft_del_up_seq; + +create table esoft_del_user ( + id number(19) not null, + user_name varchar2(255), + version number(19) not null, + deleted number(1) default 0 not null, + constraint pk_esoft_del_user primary key (id) +); +create sequence esoft_del_user_seq; + +create table esoft_del_user_esoft_del_role ( + esoft_del_user_id number(19) not null, + esoft_del_role_id number(19) not null, + constraint pk_esft_dl_sr_sft_dl_rl primary key (esoft_del_user_id,esoft_del_role_id) +); + +create table esome_convert_type ( + id number(19) not null, + name varchar2(255), + money number(38), + constraint pk_esome_convert_type primary key (id) +); +create sequence esome_convert_type_seq; create table esome_type ( id number(10) not null, @@ -691,6 +1215,15 @@ create table etrans_many ( ); create sequence etrans_many_seq; +create table rawinherit_uncle ( + id number(10) not null, + name varchar2(255), + parent_id number(19) not null, + version number(19) not null, + constraint pk_rawinherit_uncle primary key (id) +); +create sequence rawinherit_uncle_seq; + create table evanilla_collection ( id number(10) not null, name varchar2(255), @@ -709,11 +1242,11 @@ create sequence evanilla_collection_detail_seq; create table ewho_props ( id number(19) not null, name varchar2(255), - who_created varchar2(255) not null, - who_modified varchar2(255) not null, version number(19) not null, when_created timestamp not null, when_modified timestamp not null, + who_created varchar2(255) not null, + who_modified varchar2(255) not null, constraint pk_ewho_props primary key (id) ); create sequence ewho_props_seq; @@ -744,6 +1277,15 @@ create table td_parent ( ); create sequence td_parent_seq; +create table empl ( + id number(19) not null, + name varchar2(255), + age number(10), + default_address_id number(19), + constraint pk_empl primary key (id) +); +create sequence empl_seq; + create table feature_desc ( id number(10) not null, name varchar2(255), @@ -768,18 +1310,17 @@ create table foo ( create sequence foo_seq; create table gen_key_identity ( - id number(19) not null, + id number(19) generated always as identity not null, description varchar2(255), constraint pk_gen_key_identity primary key (id) ); -create sequence gen_key_identity_seq; create table gen_key_sequence ( id number(19) not null, description varchar2(255), constraint pk_gen_key_sequence primary key (id) ); -create sequence seq; +create sequence SEQ; create table gen_key_table ( id number(19) not null, @@ -788,9 +1329,29 @@ create table gen_key_table ( ); create sequence gen_key_table_seq; +create table grand_parent_person ( + identifier number(10) not null, + name varchar2(255), + age number(10), + some_bean_id number(10), + family_name varchar2(255), + address varchar2(255), + constraint pk_grand_parent_person primary key (identifier) +); +create sequence grand_parent_person_seq; + +create table survey_group ( + id number(19) not null, + name varchar2(255), + categoryobjectid number(19), + sequence_number number(10) not null, + constraint pk_survey_group primary key (id) +); +create sequence survey_group_seq; + create table c_group ( id number(19) not null, - inactive number(1), + inactive number(1) default 0 not null, name varchar2(255), version number(19) not null, when_created timestamp not null, @@ -799,6 +1360,62 @@ create table c_group ( ); create sequence c_group_seq; +create table he_doc ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_he_doc primary key (id) +); +create sequence he_doc_seq; + +create table hx_link ( + id number(19) not null, + name varchar2(255), + location varchar2(255), + comments varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_hx_link primary key (id) +); +create sequence hx_link_seq; + +create table hx_link_doc ( + hx_link_id number(19) not null, + he_doc_id number(19) not null, + constraint pk_hx_link_doc primary key (hx_link_id,he_doc_id) +); + +create table hi_doc ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_hi_doc primary key (id) +); +create sequence hi_doc_seq; + +create table hi_link ( + id number(19) not null, + name varchar2(255), + location varchar2(255), + comments varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_hi_link primary key (id) +); +create sequence hi_link_seq; + +create table hi_link_doc ( + hi_link_id number(19) not null, + hi_doc_id number(19) not null, + constraint pk_hi_link_doc primary key (hi_link_id,hi_doc_id) +); + create table imrelated ( id number(19) not null, name varchar2(255), @@ -808,18 +1425,18 @@ create table imrelated ( create sequence imrelated_seq; create table imroot ( - dtype varchar2(10) not null, + dtype varchar2(31) not null, id number(19) not null, + name varchar2(255), title varchar2(255), when_title timestamp, - name varchar2(255), constraint pk_imroot primary key (id) ); create sequence imroot_seq; create table ixresource ( dtype varchar2(255), - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), constraint pk_ixresource primary key (id) ); @@ -870,11 +1487,11 @@ create sequence drel_invoice_seq; create table item ( customer number(10) not null, - itemnumber varchar2(255) not null, + itemnumber varchar2(127) not null, description varchar2(255), units varchar2(255), - type number(10), - region number(10), + type number(10) not null, + region number(10) not null, date_modified timestamp, date_created timestamp, modified_by varchar2(255), @@ -883,6 +1500,59 @@ create table item ( constraint pk_item primary key (customer,itemnumber) ); +create table monkey ( + mid number(19) not null, + name varchar2(255), + food_preference varchar2(255), + version number(19) not null, + constraint pk_monkey primary key (mid) +); +create sequence monkey_seq; + +create table trainer ( + tid number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_trainer primary key (tid) +); +create sequence trainer_seq; + +create table trainer_monkey ( + trainer_tid number(19) not null, + monkey_mid number(19) not null, + constraint uq_trainer_monkey_mid unique (monkey_mid), + constraint pk_trainer_monkey primary key (trainer_tid,monkey_mid) +); + +create table troop ( + pid number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_troop primary key (pid) +); +create sequence troop_seq; + +create table troop_monkey ( + troop_pid number(19) not null, + monkey_mid number(19) not null, + constraint uq_troop_monkey_mid unique (monkey_mid), + constraint pk_troop_monkey primary key (troop_pid,monkey_mid) +); + +create table l2_cldf_reset_bean ( + id number(19) not null, + name varchar2(255), + constraint pk_l2_cldf_reset_bean primary key (id) +); +create sequence l2_cldf_reset_bean_seq; + +create table l2_cldf_reset_bean_child ( + id number(19) not null, + parent_id number(19), + constraint pk_l2_cldf_reset_bean_child primary key (id) +); +create sequence l2_cldf_reset_bean_child_seq; + create table level1 ( id number(19) not null, name varchar2(255), @@ -929,6 +1599,35 @@ create table level4 ( ); create sequence level4_seq; +create table link ( + id number(19) not null, + name varchar2(255), + location varchar2(255), + when_publish timestamp, + link_comment varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + deleted number(1) default 0 not null, + constraint pk_link primary key (id) +); +create sequence link_seq; + +create table link_draft ( + id number(19) not null, + name varchar2(255), + location varchar2(255), + when_publish timestamp, + link_comment varchar2(255), + dirty number(1) default 0 not null, + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + deleted number(1) default 0 not null, + constraint pk_link_draft primary key (id) +); +create sequence link_draft_seq; + create table la_attr_value ( id number(10) not null, name varchar2(255), @@ -959,7 +1658,7 @@ create table non_updateprop ( non_enum varchar2(5), name varchar2(255), note varchar2(255), - constraint ck_non_updateprop_non_enum check (non_enum in ('BEGIN','END')), + constraint ck_non_updateprop_non_enum check ( non_enum in ('BEGIN','END')), constraint pk_non_updateprop primary key (id) ); create sequence non_updateprop_seq; @@ -975,16 +1674,16 @@ create table mprinter ( last_swap_black_id number(19), version number(19) not null, constraint uq_mprinter_last_swap_cyan_id unique (last_swap_cyan_id), - constraint uq_mprinter_last_swap_magen_2 unique (last_swap_magenta_id), - constraint uq_mprinter_last_swap_yello_3 unique (last_swap_yellow_id), - constraint uq_mprinter_last_swap_black_4 unique (last_swap_black_id), + constraint uq_mprntr_lst_swp_mgnt_d unique (last_swap_magenta_id), + constraint uq_mprntr_lst_swp_yllw_d unique (last_swap_yellow_id), + constraint uq_mprntr_lst_swp_blck_d unique (last_swap_black_id), constraint pk_mprinter primary key (id) ); create sequence mprinter_seq; create table mprinter_state ( id number(19) not null, - flags number(19), + flags number(19) not null, printer_id number(19), version number(19) not null, constraint pk_mprinter_state primary key (id) @@ -1041,6 +1740,34 @@ create table muser_type ( ); create sequence muser_type_seq; +create table mail_box ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_mail_box primary key (id) +); +create sequence mail_box_seq; + +create table mail_user ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_mail_user primary key (id) +); +create sequence mail_user_seq; + +create table mail_user_inbox ( + mail_user_id number(19) not null, + mail_box_id number(19) not null, + constraint pk_mail_user_inbox primary key (mail_user_id,mail_box_id) +); + +create table mail_user_outbox ( + mail_user_id number(19) not null, + mail_box_id number(19) not null, + constraint pk_mail_user_outbox primary key (mail_user_id,mail_box_id) +); + create table map_super_actual ( id number(19) not null, name varchar2(255), @@ -1085,6 +1812,57 @@ create table mnoc_user_mnoc_role ( constraint pk_mnoc_user_mnoc_role primary key (mnoc_user_user_id,mnoc_role_role_id) ); +create table mny_a ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_mny_a primary key (id) +); +create sequence mny_a_seq; + +create table mny_b ( + id number(19) not null, + name varchar2(255), + a_id number(19), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_mny_b primary key (id) +); +create sequence mny_b_seq; + +create table mny_b_mny_c ( + mny_b_id number(19) not null, + mny_c_id number(19) not null, + constraint pk_mny_b_mny_c primary key (mny_b_id,mny_c_id) +); + +create table mny_c ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_mny_c primary key (id) +); +create sequence mny_c_seq; + +create table mny_topic ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_mny_topic primary key (id) +); +create sequence mny_topic_seq; + +create table subtopics ( + topic number(19) not null, + subtopic number(19) not null, + constraint pk_subtopics primary key (topic,subtopic) +); + create table mp_role ( id number(19) not null, mp_user_id number(19) not null, @@ -1101,10 +1879,40 @@ create table mp_user ( ); create sequence mp_user_seq; +create table ms_many_a ( + aid number(19) not null, + name varchar2(255), + ms_many_a_many_b number(1) default 0 not null, + ms_many_b number(1) default 0 not null, + deleted number(1) default 0 not null, + constraint pk_ms_many_a primary key (aid) +); +create sequence ms_many_a_seq; + +create table ms_many_a_many_b ( + ms_many_a_aid number(19) not null, + ms_many_b_bid number(19) not null, + constraint pk_ms_many_a_many_b primary key (ms_many_a_aid,ms_many_b_bid) +); + +create table ms_many_b ( + bid number(19) not null, + name varchar2(255), + deleted number(1) default 0 not null, + constraint pk_ms_many_b primary key (bid) +); +create sequence ms_many_b_seq; + +create table ms_many_b_many_a ( + ms_many_b_bid number(19) not null, + ms_many_a_aid number(19) not null, + constraint pk_ms_many_b_many_a primary key (ms_many_b_bid,ms_many_a_aid) +); + create table my_lob_size ( id number(10) not null, name varchar2(255), - my_count number(10), + my_count number(10) not null, my_lob clob, constraint pk_my_lob_size primary key (id) ); @@ -1145,6 +1953,25 @@ create table o_cached_bean_child ( ); create sequence o_cached_bean_child_seq; +create table o_cached_natkey ( + id number(19) not null, + store varchar2(255), + sku varchar2(255), + description varchar2(255), + constraint pk_o_cached_natkey primary key (id) +); +create sequence o_cached_natkey_seq; + +create table o_cached_natkey3 ( + id number(19) not null, + store varchar2(255), + code number(10) not null, + sku varchar2(255), + description varchar2(255), + constraint pk_o_cached_natkey3 primary key (id) +); +create sequence o_cached_natkey3_seq; + create table ocar ( id number(10) not null, vin varchar2(255), @@ -1156,8 +1983,19 @@ create table ocar ( ); create sequence ocar_seq; +create table ocompany ( + id number(10) not null, + corp_id varchar2(50), + cretime timestamp not null, + updtime timestamp not null, + version number(19) not null, + constraint uq_ocompany_corp_id unique (corp_id), + constraint pk_ocompany primary key (id) +); +create sequence ocompany_seq; + create table oengine ( - engine_id raw(16) not null, + engine_id varchar2(40) not null, short_desc varchar2(255), car_id number(10), version number(10) not null, @@ -1166,7 +2004,7 @@ create table oengine ( ); create table ogear_box ( - id raw(16) not null, + id varchar2(40) not null, box_desc varchar2(255), box_size number(10), car_id number(10), @@ -1175,6 +2013,35 @@ create table ogear_box ( constraint pk_ogear_box primary key (id) ); +create table oroad_show_msg ( + id number(10) not null, + company_id number(10) not null, + cretime timestamp not null, + updtime timestamp not null, + version number(19) not null, + constraint uq_oroad_show_msg_company_id unique (company_id), + constraint pk_oroad_show_msg primary key (id) +); +create sequence oroad_show_msg_seq; + +create table om_ordered_detail ( + id number(19) not null, + name varchar2(255), + master_id number(19), + version number(19) not null, + sort_order number(10), + constraint pk_om_ordered_detail primary key (id) +); +create sequence om_ordered_detail_seq; + +create table om_ordered_master ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_om_ordered_master primary key (id) +); +create sequence om_ordered_master_seq; + create table o_order ( id number(10) not null, status number(10), @@ -1183,14 +2050,14 @@ create table o_order ( kcustomer_id number(10) not null, cretime timestamp not null, updtime timestamp not null, - constraint ck_o_order_status check (status in (0,1,2,3)), + constraint ck_o_order_status check ( status in (0,1,2,3)), constraint pk_o_order primary key (id) ); create sequence o_order_seq; create table o_order_detail ( id number(10) not null, - order_id number(10), + order_id number(10) not null, order_qty number(10), ship_qty number(10), unit_price number(19,4), @@ -1202,15 +2069,15 @@ create table o_order_detail ( create sequence o_order_detail_seq; create table s_orders ( - uuid varchar2(255) not null, + uuid varchar2(40) not null, constraint pk_s_orders primary key (uuid) ); create table s_order_items ( - uuid varchar2(255) not null, + uuid varchar2(40) not null, product_variant_uuid varchar2(255), - order_uuid varchar2(255), - quantity number(10), + order_uuid varchar2(40), + quantity number(10) not null, amount number(38), constraint pk_s_order_items primary key (uuid) ); @@ -1226,6 +2093,30 @@ create table or_order_ship ( ); create sequence or_order_ship_seq; +create table organisation ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_organisation primary key (id) +); +create sequence organisation_seq; + +create table oto_bchild ( + master_id number(19) not null, + child varchar2(255), + constraint pk_oto_bchild primary key (master_id) +); +create sequence oto_bchild_seq; + +create table oto_bmaster ( + id number(19) not null, + name varchar2(255), + constraint pk_oto_bmaster primary key (id) +); +create sequence oto_bmaster_seq; + create table oto_child ( id number(10) not null, name varchar2(255), @@ -1235,6 +2126,26 @@ create table oto_child ( ); create sequence oto_child_seq; +create table oto_cust ( + cid number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_oto_cust primary key (cid) +); +create sequence oto_cust_seq; + +create table oto_cust_address ( + aid number(19) not null, + line1 varchar2(255), + line2 varchar2(255), + line3 varchar2(255), + customer_cid number(19), + version number(19) not null, + constraint uq_ot_cst_ddrss_cstmr_cd unique (customer_cid), + constraint pk_oto_cust_address primary key (aid) +); +create sequence oto_cust_address_seq; + create table oto_master ( id number(19) not null, name varchar2(255), @@ -1242,6 +2153,82 @@ create table oto_master ( ); create sequence oto_master_seq; +create table oto_prime ( + pid number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_oto_prime primary key (pid) +); +create sequence oto_prime_seq; + +create table oto_prime_extra ( + eid number(19) not null, + extra varchar2(255), + version number(19) not null, + constraint pk_oto_prime_extra primary key (eid) +); + +create table oto_th_many ( + id number(19) not null, + oto_th_top_id number(19) not null, + many varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_oto_th_many primary key (id) +); +create sequence oto_th_many_seq; + +create table oto_th_one ( + id number(19) not null, + one number(1) default 0 not null, + many_id number(19), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint uq_oto_th_one_many_id unique (many_id), + constraint pk_oto_th_one primary key (id) +); +create sequence oto_th_one_seq; + +create table oto_th_top ( + id number(19) not null, + topp varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_oto_th_top primary key (id) +); +create sequence oto_th_top_seq; + +create table oto_ubprime ( + pid varchar2(40) not null, + name varchar2(255), + version number(19) not null, + constraint pk_oto_ubprime primary key (pid) +); + +create table oto_ubprime_extra ( + eid varchar2(40) not null, + extra varchar2(255), + version number(19) not null, + constraint pk_oto_ubprime_extra primary key (eid) +); + +create table oto_uprime ( + pid varchar2(40) not null, + name varchar2(255), + version number(19) not null, + constraint pk_oto_uprime primary key (pid) +); + +create table oto_uprime_extra ( + eid varchar2(40) not null, + extra varchar2(255), + version number(19) not null, + constraint pk_oto_uprime_extra primary key (eid) +); + create table pfile ( id number(10) not null, name varchar2(255), @@ -1267,7 +2254,7 @@ create table pfile_content ( create sequence pfile_content_seq; create table paggview ( - pview_id raw(16), + pview_id varchar2(40), amount number(10) not null, constraint uq_paggview_pview_id unique (pview_id) ); @@ -1301,6 +2288,7 @@ create table rawinherit_parent ( type varchar2(31) not null, id number(19) not null, val number(10), + more varchar2(255), constraint pk_rawinherit_parent primary key (id) ); create sequence rawinherit_parent_seq; @@ -1308,9 +2296,21 @@ create sequence rawinherit_parent_seq; create table rawinherit_parent_rawinherit_d ( rawinherit_parent_id number(19) not null, rawinherit_data_id number(19) not null, - constraint pk_rawinherit_parent_rawinh_0 primary key (rawinherit_parent_id,rawinherit_data_id) + constraint pk_rwnhrt_prnt_rwnhrt_d primary key (rawinherit_parent_id,rawinherit_data_id) ); +create table parent_person ( + identifier number(10) not null, + name varchar2(255), + age number(10), + some_bean_id number(10), + parent_identifier number(10), + family_name varchar2(255), + address varchar2(255), + constraint pk_parent_person primary key (identifier) +); +create sequence parent_person_seq; + create table c_participation ( id number(19) not null, rating number(10), @@ -1320,13 +2320,13 @@ create table c_participation ( version number(19) not null, when_created timestamp not null, when_modified timestamp not null, - constraint ck_c_participation_type check (type in (0,1)), + constraint ck_c_participation_type check ( type in (0,1)), constraint pk_c_participation primary key (id) ); create sequence c_participation_seq; create table mt_permission ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), constraint pk_mt_permission primary key (id) ); @@ -1348,7 +2348,7 @@ create table persistent_file_content ( cretime timestamp not null, updtime timestamp not null, version number(19) not null, - constraint uq_persistent_file_content__1 unique (persistent_file_id), + constraint uq_prsstnt_fl_cntnt_prsstnt_1 unique (persistent_file_id), constraint pk_persistent_file_content primary key (id) ); create sequence persistent_file_content_seq; @@ -1359,7 +2359,7 @@ create table persons ( name varchar2(64) not null, constraint pk_persons primary key (id) ); -create sequence persons_seq start with 1000 increment by 40; +create sequence PERSONS_seq start with 1000; create table person ( oid number(19) not null, @@ -1376,7 +2376,15 @@ create table phones ( constraint uq_phones_phone_number unique (phone_number), constraint pk_phones primary key (id) ); -create sequence phones_seq; +create sequence PHONES_seq; + +create table primary_revision ( + id number(19) not null, + revision number(10) not null, + name varchar2(255), + version number(19) not null, + constraint pk_primary_revision primary key (id,revision) +); create table o_product ( id number(10) not null, @@ -1389,29 +2397,38 @@ create table o_product ( create sequence o_product_seq; create table pp ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), value varchar2(100) not null, constraint pk_pp primary key (id) ); create table pp_to_ww ( - pp_id raw(16) not null, - ww_id raw(16) not null, + pp_id varchar2(40) not null, + ww_id varchar2(40) not null, constraint pk_pp_to_ww primary key (pp_id,ww_id) ); +create table question ( + id number(19) not null, + name varchar2(255), + groupobjectid number(19), + sequence_number number(10) not null, + constraint pk_question primary key (id) +); +create sequence question_seq; + create table rcustomer ( - company varchar2(255) not null, - name varchar2(255) not null, + company varchar2(127) not null, + name varchar2(127) not null, description varchar2(255), constraint pk_rcustomer primary key (company,name) ); create table r_orders ( - company varchar2(255) not null, + company varchar2(127) not null, order_number number(10) not null, - customername varchar2(255), + customername varchar2(127), item varchar2(255), constraint pk_r_orders primary key (company,order_number) ); @@ -1431,20 +2448,6 @@ create table resourcefile ( constraint pk_resourcefile primary key (id) ); -create table mt_role ( - id raw(16) not null, - name varchar2(50), - tenant_id raw(16), - version number(19) not null, - constraint pk_mt_role primary key (id) -); - -create table mt_role_permission ( - mt_role_id raw(16) not null, - mt_permission_id raw(16) not null, - constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) -); - create table em_role ( id number(19) not null, name varchar2(255), @@ -1452,8 +2455,23 @@ create table em_role ( ); create sequence em_role_seq; +create table mt_role ( + id varchar2(40) not null, + name varchar2(50), + tenant_id varchar2(40), + version number(19) not null, + constraint pk_mt_role primary key (id) +); + +create table mt_role_permission ( + mt_role_id varchar2(40) not null, + mt_permission_id varchar2(40) not null, + constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) +); + create table f_second ( id number(19) not null, + mod_name varchar2(255), first number(19), title varchar2(255), constraint uq_f_second_first unique (first), @@ -1469,7 +2487,7 @@ create table section ( cretime timestamp not null, updtime timestamp not null, version number(19) not null, - constraint ck_section_type check (type in (0,1)), + constraint ck_section_type check ( type in (0,1)), constraint pk_section primary key (id) ); create sequence section_seq; @@ -1503,7 +2521,7 @@ create table some_enum_bean ( id number(19) not null, some_enum number(10), name varchar2(255), - constraint ck_some_enum_bean_some_enum check (some_enum in (0,1)), + constraint ck_some_enum_bean_some_enum check ( some_enum in (0,1)), constraint pk_some_enum_bean primary key (id) ); create sequence some_enum_bean_seq; @@ -1530,18 +2548,16 @@ create table some_new_types_bean ( instant timestamp, zone_id varchar2(60), zone_offset varchar2(60), + path varchar2(255), version number(19) not null, - constraint ck_some_new_types_bean_dow check (dow in ('1','2','3','4','5','6','7')), - constraint ck_some_new_types_bean_mth check (mth in ('1','2','3','4','5','6','7','8','9','10','11','12')), + constraint ck_some_new_types_bean_dow check ( dow in (1,2,3,4,5,6,7)), + constraint ck_some_new_types_bean_mth check ( mth in (1,2,3,4,5,6,7,8,9,10,11,12)), constraint pk_some_new_types_bean primary key (id) ); create sequence some_new_types_bean_seq; create table some_period_bean ( id number(19) not null, - period_years number(10), - period_months number(10), - period_days number(10), anniversary date, version number(19) not null, constraint pk_some_period_bean primary key (id) @@ -1575,6 +2591,13 @@ create table sub_type ( ); create sequence sub_type_seq; +create table survey ( + id number(19) not null, + name varchar2(255), + constraint pk_survey primary key (id) +); +create sequence survey_seq; + create table tbytes_only ( id number(10) not null, content blob, @@ -1584,11 +2607,40 @@ create sequence tbytes_only_seq; create table tcar ( type varchar2(31) not null, - plate_no varchar2(255) not null, + plate_no varchar2(32) not null, truckload number(19), constraint pk_tcar primary key (plate_no) ); +create table tevent ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + constraint pk_tevent primary key (id) +); +create sequence tevent_seq; + +create table tevent_many ( + id number(19) not null, + description varchar2(255), + event_id number(19), + units number(10) not null, + amount number(19,4) not null, + version number(19) not null, + constraint pk_tevent_many primary key (id) +); +create sequence tevent_many_seq; + +create table tevent_one ( + id number(19) not null, + name varchar2(255), + event_id number(19), + version number(19) not null, + constraint uq_tevent_one_event_id unique (event_id), + constraint pk_tevent_one primary key (id) +); +create sequence tevent_one_seq; + create table tint_root ( my_type number(3) not null, id number(10) not null, @@ -1618,7 +2670,7 @@ create table t_oneb ( id number(10) not null, name varchar2(255), description varchar2(255), - active number(1), + active number(1) default 0 not null, constraint pk_t_oneb primary key (id) ); create sequence t_oneb_seq; @@ -1627,9 +2679,11 @@ create table t_detail_with_other_namexxxyy ( id number(10) not null, name varchar2(255), description varchar2(255), - active number(1), + some_unique_value varchar2(127), + active number(1) default 0 not null, master_id number(10), - constraint pk_t_detail_with_other_name_0 primary key (id) + constraint uq_t_dtl_wth_thr_nmxxxyy_sm_1 unique (some_unique_value), + constraint pk_t_dtl_wth_thr_nmxxxyy primary key (id) ); create sequence t_atable_detail_seq; @@ -1637,7 +2691,7 @@ create table ts_detail_two ( id number(10) not null, name varchar2(255), description varchar2(255), - active number(1), + active number(1) default 0 not null, master_id number(10), constraint pk_ts_detail_two primary key (id) ); @@ -1647,7 +2701,7 @@ create table t_atable_thatisrelatively ( id number(10) not null, name varchar2(255), description varchar2(255), - active number(1), + active number(1) default 0 not null, constraint pk_t_atable_thatisrelatively primary key (id) ); create sequence t_atable_master_seq; @@ -1656,20 +2710,20 @@ create table ts_master_two ( id number(10) not null, name varchar2(255), description varchar2(255), - active number(1), + active number(1) default 0 not null, constraint pk_ts_master_two primary key (id) ); create sequence ts_master_two_seq; create table tuuid_entity ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), constraint pk_tuuid_entity primary key (id) ); create table twheel ( id number(19) not null, - owner_plate_no varchar2(255) not null, + owner_plate_no varchar2(32) not null, constraint pk_twheel primary key (id) ); create sequence twheel_seq; @@ -1683,18 +2737,21 @@ create table twith_pre_insert ( create sequence twith_pre_insert_seq; create table mt_tenant ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), version number(19) not null, constraint pk_mt_tenant primary key (id) ); -create table sa_tire ( - id number(19) not null, - version number(10) not null, - constraint pk_sa_tire primary key (id) +create table test_annotation_base_entity ( + direct varchar2(255), + meta varchar2(255), + mixed varchar2(255), + constraint_annotation varchar2(40), + null1 varchar2(255) not null, + null2 varchar2(255), + null3 varchar2(255) ); -create sequence sa_tire_seq; create table tire ( id number(19) not null, @@ -1705,6 +2762,13 @@ create table tire ( ); create sequence tire_seq; +create table sa_tire ( + id number(19) not null, + version number(10) not null, + constraint pk_sa_tire primary key (id) +); +create sequence sa_tire_seq; + create table trip ( id number(10) not null, vehicle_driver_id number(10), @@ -1734,6 +2798,15 @@ create table type ( constraint pk_type primary key (customer,type) ); +create table tz_bean ( + id number(19) not null, + moda varchar2(255), + ts timestamp, + tstz timestamp, + constraint pk_tz_bean primary key (id) +); +create sequence tz_bean_seq; + create table ut_detail ( id number(10) not null, utmaster_id number(10) not null, @@ -1755,24 +2828,31 @@ create table ut_master ( create sequence ut_master_seq; create table uuone ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), constraint pk_uuone primary key (id) ); create table uutwo ( - id raw(16) not null, + id varchar2(40) not null, name varchar2(255), - master_id raw(16), + master_id varchar2(40), constraint pk_uutwo primary key (id) ); -create table em_user ( +create table c_user ( id number(19) not null, + inactive number(1) default 0 not null, name varchar2(255), - constraint pk_em_user primary key (id) + email varchar2(255), + password_hash varchar2(255), + group_id number(19), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + constraint pk_c_user primary key (id) ); -create sequence em_user_seq; +create sequence c_user_seq; create table tx_user ( id number(19) not null, @@ -1781,18 +2861,20 @@ create table tx_user ( ); create sequence tx_user_seq; -create table c_user ( +create table g_user ( id number(19) not null, - inactive number(1), - name varchar2(255), - email varchar2(255), - group_id number(19), + username varchar2(255), version number(19) not null, - when_created timestamp not null, - when_modified timestamp not null, - constraint pk_c_user primary key (id) + constraint pk_g_user primary key (id) ); -create sequence c_user_seq; +create sequence g_user_seq; + +create table em_user ( + id number(19) not null, + name varchar2(255), + constraint pk_em_user primary key (id) +); +create sequence em_user_seq; create table oto_user ( id number(19) not null, @@ -1820,10 +2902,13 @@ create table vehicle ( cretime timestamp not null, updtime timestamp not null, version number(19) not null, - truck_ref_id number(10), - capacity number(19,4), + siz varchar2(1), driver varchar2(255), car_ref_id number(10), + notes varchar2(255), + truck_ref_id number(10), + capacity number(19,4), + constraint ck_vehicle_siz check ( siz in ('S','M','L','H')), constraint pk_vehicle primary key (id) ); create sequence vehicle_seq; @@ -1863,13 +2948,6 @@ create table sa_wheel ( ); create sequence sa_wheel_seq; -create table sp_car_wheel ( - id number(19) not null, - version number(10) not null, - constraint pk_sp_car_wheel primary key (id) -); -create sequence sp_car_wheel_seq; - create table wheel ( id number(19) not null, version number(10) not null, @@ -1877,10 +2955,30 @@ create table wheel ( ); create sequence wheel_seq; +create table sp_car_wheel ( + id number(19) not null, + version number(10) not null, + constraint pk_sp_car_wheel primary key (id) +); +create sequence sp_car_wheel_seq; + +create table g_who_props_otm ( + id number(19) not null, + name varchar2(255), + version number(19) not null, + when_created timestamp not null, + when_modified timestamp not null, + who_created_id number(19), + who_modified_id number(19), + constraint pk_g_who_props_otm primary key (id) +); +create sequence g_who_props_otm_seq; + create table with_zero ( id number(19) not null, name varchar2(255), parent_id number(10), + lang varchar2(2) default 'en' not null, version number(19) not null, constraint pk_with_zero primary key (id) ); @@ -1894,8 +2992,8 @@ create table parent ( create sequence parent_seq; create table wview ( - id raw(16) not null, - name varchar2(255) not null, + id varchar2(40) not null, + name varchar2(127) not null, constraint uq_wview_name unique (name), constraint pk_wview primary key (id) ); @@ -1908,48 +3006,85 @@ create table zones ( ); create sequence zones_seq; +create index ix_cntct_lst_nm_frst_nm on contact (last_name,first_name); +create index ix_e_basic_name on e_basic (name); alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id); create index ix_bar_foo_id on bar (foo_id); +alter table addr add constraint fk_addr_employee_id foreign key (employee_id) references empl (id); +create index ix_addr_employee_id on addr (employee_id); + alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code); create index ix_o_address_country_code on o_address (country_code); -alter table animals add constraint fk_animals_shelter_id foreign key (shelter_id) references animal_shelter (id); -create index ix_animals_shelter_id on animals (shelter_id); +alter table album add constraint fk_album_cover_id foreign key (cover_id) references cover (id); -alter table attribute add constraint fk_attribute_attribute_hold_1 foreign key (attribute_holder_id) references attribute_holder (id); -create index ix_attribute_attribute_hold_1 on attribute (attribute_holder_id); +alter table animal add constraint fk_animal_shelter_id foreign key (shelter_id) references animal_shelter (id); +create index ix_animal_shelter_id on animal (shelter_id); + +alter table attribute add constraint fk_attrbt_ttrbt_hldr_d foreign key (attribute_holder_id) references attribute_holder (id); +create index ix_attrbt_ttrbt_hldr_d on attribute (attribute_holder_id); alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id); create index ix_bbookmark_user_id on bbookmark (user_id); +alter table bsite_user add constraint fk_bsite_user_site_id foreign key (site_id) references bsite (id); +create index ix_bsite_user_site_id on bsite_user (site_id); + +alter table bsite_user add constraint fk_bsite_user_user_id foreign key (user_id) references buser (id); +create index ix_bsite_user_user_id on bsite_user (user_id); + +alter table bsite_user_b add constraint fk_bsite_user_b_site foreign key (site) references bsite (id); +create index ix_bsite_user_b_site on bsite_user_b (site); + +alter table bsite_user_b add constraint fk_bsite_user_b_usr foreign key (usr) references buser (id); +create index ix_bsite_user_b_usr on bsite_user_b (usr); + +alter table bsite_user_c add constraint fk_bsite_user_c_site_uid foreign key (site_uid) references bsite (id); +create index ix_bsite_user_c_site_uid on bsite_user_c (site_uid); + +alter table bsite_user_c add constraint fk_bsite_user_c_user_uid foreign key (user_uid) references buser (id); +create index ix_bsite_user_c_user_uid on bsite_user_c (user_uid); + alter table drel_booking add constraint fk_drel_booking_agent_invoice foreign key (agent_invoice) references drel_invoice (id); -alter table drel_booking add constraint fk_drel_booking_client_invo_2 foreign key (client_invoice) references drel_invoice (id); +alter table drel_booking add constraint fk_drl_bkng_clnt_nvc foreign key (client_invoice) references drel_invoice (id); -alter table ckey_detail add constraint fk_ckey_detail_ckey_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key); -create index ix_ckey_detail_one_key_two__1 on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key); +create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id); create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); -alter table calculation_result add constraint fk_calculation_result_produ_1 foreign key (product_configuration_id) references configuration (id); -create index ix_calculation_result_produ_1 on calculation_result (product_configuration_id); +alter table calculation_result add constraint fk_clcltn_rslt_prdct_cnfgrt_1 foreign key (product_configuration_id) references configuration (id); +create index ix_clcltn_rslt_prdct_cnfgrt_1 on calculation_result (product_configuration_id); -alter table calculation_result add constraint fk_calculation_result_group_2 foreign key (group_configuration_id) references configuration (id); -create index ix_calculation_result_group_2 on calculation_result (group_configuration_id); +alter table calculation_result add constraint fk_clcltn_rslt_grp_cnfgrtn_d foreign key (group_configuration_id) references configuration (id); +create index ix_clcltn_rslt_grp_cnfgrtn_d on calculation_result (group_configuration_id); -alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_1 foreign key (car) references sp_car_car (id); -create index ix_sp_car_car_wheels_car on sp_car_car_wheels (car); +alter table sp_car_car_wheels add constraint fk_sp_cr_cr_whls_sp_cr_cr foreign key (car) references sp_car_car (id); +create index ix_sp_cr_cr_whls_sp_cr_cr on sp_car_car_wheels (car); -alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_2 foreign key (wheel) references sp_car_wheel (id); -create index ix_sp_car_car_wheels_wheel on sp_car_car_wheels (wheel); +alter table sp_car_car_wheels add constraint fk_sp_cr_cr_whls_sp_cr_whl foreign key (wheel) references sp_car_wheel (id); +create index ix_sp_cr_cr_whls_sp_cr_whl on sp_car_car_wheels (wheel); + +alter table car_accessory add constraint fk_car_accessory_fuse_id foreign key (fuse_id) references car_fuse (id); +create index ix_car_accessory_fuse_id on car_accessory (fuse_id); alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id); create index ix_car_accessory_car_id on car_accessory (car_id); -alter table configuration add constraint fk_configuration_configurat_1 foreign key (configurations_id) references configurations (id); -create index ix_configuration_configurat_1 on configuration (configurations_id); +alter table category add constraint fk_category_surveyobjectid foreign key (surveyobjectid) references survey (id); +create index ix_category_surveyobjectid on category (surveyobjectid); + +alter table child_person add constraint fk_child_person_some_bean_id foreign key (some_bean_id) references e_basic (id); +create index ix_child_person_some_bean_id on child_person (some_bean_id); + +alter table child_person add constraint fk_chld_prsn_prnt_dntfr foreign key (parent_identifier) references parent_person (identifier); +create index ix_chld_prsn_prnt_dntfr on child_person (parent_identifier); + +alter table configuration add constraint fk_cnfgrtn_cnfgrtns_d foreign key (configurations_id) references configurations (id); +create index ix_cnfgrtn_cnfgrtns_d on configuration (configurations_id); alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id); create index ix_contact_customer_id on contact (customer_id); @@ -1963,11 +3098,60 @@ create index ix_contact_note_contact_id on contact_note (contact_id); alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id); create index ix_c_conversation_group_id on c_conversation (group_id); -alter table o_customer add constraint fk_o_customer_billing_addre_1 foreign key (billing_address_id) references o_address (id); -create index ix_o_customer_billing_addre_1 on o_customer (billing_address_id); +alter table o_customer add constraint fk_o_cstmr_bllng_ddrss_d foreign key (billing_address_id) references o_address (id); +create index ix_o_cstmr_bllng_ddrss_d on o_customer (billing_address_id); -alter table o_customer add constraint fk_o_customer_shipping_addr_2 foreign key (shipping_address_id) references o_address (id); -create index ix_o_customer_shipping_addr_2 on o_customer (shipping_address_id); +alter table o_customer add constraint fk_o_cstmr_shppng_ddrss_d foreign key (shipping_address_id) references o_address (id); +create index ix_o_cstmr_shppng_ddrss_d on o_customer (shipping_address_id); + +alter table dcredit_drol add constraint fk_dcredit_drol_dcredit foreign key (dcredit_id) references dcredit (id); +create index ix_dcredit_drol_dcredit on dcredit_drol (dcredit_id); + +alter table dcredit_drol add constraint fk_dcredit_drol_drol foreign key (drol_id) references drol (id); +create index ix_dcredit_drol_drol on dcredit_drol (drol_id); + +alter table drot_drol add constraint fk_drot_drol_drot foreign key (drot_id) references drot (id); +create index ix_drot_drol_drot on drot_drol (drot_id); + +alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) references drol (id); +create index ix_drot_drol_drol on drot_drol (drol_id); + +alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade; +create index ix_dfk_cascade_one_id on dfk_cascade (one_id); + +alter table dfk_set_null add constraint fk_dfk_set_null_one_id foreign key (one_id) references dfk_one (id) on delete set null; +create index ix_dfk_set_null_one_id on dfk_set_null (one_id); + +alter table doc add constraint fk_doc_id foreign key (id) references doc_draft (id); + +alter table doc_link add constraint fk_doc_link_doc foreign key (doc_id) references doc (id); +create index ix_doc_link_doc on doc_link (doc_id); + +alter table doc_link add constraint fk_doc_link_link foreign key (link_id) references link (id); +create index ix_doc_link_link on doc_link (link_id); + +alter table document add constraint fk_document_id foreign key (id) references document_draft (id); + +alter table document add constraint fk_document_organisation_id foreign key (organisation_id) references organisation (id); +create index ix_document_organisation_id on document (organisation_id); + +alter table document_draft add constraint fk_dcmnt_drft_rgnstn_d foreign key (organisation_id) references organisation (id); +create index ix_dcmnt_drft_rgnstn_d on document_draft (organisation_id); + +alter table document_media add constraint fk_document_media_document_id foreign key (document_id) references document (id); +create index ix_document_media_document_id on document_media (document_id); + +alter table document_media_draft add constraint fk_dcmnt_md_drft_dcmnt_d foreign key (document_id) references document_draft (id); +create index ix_dcmnt_md_drft_dcmnt_d on document_media_draft (document_id); + +alter table ebasic_json_map_detail add constraint fk_ebsc_jsn_mp_dtl_wnr_d foreign key (owner_id) references ebasic_json_map (id); +create index ix_ebsc_jsn_mp_dtl_wnr_d on ebasic_json_map_detail (owner_id); + +alter table ebasic_no_sdchild add constraint fk_ebasic_no_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id); +create index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild (owner_id); + +alter table ebasic_sdchild add constraint fk_ebasic_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id); +create index ix_ebasic_sdchild_owner_id on ebasic_sdchild (owner_id); alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id); create index ix_eemb_inner_outer_id on eemb_inner (outer_id); @@ -1975,8 +3159,8 @@ create index ix_eemb_inner_outer_id on eemb_inner (outer_id); alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id); create index ix_einvoice_person_id on einvoice (person_id); -alter table enull_collection_detail add constraint fk_enull_collection_detail__1 foreign key (enull_collection_id) references enull_collection (id); -create index ix_enull_collection_detail__1 on enull_collection_detail (enull_collection_id); +alter table enull_collection_detail add constraint fk_enll_cllctn_dtl_nll_cllc_1 foreign key (enull_collection_id) references enull_collection (id); +create index ix_enll_cllctn_dtl_nll_cllc_1 on enull_collection_detail (enull_collection_id); alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id); create index ix_eopt_one_a_b_id on eopt_one_a (b_id); @@ -1984,12 +3168,66 @@ create index ix_eopt_one_a_b_id on eopt_one_a (b_id); alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id); create index ix_eopt_one_b_c_id on eopt_one_b (c_id); -alter table evanilla_collection_detail add constraint fk_evanilla_collection_deta_1 foreign key (evanilla_collection_id) references evanilla_collection (id); -create index ix_evanilla_collection_deta_1 on evanilla_collection_detail (evanilla_collection_id); +alter table esoft_del_book add constraint fk_esoft_del_book_lend_by_id foreign key (lend_by_id) references esoft_del_user (id); +create index ix_esoft_del_book_lend_by_id on esoft_del_book (lend_by_id); + +alter table esoft_del_book_esoft_del_user add constraint fk_esft_dl_bk_sft_dl_sr_sft_1 foreign key (esoft_del_book_id) references esoft_del_book (id); +create index ix_esft_dl_bk_sft_dl_sr_sft_1 on esoft_del_book_esoft_del_user (esoft_del_book_id); + +alter table esoft_del_book_esoft_del_user add constraint fk_esft_dl_bk_sft_dl_sr_sft_2 foreign key (esoft_del_user_id) references esoft_del_user (id); +create index ix_esft_dl_bk_sft_dl_sr_sft_2 on esoft_del_book_esoft_del_user (esoft_del_user_id); + +alter table esoft_del_down add constraint fk_esft_dl_dwn_sft_dl_md_d foreign key (esoft_del_mid_id) references esoft_del_mid (id); +create index ix_esft_dl_dwn_sft_dl_md_d on esoft_del_down (esoft_del_mid_id); + +alter table esoft_del_mid add constraint fk_esoft_del_mid_top_id foreign key (top_id) references esoft_del_top (id); +create index ix_esoft_del_mid_top_id on esoft_del_mid (top_id); + +alter table esoft_del_mid add constraint fk_esoft_del_mid_up_id foreign key (up_id) references esoft_del_up (id); +create index ix_esoft_del_mid_up_id on esoft_del_mid (up_id); + +alter table esoft_del_role_esoft_del_user add constraint fk_esft_dl_rl_sft_dl_sr_sft_1 foreign key (esoft_del_role_id) references esoft_del_role (id); +create index ix_esft_dl_rl_sft_dl_sr_sft_1 on esoft_del_role_esoft_del_user (esoft_del_role_id); + +alter table esoft_del_role_esoft_del_user add constraint fk_esft_dl_rl_sft_dl_sr_sft_2 foreign key (esoft_del_user_id) references esoft_del_user (id); +create index ix_esft_dl_rl_sft_dl_sr_sft_2 on esoft_del_role_esoft_del_user (esoft_del_user_id); + +alter table esoft_del_user_esoft_del_role add constraint fk_esft_dl_sr_sft_dl_rl_sft_1 foreign key (esoft_del_user_id) references esoft_del_user (id); +create index ix_esft_dl_sr_sft_dl_rl_sft_1 on esoft_del_user_esoft_del_role (esoft_del_user_id); + +alter table esoft_del_user_esoft_del_role add constraint fk_esft_dl_sr_sft_dl_rl_sft_2 foreign key (esoft_del_role_id) references esoft_del_role (id); +create index ix_esft_dl_sr_sft_dl_rl_sft_2 on esoft_del_user_esoft_del_role (esoft_del_role_id); + +alter table rawinherit_uncle add constraint fk_rawinherit_uncle_parent_id foreign key (parent_id) references rawinherit_parent (id); +create index ix_rawinherit_uncle_parent_id on rawinherit_uncle (parent_id); + +alter table evanilla_collection_detail add constraint fk_evnll_cllctn_dtl_vnll_cl_1 foreign key (evanilla_collection_id) references evanilla_collection (id); +create index ix_evnll_cllctn_dtl_vnll_cl_1 on evanilla_collection_detail (evanilla_collection_id); alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id); create index ix_td_child_parent_id on td_child (parent_id); +alter table empl add constraint fk_empl_default_address_id foreign key (default_address_id) references addr (id); +create index ix_empl_default_address_id on empl (default_address_id); + +alter table grand_parent_person add constraint fk_grnd_prnt_prsn_sm_bn_d foreign key (some_bean_id) references e_basic (id); +create index ix_grnd_prnt_prsn_sm_bn_d on grand_parent_person (some_bean_id); + +alter table survey_group add constraint fk_srvy_grp_ctgrybjctd foreign key (categoryobjectid) references category (id); +create index ix_srvy_grp_ctgrybjctd on survey_group (categoryobjectid); + +alter table hx_link_doc add constraint fk_hx_link_doc_hx_link foreign key (hx_link_id) references hx_link (id); +create index ix_hx_link_doc_hx_link on hx_link_doc (hx_link_id); + +alter table hx_link_doc add constraint fk_hx_link_doc_he_doc foreign key (he_doc_id) references he_doc (id); +create index ix_hx_link_doc_he_doc on hx_link_doc (he_doc_id); + +alter table hi_link_doc add constraint fk_hi_link_doc_hi_link foreign key (hi_link_id) references hi_link (id); +create index ix_hi_link_doc_hi_link on hi_link_doc (hi_link_id); + +alter table hi_link_doc add constraint fk_hi_link_doc_hi_doc foreign key (hi_doc_id) references hi_doc (id); +create index ix_hi_link_doc_hi_doc on hi_link_doc (hi_doc_id); + alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id); create index ix_imrelated_owner_id on imrelated (owner_id); @@ -2003,46 +3241,59 @@ alter table inner_report add constraint fk_inner_report_forecast_id foreign key alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id); create index ix_drel_invoice_booking on drel_invoice (booking); -alter table item add constraint fk_item_type foreign key (customer,type) references type (customer,type); -create index ix_item_customer_type on item (customer,type); +alter table item add constraint fk_item_etype foreign key (customer,type) references type (customer,type); +create index ix_item_etype on item (customer,type); -alter table item add constraint fk_item_region foreign key (customer,region) references region (customer,type); -create index ix_item_customer_region on item (customer,region); +alter table item add constraint fk_item_eregion foreign key (customer,region) references region (customer,type); +create index ix_item_eregion on item (customer,region); + +alter table trainer_monkey add constraint fk_trainer_monkey_trainer foreign key (trainer_tid) references trainer (tid); + +alter table trainer_monkey add constraint fk_trainer_monkey_monkey foreign key (monkey_mid) references monkey (mid); + +alter table troop_monkey add constraint fk_troop_monkey_troop foreign key (troop_pid) references troop (pid); + +alter table troop_monkey add constraint fk_troop_monkey_monkey foreign key (monkey_mid) references monkey (mid); + +alter table l2_cldf_reset_bean_child add constraint fk_l2_cldf_rst_bn_chld_prnt_d foreign key (parent_id) references l2_cldf_reset_bean (id); +create index ix_l2_cldf_rst_bn_chld_prnt_d on l2_cldf_reset_bean_child (parent_id); alter table level1_level4 add constraint fk_level1_level4_level1 foreign key (level1_id) references level1 (id); -create index ix_level1_level4_level1_id on level1_level4 (level1_id); +create index ix_level1_level4_level1 on level1_level4 (level1_id); alter table level1_level4 add constraint fk_level1_level4_level4 foreign key (level4_id) references level4 (id); -create index ix_level1_level4_level4_id on level1_level4 (level4_id); +create index ix_level1_level4_level4 on level1_level4 (level4_id); alter table level1_level2 add constraint fk_level1_level2_level1 foreign key (level1_id) references level1 (id); -create index ix_level1_level2_level1_id on level1_level2 (level1_id); +create index ix_level1_level2_level1 on level1_level2 (level1_id); alter table level1_level2 add constraint fk_level1_level2_level2 foreign key (level2_id) references level2 (id); -create index ix_level1_level2_level2_id on level1_level2 (level2_id); +create index ix_level1_level2_level2 on level1_level2 (level2_id); alter table level2_level3 add constraint fk_level2_level3_level2 foreign key (level2_id) references level2 (id); -create index ix_level2_level3_level2_id on level2_level3 (level2_id); +create index ix_level2_level3_level2 on level2_level3 (level2_id); alter table level2_level3 add constraint fk_level2_level3_level3 foreign key (level3_id) references level3 (id); -create index ix_level2_level3_level3_id on level2_level3 (level3_id); +create index ix_level2_level3_level3 on level2_level3 (level3_id); -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute__1 foreign key (la_attr_value_id) references la_attr_value (id); -create index ix_la_attr_value_attribute__1 on la_attr_value_attribute (la_attr_value_id); +alter table link add constraint fk_link_id foreign key (id) references link_draft (id); -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute__2 foreign key (attribute_id) references attribute (id); -create index ix_la_attr_value_attribute__2 on la_attr_value_attribute (attribute_id); +alter table la_attr_value_attribute add constraint fk_l_ttr_vl_ttrbt_l_ttr_vl foreign key (la_attr_value_id) references la_attr_value (id); +create index ix_l_ttr_vl_ttrbt_l_ttr_vl on la_attr_value_attribute (la_attr_value_id); + +alter table la_attr_value_attribute add constraint fk_l_ttr_vl_ttrbt_ttrbt foreign key (attribute_id) references attribute (id); +create index ix_l_ttr_vl_ttrbt_ttrbt on la_attr_value_attribute (attribute_id); alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id); create index ix_mprinter_current_state_id on mprinter (current_state_id); alter table mprinter add constraint fk_mprinter_last_swap_cyan_id foreign key (last_swap_cyan_id) references mprinter_state (id); -alter table mprinter add constraint fk_mprinter_last_swap_magen_3 foreign key (last_swap_magenta_id) references mprinter_state (id); +alter table mprinter add constraint fk_mprntr_lst_swp_mgnt_d foreign key (last_swap_magenta_id) references mprinter_state (id); -alter table mprinter add constraint fk_mprinter_last_swap_yello_4 foreign key (last_swap_yellow_id) references mprinter_state (id); +alter table mprinter add constraint fk_mprntr_lst_swp_yllw_d foreign key (last_swap_yellow_id) references mprinter_state (id); -alter table mprinter add constraint fk_mprinter_last_swap_black_5 foreign key (last_swap_black_id) references mprinter_state (id); +alter table mprinter add constraint fk_mprntr_lst_swp_blck_d foreign key (last_swap_black_id) references mprinter_state (id); alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id); create index ix_mprinter_state_printer_id on mprinter_state (printer_id); @@ -2051,45 +3302,89 @@ alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_ create index ix_mprofile_picture_id on mprofile (picture_id); alter table mrole_muser add constraint fk_mrole_muser_mrole foreign key (mrole_roleid) references mrole (roleid); -create index ix_mrole_muser_mrole_roleid on mrole_muser (mrole_roleid); +create index ix_mrole_muser_mrole on mrole_muser (mrole_roleid); alter table mrole_muser add constraint fk_mrole_muser_muser foreign key (muser_userid) references muser (userid); -create index ix_mrole_muser_muser_userid on mrole_muser (muser_userid); +create index ix_mrole_muser_muser on mrole_muser (muser_userid); alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id); create index ix_muser_user_type_id on muser (user_type_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_user foreign key (mail_user_id) references mail_user (id); +create index ix_mail_user_inbox_mail_user on mail_user_inbox (mail_user_id); + +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_box foreign key (mail_box_id) references mail_box (id); +create index ix_mail_user_inbox_mail_box on mail_user_inbox (mail_box_id); + +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_user foreign key (mail_user_id) references mail_user (id); +create index ix_mail_user_outbox_mail_user on mail_user_outbox (mail_user_id); + +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_box foreign key (mail_box_id) references mail_box (id); +create index ix_mail_user_outbox_mail_box on mail_user_outbox (mail_box_id); + alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id); create index ix_c_message_conversation_id on c_message (conversation_id); alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id); create index ix_c_message_user_id on c_message (user_id); -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_1 foreign key (mnoc_user_user_id) references mnoc_user (user_id); -create index ix_mnoc_user_mnoc_role_mnoc_1 on mnoc_user_mnoc_role (mnoc_user_user_id); +alter table mnoc_user_mnoc_role add constraint fk_mnc_sr_mnc_rl_mnc_sr foreign key (mnoc_user_user_id) references mnoc_user (user_id); +create index ix_mnc_sr_mnc_rl_mnc_sr on mnoc_user_mnoc_role (mnoc_user_user_id); -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_2 foreign key (mnoc_role_role_id) references mnoc_role (role_id); -create index ix_mnoc_user_mnoc_role_mnoc_2 on mnoc_user_mnoc_role (mnoc_role_role_id); +alter table mnoc_user_mnoc_role add constraint fk_mnc_sr_mnc_rl_mnc_rl foreign key (mnoc_role_role_id) references mnoc_role (role_id); +create index ix_mnc_sr_mnc_rl_mnc_rl on mnoc_user_mnoc_role (mnoc_role_role_id); + +alter table mny_b add constraint fk_mny_b_a_id foreign key (a_id) references mny_a (id); +create index ix_mny_b_a_id on mny_b (a_id); + +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_b foreign key (mny_b_id) references mny_b (id); +create index ix_mny_b_mny_c_mny_b on mny_b_mny_c (mny_b_id); + +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_c foreign key (mny_c_id) references mny_c (id); +create index ix_mny_b_mny_c_mny_c on mny_b_mny_c (mny_c_id); + +alter table subtopics add constraint fk_subtopics_mny_topic_1 foreign key (topic) references mny_topic (id); +create index ix_subtopics_mny_topic_1 on subtopics (topic); + +alter table subtopics add constraint fk_subtopics_mny_topic_2 foreign key (subtopic) references mny_topic (id); +create index ix_subtopics_mny_topic_2 on subtopics (subtopic); alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id); create index ix_mp_role_mp_user_id on mp_role (mp_user_id); -alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_pa_1 foreign key (parent_id) references my_lob_size (id); -create index ix_my_lob_size_join_many_pa_1 on my_lob_size_join_many (parent_id); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid); +create index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b (ms_many_a_aid); -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o__1 foreign key (o_cached_bean_id) references o_cached_bean (id); -create index ix_o_cached_bean_country_o__1 on o_cached_bean_country (o_cached_bean_id); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid); +create index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b (ms_many_b_bid); -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o__2 foreign key (o_country_code) references o_country (code); -create index ix_o_cached_bean_country_o__2 on o_cached_bean_country (o_country_code); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid); +create index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a (ms_many_b_bid); -alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cach_1 foreign key (cached_bean_id) references o_cached_bean (id); -create index ix_o_cached_bean_child_cach_1 on o_cached_bean_child (cached_bean_id); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid); +create index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a (ms_many_a_aid); + +alter table my_lob_size_join_many add constraint fk_my_lb_sz_jn_mny_prnt_d foreign key (parent_id) references my_lob_size (id); +create index ix_my_lb_sz_jn_mny_prnt_d on my_lob_size_join_many (parent_id); + +alter table o_cached_bean_country add constraint fk_o_cchd_bn_cntry__cchd_bn foreign key (o_cached_bean_id) references o_cached_bean (id); +create index ix_o_cchd_bn_cntry__cchd_bn on o_cached_bean_country (o_cached_bean_id); + +alter table o_cached_bean_country add constraint fk_o_cchd_bn_cntry__cntry foreign key (o_country_code) references o_country (code); +create index ix_o_cchd_bn_cntry__cntry on o_cached_bean_country (o_country_code); + +alter table o_cached_bean_child add constraint fk_o_cchd_bn_chld_cchd_bn_d foreign key (cached_bean_id) references o_cached_bean (id); +create index ix_o_cchd_bn_chld_cchd_bn_d on o_cached_bean_child (cached_bean_id); alter table oengine add constraint fk_oengine_car_id foreign key (car_id) references ocar (id); alter table ogear_box add constraint fk_ogear_box_car_id foreign key (car_id) references ocar (id); +alter table oroad_show_msg add constraint fk_oroad_show_msg_company_id foreign key (company_id) references ocompany (id); + +alter table om_ordered_detail add constraint fk_om_rdrd_dtl_mstr_d foreign key (master_id) references om_ordered_master (id); +create index ix_om_rdrd_dtl_mstr_d on om_ordered_detail (master_id); + alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id); create index ix_o_order_kcustomer_id on o_order (kcustomer_id); @@ -2105,8 +3400,23 @@ create index ix_s_order_items_order_uuid on s_order_items (order_uuid); alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id); create index ix_or_order_ship_order_id on or_order_ship (order_id); +alter table oto_bchild add constraint fk_oto_bchild_master_id foreign key (master_id) references oto_bmaster (id); + alter table oto_child add constraint fk_oto_child_master_id foreign key (master_id) references oto_master (id); +alter table oto_cust_address add constraint fk_ot_cst_ddrss_cstmr_cd foreign key (customer_cid) references oto_cust (cid); + +alter table oto_prime_extra add constraint fk_oto_prime_extra_eid foreign key (eid) references oto_prime (pid); + +alter table oto_th_many add constraint fk_oto_th_many_oto_th_top_id foreign key (oto_th_top_id) references oto_th_top (id); +create index ix_oto_th_many_oto_th_top_id on oto_th_many (oto_th_top_id); + +alter table oto_th_one add constraint fk_oto_th_one_many_id foreign key (many_id) references oto_th_many (id); + +alter table oto_ubprime_extra add constraint fk_oto_ubprime_extra_eid foreign key (eid) references oto_ubprime (pid); + +alter table oto_uprime_extra add constraint fk_oto_uprime_extra_eid foreign key (eid) references oto_uprime (pid); + alter table pfile add constraint fk_pfile_file_content_id foreign key (file_content_id) references pfile_content (id); alter table pfile add constraint fk_pfile_file_content2_id foreign key (file_content2_id) references pfile_content (id); @@ -2118,19 +3428,25 @@ create index ix_pallet_location_zone_sid on pallet_location (zone_sid); alter table parcel_location add constraint fk_parcel_location_parcelid foreign key (parcelid) references parcel (parcelid); -alter table rawinherit_parent_rawinherit_d add constraint fk_rawinherit_parent_rawinh_1 foreign key (rawinherit_parent_id) references rawinherit_parent (id); -create index ix_rawinherit_parent_rawinh_1 on rawinherit_parent_rawinherit_d (rawinherit_parent_id); +alter table rawinherit_parent_rawinherit_d add constraint fk_rwnhrt_prnt_rwnhrt_d_rwn_1 foreign key (rawinherit_parent_id) references rawinherit_parent (id); +create index ix_rwnhrt_prnt_rwnhrt_d_rwn_1 on rawinherit_parent_rawinherit_d (rawinherit_parent_id); -alter table rawinherit_parent_rawinherit_d add constraint fk_rawinherit_parent_rawinh_2 foreign key (rawinherit_data_id) references rawinherit_data (id); -create index ix_rawinherit_parent_rawinh_2 on rawinherit_parent_rawinherit_d (rawinherit_data_id); +alter table rawinherit_parent_rawinherit_d add constraint fk_rwnhrt_prnt_rwnhrt_d_rwn_2 foreign key (rawinherit_data_id) references rawinherit_data (id); +create index ix_rwnhrt_prnt_rwnhrt_d_rwn_2 on rawinherit_parent_rawinherit_d (rawinherit_data_id); -alter table c_participation add constraint fk_c_participation_conversa_1 foreign key (conversation_id) references c_conversation (id); -create index ix_c_participation_conversa_1 on c_participation (conversation_id); +alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id); +create index ix_parent_person_some_bean_id on parent_person (some_bean_id); + +alter table parent_person add constraint fk_prnt_prsn_prnt_dntfr foreign key (parent_identifier) references grand_parent_person (identifier); +create index ix_prnt_prsn_prnt_dntfr on parent_person (parent_identifier); + +alter table c_participation add constraint fk_c_prtcptn_cnvrstn_d foreign key (conversation_id) references c_conversation (id); +create index ix_c_prtcptn_cnvrstn_d on c_participation (conversation_id); alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id); create index ix_c_participation_user_id on c_participation (user_id); -alter table persistent_file_content add constraint fk_persistent_file_content__1 foreign key (persistent_file_id) references persistent_file (id); +alter table persistent_file_content add constraint fk_prsstnt_fl_cntnt_prsstnt_1 foreign key (persistent_file_id) references persistent_file (id); alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid); create index ix_person_default_address_oid on person (default_address_oid); @@ -2139,25 +3455,28 @@ alter table phones add constraint fk_phones_person_id foreign key (person_id) re create index ix_phones_person_id on phones (person_id); alter table pp_to_ww add constraint fk_pp_to_ww_pp foreign key (pp_id) references pp (id); -create index ix_pp_to_ww_pp_id on pp_to_ww (pp_id); +create index ix_pp_to_ww_pp on pp_to_ww (pp_id); alter table pp_to_ww add constraint fk_pp_to_ww_wview foreign key (ww_id) references wview (id); -create index ix_pp_to_ww_ww_id on pp_to_ww (ww_id); +create index ix_pp_to_ww_wview on pp_to_ww (ww_id); -alter table r_orders add constraint fk_r_orders_rcustomer foreign key (company,customername) references rcustomer (company,name); -create index ix_r_orders_company_custome_1 on r_orders (company,customername); +alter table question add constraint fk_question_groupobjectid foreign key (groupobjectid) references survey_group (id); +create index ix_question_groupobjectid on question (groupobjectid); -alter table resourcefile add constraint fk_resourcefile_parentresou_1 foreign key (parentresourcefileid) references resourcefile (id); -create index ix_resourcefile_parentresou_1 on resourcefile (parentresourcefileid); +alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name); +create index ix_r_orders_customer on r_orders (company,customername); + +alter table resourcefile add constraint fk_rsrcfl_prntrsrcfld foreign key (parentresourcefileid) references resourcefile (id); +create index ix_rsrcfl_prntrsrcfld on resourcefile (parentresourcefileid); alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id); create index ix_mt_role_tenant_id on mt_role (tenant_id); alter table mt_role_permission add constraint fk_mt_role_permission_mt_role foreign key (mt_role_id) references mt_role (id); -create index ix_mt_role_permission_mt_ro_1 on mt_role_permission (mt_role_id); +create index ix_mt_role_permission_mt_role on mt_role_permission (mt_role_id); -alter table mt_role_permission add constraint fk_mt_role_permission_mt_pe_2 foreign key (mt_permission_id) references mt_permission (id); -create index ix_mt_role_permission_mt_pe_2 on mt_role_permission (mt_permission_id); +alter table mt_role_permission add constraint fk_mt_rl_prmssn_mt_prmssn foreign key (mt_permission_id) references mt_permission (id); +create index ix_mt_rl_prmssn_mt_prmssn on mt_role_permission (mt_permission_id); alter table f_second add constraint fk_f_second_first foreign key (first) references f_first (id); @@ -2167,20 +3486,25 @@ create index ix_section_article_id on section (article_id); alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id); create index ix_self_parent_parent_id on self_parent (parent_id); -alter table self_ref_customer add constraint fk_self_ref_customer_referr_1 foreign key (referred_by_id) references self_ref_customer (id); -create index ix_self_ref_customer_referr_1 on self_ref_customer (referred_by_id); +alter table self_ref_customer add constraint fk_slf_rf_cstmr_rfrrd_by_d foreign key (referred_by_id) references self_ref_customer (id); +create index ix_slf_rf_cstmr_rfrrd_by_d on self_ref_customer (referred_by_id); alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id); create index ix_self_ref_example_parent_id on self_ref_example (parent_id); -alter table stockforecast add constraint fk_stockforecast_inner_repo_1 foreign key (inner_report_id) references inner_report (id); -create index ix_stockforecast_inner_repo_1 on stockforecast (inner_report_id); +alter table stockforecast add constraint fk_stckfrcst_nnr_rprt_d foreign key (inner_report_id) references inner_report (id); +create index ix_stckfrcst_nnr_rprt_d on stockforecast (inner_report_id); alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id); create index ix_sub_section_section_id on sub_section (section_id); -alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_name_1 foreign key (master_id) references t_atable_thatisrelatively (id); -create index ix_t_detail_with_other_name_1 on t_detail_with_other_namexxxyy (master_id); +alter table tevent_many add constraint fk_tevent_many_event_id foreign key (event_id) references tevent_one (id); +create index ix_tevent_many_event_id on tevent_many (event_id); + +alter table tevent_one add constraint fk_tevent_one_event_id foreign key (event_id) references tevent (id); + +alter table t_detail_with_other_namexxxyy add constraint fk_t_dtl_wth_thr_nmxxxyy_ms_1 foreign key (master_id) references t_atable_thatisrelatively (id); +create index ix_t_dtl_wth_thr_nmxxxyy_ms_1 on t_detail_with_other_namexxxyy (master_id); alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id); create index ix_ts_detail_two_master_id on ts_detail_two (master_id); @@ -2216,12 +3540,12 @@ create index ix_em_user_role_user_id on em_user_role (user_id); alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id); create index ix_em_user_role_role_id on em_user_role (role_id); -alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id); -create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); - alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id); create index ix_vehicle_car_ref_id on vehicle (car_ref_id); +alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id); +create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); + alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id); create index ix_vehicle_driver_vehicle_id on vehicle_driver (vehicle_id); @@ -2231,11 +3555,11 @@ create index ix_vehicle_driver_address_id on vehicle_driver (address_id); alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id); create index ix_warehouses_officezoneid on warehouses (officezoneid); -alter table warehousesshippingzones add constraint fk_warehousesshippingzones__1 foreign key (warehouseid) references warehouses (id); -create index ix_warehousesshippingzones__1 on warehousesshippingzones (warehouseid); +alter table warehousesshippingzones add constraint fk_wrhssshppngzns_wrhss foreign key (warehouseid) references warehouses (id); +create index ix_wrhssshppngzns_wrhss on warehousesshippingzones (warehouseid); -alter table warehousesshippingzones add constraint fk_warehousesshippingzones__2 foreign key (shippingzoneid) references zones (id); -create index ix_warehousesshippingzones__2 on warehousesshippingzones (shippingzoneid); +alter table warehousesshippingzones add constraint fk_wrhssshppngzns_zns foreign key (shippingzoneid) references zones (id); +create index ix_wrhssshppngzns_zns on warehousesshippingzones (shippingzoneid); alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id); create index ix_sa_wheel_tire on sa_wheel (tire); @@ -2243,6 +3567,12 @@ create index ix_sa_wheel_tire on sa_wheel (tire); alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id); create index ix_sa_wheel_car on sa_wheel (car); +alter table g_who_props_otm add constraint fk_g_wh_prps_tm_wh_crtd_d foreign key (who_created_id) references g_user (id); +create index ix_g_wh_prps_tm_wh_crtd_d on g_who_props_otm (who_created_id); + +alter table g_who_props_otm add constraint fk_g_wh_prps_tm_wh_mdfd_d foreign key (who_modified_id) references g_user (id); +create index ix_g_wh_prps_tm_wh_mdfd_d on g_who_props_otm (who_modified_id); + alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id); create index ix_with_zero_parent_id on with_zero (parent_id); diff --git a/src/test/ddl-review/oracle-drop-all.sql b/src/test/ddl-review/oracle-drop-all.sql index 1c863ed7b..b621e55a1 100644 --- a/src/test/ddl-review/oracle-drop-all.sql +++ b/src/test/ddl-review/oracle-drop-all.sql @@ -1,45 +1,80 @@ alter table bar drop constraint fk_bar_foo_id; drop index ix_bar_foo_id; +alter table addr drop constraint fk_addr_employee_id; +drop index ix_addr_employee_id; + alter table o_address drop constraint fk_o_address_country_code; drop index ix_o_address_country_code; -alter table animals drop constraint fk_animals_shelter_id; -drop index ix_animals_shelter_id; +alter table album drop constraint fk_album_cover_id; -alter table attribute drop constraint fk_attribute_attribute_hold_1; -drop index ix_attribute_attribute_hold_1; +alter table animal drop constraint fk_animal_shelter_id; +drop index ix_animal_shelter_id; + +alter table attribute drop constraint fk_attrbt_ttrbt_hldr_d; +drop index ix_attrbt_ttrbt_hldr_d; alter table bbookmark drop constraint fk_bbookmark_user_id; drop index ix_bbookmark_user_id; +alter table bsite_user drop constraint fk_bsite_user_site_id; +drop index ix_bsite_user_site_id; + +alter table bsite_user drop constraint fk_bsite_user_user_id; +drop index ix_bsite_user_user_id; + +alter table bsite_user_b drop constraint fk_bsite_user_b_site; +drop index ix_bsite_user_b_site; + +alter table bsite_user_b drop constraint fk_bsite_user_b_usr; +drop index ix_bsite_user_b_usr; + +alter table bsite_user_c drop constraint fk_bsite_user_c_site_uid; +drop index ix_bsite_user_c_site_uid; + +alter table bsite_user_c drop constraint fk_bsite_user_c_user_uid; +drop index ix_bsite_user_c_user_uid; + alter table drel_booking drop constraint fk_drel_booking_agent_invoice; -alter table drel_booking drop constraint fk_drel_booking_client_invo_2; +alter table drel_booking drop constraint fk_drl_bkng_clnt_nvc; -alter table ckey_detail drop constraint fk_ckey_detail_ckey_parent; -drop index ix_ckey_detail_one_key_two__1; +alter table ckey_detail drop constraint fk_ckey_detail_parent; +drop index ix_ckey_detail_parent; alter table ckey_parent drop constraint fk_ckey_parent_assoc_id; drop index ix_ckey_parent_assoc_id; -alter table calculation_result drop constraint fk_calculation_result_produ_1; -drop index ix_calculation_result_produ_1; +alter table calculation_result drop constraint fk_clcltn_rslt_prdct_cnfgrt_1; +drop index ix_clcltn_rslt_prdct_cnfgrt_1; -alter table calculation_result drop constraint fk_calculation_result_group_2; -drop index ix_calculation_result_group_2; +alter table calculation_result drop constraint fk_clcltn_rslt_grp_cnfgrtn_d; +drop index ix_clcltn_rslt_grp_cnfgrtn_d; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_1; -drop index ix_sp_car_car_wheels_car; +alter table sp_car_car_wheels drop constraint fk_sp_cr_cr_whls_sp_cr_cr; +drop index ix_sp_cr_cr_whls_sp_cr_cr; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_2; -drop index ix_sp_car_car_wheels_wheel; +alter table sp_car_car_wheels drop constraint fk_sp_cr_cr_whls_sp_cr_whl; +drop index ix_sp_cr_cr_whls_sp_cr_whl; + +alter table car_accessory drop constraint fk_car_accessory_fuse_id; +drop index ix_car_accessory_fuse_id; alter table car_accessory drop constraint fk_car_accessory_car_id; drop index ix_car_accessory_car_id; -alter table configuration drop constraint fk_configuration_configurat_1; -drop index ix_configuration_configurat_1; +alter table category drop constraint fk_category_surveyobjectid; +drop index ix_category_surveyobjectid; + +alter table child_person drop constraint fk_child_person_some_bean_id; +drop index ix_child_person_some_bean_id; + +alter table child_person drop constraint fk_chld_prsn_prnt_dntfr; +drop index ix_chld_prsn_prnt_dntfr; + +alter table configuration drop constraint fk_cnfgrtn_cnfgrtns_d; +drop index ix_cnfgrtn_cnfgrtns_d; alter table contact drop constraint fk_contact_customer_id; drop index ix_contact_customer_id; @@ -53,11 +88,60 @@ drop index ix_contact_note_contact_id; alter table c_conversation drop constraint fk_c_conversation_group_id; drop index ix_c_conversation_group_id; -alter table o_customer drop constraint fk_o_customer_billing_addre_1; -drop index ix_o_customer_billing_addre_1; +alter table o_customer drop constraint fk_o_cstmr_bllng_ddrss_d; +drop index ix_o_cstmr_bllng_ddrss_d; -alter table o_customer drop constraint fk_o_customer_shipping_addr_2; -drop index ix_o_customer_shipping_addr_2; +alter table o_customer drop constraint fk_o_cstmr_shppng_ddrss_d; +drop index ix_o_cstmr_shppng_ddrss_d; + +alter table dcredit_drol drop constraint fk_dcredit_drol_dcredit; +drop index ix_dcredit_drol_dcredit; + +alter table dcredit_drol drop constraint fk_dcredit_drol_drol; +drop index ix_dcredit_drol_drol; + +alter table drot_drol drop constraint fk_drot_drol_drot; +drop index ix_drot_drol_drot; + +alter table drot_drol drop constraint fk_drot_drol_drol; +drop index ix_drot_drol_drol; + +alter table dfk_cascade drop constraint fk_dfk_cascade_one_id; +drop index ix_dfk_cascade_one_id; + +alter table dfk_set_null drop constraint fk_dfk_set_null_one_id; +drop index ix_dfk_set_null_one_id; + +alter table doc drop constraint fk_doc_id; + +alter table doc_link drop constraint fk_doc_link_doc; +drop index ix_doc_link_doc; + +alter table doc_link drop constraint fk_doc_link_link; +drop index ix_doc_link_link; + +alter table document drop constraint fk_document_id; + +alter table document drop constraint fk_document_organisation_id; +drop index ix_document_organisation_id; + +alter table document_draft drop constraint fk_dcmnt_drft_rgnstn_d; +drop index ix_dcmnt_drft_rgnstn_d; + +alter table document_media drop constraint fk_document_media_document_id; +drop index ix_document_media_document_id; + +alter table document_media_draft drop constraint fk_dcmnt_md_drft_dcmnt_d; +drop index ix_dcmnt_md_drft_dcmnt_d; + +alter table ebasic_json_map_detail drop constraint fk_ebsc_jsn_mp_dtl_wnr_d; +drop index ix_ebsc_jsn_mp_dtl_wnr_d; + +alter table ebasic_no_sdchild drop constraint fk_ebasic_no_sdchild_owner_id; +drop index ix_ebasic_no_sdchild_owner_id; + +alter table ebasic_sdchild drop constraint fk_ebasic_sdchild_owner_id; +drop index ix_ebasic_sdchild_owner_id; alter table eemb_inner drop constraint fk_eemb_inner_outer_id; drop index ix_eemb_inner_outer_id; @@ -65,8 +149,8 @@ drop index ix_eemb_inner_outer_id; alter table einvoice drop constraint fk_einvoice_person_id; drop index ix_einvoice_person_id; -alter table enull_collection_detail drop constraint fk_enull_collection_detail__1; -drop index ix_enull_collection_detail__1; +alter table enull_collection_detail drop constraint fk_enll_cllctn_dtl_nll_cllc_1; +drop index ix_enll_cllctn_dtl_nll_cllc_1; alter table eopt_one_a drop constraint fk_eopt_one_a_b_id; drop index ix_eopt_one_a_b_id; @@ -74,12 +158,66 @@ drop index ix_eopt_one_a_b_id; alter table eopt_one_b drop constraint fk_eopt_one_b_c_id; drop index ix_eopt_one_b_c_id; -alter table evanilla_collection_detail drop constraint fk_evanilla_collection_deta_1; -drop index ix_evanilla_collection_deta_1; +alter table esoft_del_book drop constraint fk_esoft_del_book_lend_by_id; +drop index ix_esoft_del_book_lend_by_id; + +alter table esoft_del_book_esoft_del_user drop constraint fk_esft_dl_bk_sft_dl_sr_sft_1; +drop index ix_esft_dl_bk_sft_dl_sr_sft_1; + +alter table esoft_del_book_esoft_del_user drop constraint fk_esft_dl_bk_sft_dl_sr_sft_2; +drop index ix_esft_dl_bk_sft_dl_sr_sft_2; + +alter table esoft_del_down drop constraint fk_esft_dl_dwn_sft_dl_md_d; +drop index ix_esft_dl_dwn_sft_dl_md_d; + +alter table esoft_del_mid drop constraint fk_esoft_del_mid_top_id; +drop index ix_esoft_del_mid_top_id; + +alter table esoft_del_mid drop constraint fk_esoft_del_mid_up_id; +drop index ix_esoft_del_mid_up_id; + +alter table esoft_del_role_esoft_del_user drop constraint fk_esft_dl_rl_sft_dl_sr_sft_1; +drop index ix_esft_dl_rl_sft_dl_sr_sft_1; + +alter table esoft_del_role_esoft_del_user drop constraint fk_esft_dl_rl_sft_dl_sr_sft_2; +drop index ix_esft_dl_rl_sft_dl_sr_sft_2; + +alter table esoft_del_user_esoft_del_role drop constraint fk_esft_dl_sr_sft_dl_rl_sft_1; +drop index ix_esft_dl_sr_sft_dl_rl_sft_1; + +alter table esoft_del_user_esoft_del_role drop constraint fk_esft_dl_sr_sft_dl_rl_sft_2; +drop index ix_esft_dl_sr_sft_dl_rl_sft_2; + +alter table rawinherit_uncle drop constraint fk_rawinherit_uncle_parent_id; +drop index ix_rawinherit_uncle_parent_id; + +alter table evanilla_collection_detail drop constraint fk_evnll_cllctn_dtl_vnll_cl_1; +drop index ix_evnll_cllctn_dtl_vnll_cl_1; alter table td_child drop constraint fk_td_child_parent_id; drop index ix_td_child_parent_id; +alter table empl drop constraint fk_empl_default_address_id; +drop index ix_empl_default_address_id; + +alter table grand_parent_person drop constraint fk_grnd_prnt_prsn_sm_bn_d; +drop index ix_grnd_prnt_prsn_sm_bn_d; + +alter table survey_group drop constraint fk_srvy_grp_ctgrybjctd; +drop index ix_srvy_grp_ctgrybjctd; + +alter table hx_link_doc drop constraint fk_hx_link_doc_hx_link; +drop index ix_hx_link_doc_hx_link; + +alter table hx_link_doc drop constraint fk_hx_link_doc_he_doc; +drop index ix_hx_link_doc_he_doc; + +alter table hi_link_doc drop constraint fk_hi_link_doc_hi_link; +drop index ix_hi_link_doc_hi_link; + +alter table hi_link_doc drop constraint fk_hi_link_doc_hi_doc; +drop index ix_hi_link_doc_hi_doc; + alter table imrelated drop constraint fk_imrelated_owner_id; drop index ix_imrelated_owner_id; @@ -93,46 +231,59 @@ alter table inner_report drop constraint fk_inner_report_forecast_id; alter table drel_invoice drop constraint fk_drel_invoice_booking; drop index ix_drel_invoice_booking; -alter table item drop constraint fk_item_type; -drop index ix_item_customer_type; +alter table item drop constraint fk_item_etype; +drop index ix_item_etype; -alter table item drop constraint fk_item_region; -drop index ix_item_customer_region; +alter table item drop constraint fk_item_eregion; +drop index ix_item_eregion; + +alter table trainer_monkey drop constraint fk_trainer_monkey_trainer; + +alter table trainer_monkey drop constraint fk_trainer_monkey_monkey; + +alter table troop_monkey drop constraint fk_troop_monkey_troop; + +alter table troop_monkey drop constraint fk_troop_monkey_monkey; + +alter table l2_cldf_reset_bean_child drop constraint fk_l2_cldf_rst_bn_chld_prnt_d; +drop index ix_l2_cldf_rst_bn_chld_prnt_d; alter table level1_level4 drop constraint fk_level1_level4_level1; -drop index ix_level1_level4_level1_id; +drop index ix_level1_level4_level1; alter table level1_level4 drop constraint fk_level1_level4_level4; -drop index ix_level1_level4_level4_id; +drop index ix_level1_level4_level4; alter table level1_level2 drop constraint fk_level1_level2_level1; -drop index ix_level1_level2_level1_id; +drop index ix_level1_level2_level1; alter table level1_level2 drop constraint fk_level1_level2_level2; -drop index ix_level1_level2_level2_id; +drop index ix_level1_level2_level2; alter table level2_level3 drop constraint fk_level2_level3_level2; -drop index ix_level2_level3_level2_id; +drop index ix_level2_level3_level2; alter table level2_level3 drop constraint fk_level2_level3_level3; -drop index ix_level2_level3_level3_id; +drop index ix_level2_level3_level3; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute__1; -drop index ix_la_attr_value_attribute__1; +alter table link drop constraint fk_link_id; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute__2; -drop index ix_la_attr_value_attribute__2; +alter table la_attr_value_attribute drop constraint fk_l_ttr_vl_ttrbt_l_ttr_vl; +drop index ix_l_ttr_vl_ttrbt_l_ttr_vl; + +alter table la_attr_value_attribute drop constraint fk_l_ttr_vl_ttrbt_ttrbt; +drop index ix_l_ttr_vl_ttrbt_ttrbt; alter table mprinter drop constraint fk_mprinter_current_state_id; drop index ix_mprinter_current_state_id; alter table mprinter drop constraint fk_mprinter_last_swap_cyan_id; -alter table mprinter drop constraint fk_mprinter_last_swap_magen_3; +alter table mprinter drop constraint fk_mprntr_lst_swp_mgnt_d; -alter table mprinter drop constraint fk_mprinter_last_swap_yello_4; +alter table mprinter drop constraint fk_mprntr_lst_swp_yllw_d; -alter table mprinter drop constraint fk_mprinter_last_swap_black_5; +alter table mprinter drop constraint fk_mprntr_lst_swp_blck_d; alter table mprinter_state drop constraint fk_mprinter_state_printer_id; drop index ix_mprinter_state_printer_id; @@ -141,45 +292,89 @@ alter table mprofile drop constraint fk_mprofile_picture_id; drop index ix_mprofile_picture_id; alter table mrole_muser drop constraint fk_mrole_muser_mrole; -drop index ix_mrole_muser_mrole_roleid; +drop index ix_mrole_muser_mrole; alter table mrole_muser drop constraint fk_mrole_muser_muser; -drop index ix_mrole_muser_muser_userid; +drop index ix_mrole_muser_muser; alter table muser drop constraint fk_muser_user_type_id; drop index ix_muser_user_type_id; +alter table mail_user_inbox drop constraint fk_mail_user_inbox_mail_user; +drop index ix_mail_user_inbox_mail_user; + +alter table mail_user_inbox drop constraint fk_mail_user_inbox_mail_box; +drop index ix_mail_user_inbox_mail_box; + +alter table mail_user_outbox drop constraint fk_mail_user_outbox_mail_user; +drop index ix_mail_user_outbox_mail_user; + +alter table mail_user_outbox drop constraint fk_mail_user_outbox_mail_box; +drop index ix_mail_user_outbox_mail_box; + alter table c_message drop constraint fk_c_message_conversation_id; drop index ix_c_message_conversation_id; alter table c_message drop constraint fk_c_message_user_id; drop index ix_c_message_user_id; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_1; -drop index ix_mnoc_user_mnoc_role_mnoc_1; +alter table mnoc_user_mnoc_role drop constraint fk_mnc_sr_mnc_rl_mnc_sr; +drop index ix_mnc_sr_mnc_rl_mnc_sr; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_2; -drop index ix_mnoc_user_mnoc_role_mnoc_2; +alter table mnoc_user_mnoc_role drop constraint fk_mnc_sr_mnc_rl_mnc_rl; +drop index ix_mnc_sr_mnc_rl_mnc_rl; + +alter table mny_b drop constraint fk_mny_b_a_id; +drop index ix_mny_b_a_id; + +alter table mny_b_mny_c drop constraint fk_mny_b_mny_c_mny_b; +drop index ix_mny_b_mny_c_mny_b; + +alter table mny_b_mny_c drop constraint fk_mny_b_mny_c_mny_c; +drop index ix_mny_b_mny_c_mny_c; + +alter table subtopics drop constraint fk_subtopics_mny_topic_1; +drop index ix_subtopics_mny_topic_1; + +alter table subtopics drop constraint fk_subtopics_mny_topic_2; +drop index ix_subtopics_mny_topic_2; alter table mp_role drop constraint fk_mp_role_mp_user_id; drop index ix_mp_role_mp_user_id; -alter table my_lob_size_join_many drop constraint fk_my_lob_size_join_many_pa_1; -drop index ix_my_lob_size_join_many_pa_1; +alter table ms_many_a_many_b drop constraint fk_ms_many_a_many_b_ms_many_a; +drop index ix_ms_many_a_many_b_ms_many_a; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o__1; -drop index ix_o_cached_bean_country_o__1; +alter table ms_many_a_many_b drop constraint fk_ms_many_a_many_b_ms_many_b; +drop index ix_ms_many_a_many_b_ms_many_b; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o__2; -drop index ix_o_cached_bean_country_o__2; +alter table ms_many_b_many_a drop constraint fk_ms_many_b_many_a_ms_many_b; +drop index ix_ms_many_b_many_a_ms_many_b; -alter table o_cached_bean_child drop constraint fk_o_cached_bean_child_cach_1; -drop index ix_o_cached_bean_child_cach_1; +alter table ms_many_b_many_a drop constraint fk_ms_many_b_many_a_ms_many_a; +drop index ix_ms_many_b_many_a_ms_many_a; + +alter table my_lob_size_join_many drop constraint fk_my_lb_sz_jn_mny_prnt_d; +drop index ix_my_lb_sz_jn_mny_prnt_d; + +alter table o_cached_bean_country drop constraint fk_o_cchd_bn_cntry__cchd_bn; +drop index ix_o_cchd_bn_cntry__cchd_bn; + +alter table o_cached_bean_country drop constraint fk_o_cchd_bn_cntry__cntry; +drop index ix_o_cchd_bn_cntry__cntry; + +alter table o_cached_bean_child drop constraint fk_o_cchd_bn_chld_cchd_bn_d; +drop index ix_o_cchd_bn_chld_cchd_bn_d; alter table oengine drop constraint fk_oengine_car_id; alter table ogear_box drop constraint fk_ogear_box_car_id; +alter table oroad_show_msg drop constraint fk_oroad_show_msg_company_id; + +alter table om_ordered_detail drop constraint fk_om_rdrd_dtl_mstr_d; +drop index ix_om_rdrd_dtl_mstr_d; + alter table o_order drop constraint fk_o_order_kcustomer_id; drop index ix_o_order_kcustomer_id; @@ -195,8 +390,23 @@ drop index ix_s_order_items_order_uuid; alter table or_order_ship drop constraint fk_or_order_ship_order_id; drop index ix_or_order_ship_order_id; +alter table oto_bchild drop constraint fk_oto_bchild_master_id; + alter table oto_child drop constraint fk_oto_child_master_id; +alter table oto_cust_address drop constraint fk_ot_cst_ddrss_cstmr_cd; + +alter table oto_prime_extra drop constraint fk_oto_prime_extra_eid; + +alter table oto_th_many drop constraint fk_oto_th_many_oto_th_top_id; +drop index ix_oto_th_many_oto_th_top_id; + +alter table oto_th_one drop constraint fk_oto_th_one_many_id; + +alter table oto_ubprime_extra drop constraint fk_oto_ubprime_extra_eid; + +alter table oto_uprime_extra drop constraint fk_oto_uprime_extra_eid; + alter table pfile drop constraint fk_pfile_file_content_id; alter table pfile drop constraint fk_pfile_file_content2_id; @@ -208,19 +418,25 @@ drop index ix_pallet_location_zone_sid; alter table parcel_location drop constraint fk_parcel_location_parcelid; -alter table rawinherit_parent_rawinherit_d drop constraint fk_rawinherit_parent_rawinh_1; -drop index ix_rawinherit_parent_rawinh_1; +alter table rawinherit_parent_rawinherit_d drop constraint fk_rwnhrt_prnt_rwnhrt_d_rwn_1; +drop index ix_rwnhrt_prnt_rwnhrt_d_rwn_1; -alter table rawinherit_parent_rawinherit_d drop constraint fk_rawinherit_parent_rawinh_2; -drop index ix_rawinherit_parent_rawinh_2; +alter table rawinherit_parent_rawinherit_d drop constraint fk_rwnhrt_prnt_rwnhrt_d_rwn_2; +drop index ix_rwnhrt_prnt_rwnhrt_d_rwn_2; -alter table c_participation drop constraint fk_c_participation_conversa_1; -drop index ix_c_participation_conversa_1; +alter table parent_person drop constraint fk_parent_person_some_bean_id; +drop index ix_parent_person_some_bean_id; + +alter table parent_person drop constraint fk_prnt_prsn_prnt_dntfr; +drop index ix_prnt_prsn_prnt_dntfr; + +alter table c_participation drop constraint fk_c_prtcptn_cnvrstn_d; +drop index ix_c_prtcptn_cnvrstn_d; alter table c_participation drop constraint fk_c_participation_user_id; drop index ix_c_participation_user_id; -alter table persistent_file_content drop constraint fk_persistent_file_content__1; +alter table persistent_file_content drop constraint fk_prsstnt_fl_cntnt_prsstnt_1; alter table person drop constraint fk_person_default_address_oid; drop index ix_person_default_address_oid; @@ -229,25 +445,28 @@ alter table phones drop constraint fk_phones_person_id; drop index ix_phones_person_id; alter table pp_to_ww drop constraint fk_pp_to_ww_pp; -drop index ix_pp_to_ww_pp_id; +drop index ix_pp_to_ww_pp; alter table pp_to_ww drop constraint fk_pp_to_ww_wview; -drop index ix_pp_to_ww_ww_id; +drop index ix_pp_to_ww_wview; -alter table r_orders drop constraint fk_r_orders_rcustomer; -drop index ix_r_orders_company_custome_1; +alter table question drop constraint fk_question_groupobjectid; +drop index ix_question_groupobjectid; -alter table resourcefile drop constraint fk_resourcefile_parentresou_1; -drop index ix_resourcefile_parentresou_1; +alter table r_orders drop constraint fk_r_orders_customer; +drop index ix_r_orders_customer; + +alter table resourcefile drop constraint fk_rsrcfl_prntrsrcfld; +drop index ix_rsrcfl_prntrsrcfld; alter table mt_role drop constraint fk_mt_role_tenant_id; drop index ix_mt_role_tenant_id; alter table mt_role_permission drop constraint fk_mt_role_permission_mt_role; -drop index ix_mt_role_permission_mt_ro_1; +drop index ix_mt_role_permission_mt_role; -alter table mt_role_permission drop constraint fk_mt_role_permission_mt_pe_2; -drop index ix_mt_role_permission_mt_pe_2; +alter table mt_role_permission drop constraint fk_mt_rl_prmssn_mt_prmssn; +drop index ix_mt_rl_prmssn_mt_prmssn; alter table f_second drop constraint fk_f_second_first; @@ -257,20 +476,25 @@ drop index ix_section_article_id; alter table self_parent drop constraint fk_self_parent_parent_id; drop index ix_self_parent_parent_id; -alter table self_ref_customer drop constraint fk_self_ref_customer_referr_1; -drop index ix_self_ref_customer_referr_1; +alter table self_ref_customer drop constraint fk_slf_rf_cstmr_rfrrd_by_d; +drop index ix_slf_rf_cstmr_rfrrd_by_d; alter table self_ref_example drop constraint fk_self_ref_example_parent_id; drop index ix_self_ref_example_parent_id; -alter table stockforecast drop constraint fk_stockforecast_inner_repo_1; -drop index ix_stockforecast_inner_repo_1; +alter table stockforecast drop constraint fk_stckfrcst_nnr_rprt_d; +drop index ix_stckfrcst_nnr_rprt_d; alter table sub_section drop constraint fk_sub_section_section_id; drop index ix_sub_section_section_id; -alter table t_detail_with_other_namexxxyy drop constraint fk_t_detail_with_other_name_1; -drop index ix_t_detail_with_other_name_1; +alter table tevent_many drop constraint fk_tevent_many_event_id; +drop index ix_tevent_many_event_id; + +alter table tevent_one drop constraint fk_tevent_one_event_id; + +alter table t_detail_with_other_namexxxyy drop constraint fk_t_dtl_wth_thr_nmxxxyy_ms_1; +drop index ix_t_dtl_wth_thr_nmxxxyy_ms_1; alter table ts_detail_two drop constraint fk_ts_detail_two_master_id; drop index ix_ts_detail_two_master_id; @@ -306,12 +530,12 @@ drop index ix_em_user_role_user_id; alter table em_user_role drop constraint fk_em_user_role_role_id; drop index ix_em_user_role_role_id; -alter table vehicle drop constraint fk_vehicle_truck_ref_id; -drop index ix_vehicle_truck_ref_id; - alter table vehicle drop constraint fk_vehicle_car_ref_id; drop index ix_vehicle_car_ref_id; +alter table vehicle drop constraint fk_vehicle_truck_ref_id; +drop index ix_vehicle_truck_ref_id; + alter table vehicle_driver drop constraint fk_vehicle_driver_vehicle_id; drop index ix_vehicle_driver_vehicle_id; @@ -321,11 +545,11 @@ drop index ix_vehicle_driver_address_id; alter table warehouses drop constraint fk_warehouses_officezoneid; drop index ix_warehouses_officezoneid; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones__1; -drop index ix_warehousesshippingzones__1; +alter table warehousesshippingzones drop constraint fk_wrhssshppngzns_wrhss; +drop index ix_wrhssshppngzns_wrhss; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones__2; -drop index ix_warehousesshippingzones__2; +alter table warehousesshippingzones drop constraint fk_wrhssshppngzns_zns; +drop index ix_wrhssshppngzns_zns; alter table sa_wheel drop constraint fk_sa_wheel_tire; drop index ix_sa_wheel_tire; @@ -333,6 +557,12 @@ drop index ix_sa_wheel_tire; alter table sa_wheel drop constraint fk_sa_wheel_car; drop index ix_sa_wheel_car; +alter table g_who_props_otm drop constraint fk_g_wh_prps_tm_wh_crtd_d; +drop index ix_g_wh_prps_tm_wh_crtd_d; + +alter table g_who_props_otm drop constraint fk_g_wh_prps_tm_wh_mdfd_d; +drop index ix_g_wh_prps_tm_wh_mdfd_d; + alter table with_zero drop constraint fk_with_zero_parent_id; drop index ix_with_zero_parent_id; @@ -345,14 +575,20 @@ drop sequence bar_seq; drop table oto_account cascade constraints purge; drop sequence oto_account_seq; -drop table o_address cascade constraints purge; -drop sequence o_address_seq; +drop table addr cascade constraints purge; +drop sequence addr_seq; drop table address cascade constraints purge; drop sequence address_seq; -drop table animals cascade constraints purge; -drop sequence animals_seq; +drop table o_address cascade constraints purge; +drop sequence o_address_seq; + +drop table album cascade constraints purge; +drop sequence album_seq; + +drop table animal cascade constraints purge; +drop sequence animal_seq; drop table animal_shelter cascade constraints purge; drop sequence animal_shelter_seq; @@ -378,6 +614,16 @@ drop sequence bbookmark_user_seq; drop table bsimple_with_gen cascade constraints purge; drop sequence bsimple_with_gen_seq; +drop table bsite cascade constraints purge; + +drop table bsite_user cascade constraints purge; + +drop table bsite_user_b cascade constraints purge; + +drop table bsite_user_c cascade constraints purge; + +drop table buser cascade constraints purge; + drop table bwith_qident cascade constraints purge; drop sequence bwith_qident_seq; @@ -390,6 +636,9 @@ drop sequence bean_with_time_zone_seq; drop table drel_booking cascade constraints purge; drop sequence drel_booking_seq; +drop table cinh_root cascade constraints purge; +drop sequence cinh_root_seq; + drop table ckey_assoc cascade constraints purge; drop sequence ckey_assoc_seq; @@ -414,6 +663,15 @@ drop table sp_car_car_wheels cascade constraints purge; drop table car_accessory cascade constraints purge; drop sequence car_accessory_seq; +drop table car_fuse cascade constraints purge; +drop sequence car_fuse_seq; + +drop table category cascade constraints purge; +drop sequence category_seq; + +drop table child_person cascade constraints purge; +drop sequence child_person_seq; + drop table configuration cascade constraints purge; drop sequence configuration_seq; @@ -434,21 +692,86 @@ drop sequence c_conversation_seq; drop table o_country cascade constraints purge; +drop table cover cascade constraints purge; +drop sequence cover_seq; + drop table o_customer cascade constraints purge; drop sequence o_customer_seq; +drop table dcredit cascade constraints purge; +drop sequence dcredit_seq; + +drop table dcredit_drol cascade constraints purge; + drop table dexh_entity cascade constraints purge; drop sequence dexh_entity_seq; drop table dperson cascade constraints purge; drop sequence dperson_seq; +drop table drol cascade constraints purge; +drop sequence drol_seq; + +drop table drot cascade constraints purge; +drop sequence drot_seq; + +drop table drot_drol cascade constraints purge; + drop table rawinherit_data cascade constraints purge; drop sequence rawinherit_data_seq; +drop table dfk_cascade cascade constraints purge; +drop sequence dfk_cascade_seq; + +drop table dfk_cascade_one cascade constraints purge; +drop sequence dfk_cascade_one_seq; + +drop table dfk_none cascade constraints purge; +drop sequence dfk_none_seq; + +drop table dfk_none_via_join cascade constraints purge; +drop sequence dfk_none_via_join_seq; + +drop table dfk_one cascade constraints purge; +drop sequence dfk_one_seq; + +drop table dfk_set_null cascade constraints purge; +drop sequence dfk_set_null_seq; + +drop table doc cascade constraints purge; +drop sequence doc_seq; + +drop table doc_link cascade constraints purge; + +drop table doc_link_draft cascade constraints purge; + +drop table doc_draft cascade constraints purge; +drop sequence doc_draft_seq; + +drop table document cascade constraints purge; +drop sequence document_seq; + +drop table document_draft cascade constraints purge; +drop sequence document_draft_seq; + +drop table document_media cascade constraints purge; +drop sequence document_media_seq; + +drop table document_media_draft cascade constraints purge; +drop sequence document_media_draft_seq; + +drop table earray_bean cascade constraints purge; +drop sequence earray_bean_seq; + +drop table earray_set_bean cascade constraints purge; +drop sequence earray_set_bean_seq; + drop table e_basic cascade constraints purge; drop sequence e_basic_seq; +drop table ebasic_change_log cascade constraints purge; +drop sequence ebasic_change_log_seq; + drop table ebasic_clob cascade constraints purge; drop sequence ebasic_clob_seq; @@ -466,6 +789,15 @@ drop sequence e_basicenc_bin_seq; drop table e_basic_enum_id cascade constraints purge; +drop table e_basic_eni cascade constraints purge; +drop sequence e_basic_eni_seq; + +drop table ebasic_hstore cascade constraints purge; +drop sequence ebasic_hstore_seq; + +drop table ebasic_json_list cascade constraints purge; +drop sequence ebasic_json_list_seq; + drop table ebasic_json_map cascade constraints purge; drop sequence ebasic_json_map_seq; @@ -475,6 +807,9 @@ drop sequence ebasic_json_map_blob_seq; drop table ebasic_json_map_clob cascade constraints purge; drop sequence ebasic_json_map_clob_seq; +drop table ebasic_json_map_detail cascade constraints purge; +drop sequence ebasic_json_map_detail_seq; + drop table ebasic_json_map_json_b cascade constraints purge; drop sequence ebasic_json_map_json_b_seq; @@ -493,9 +828,21 @@ drop sequence ebasic_json_node_json_b_seq; drop table ebasic_json_node_varchar cascade constraints purge; drop sequence ebasic_json_node_varchar_seq; +drop table ebasic_json_unmapped cascade constraints purge; +drop sequence ebasic_json_unmapped_seq; + drop table e_basic_ndc cascade constraints purge; drop sequence e_basic_ndc_seq; +drop table ebasic_no_sdchild cascade constraints purge; +drop sequence ebasic_no_sdchild_seq; + +drop table ebasic_sdchild cascade constraints purge; +drop sequence ebasic_sdchild_seq; + +drop table ebasic_soft_delete cascade constraints purge; +drop sequence ebasic_soft_delete_seq; + drop table e_basicver cascade constraints purge; drop sequence e_basicver_seq; @@ -505,6 +852,11 @@ drop sequence e_basic_withlife_seq; drop table e_basicverucon cascade constraints purge; drop sequence e_basicverucon_seq; +drop table e_col_ab cascade constraints purge; +drop sequence e_col_ab_seq; + +drop table ecustom_id cascade constraints purge; + drop table eemb_inner cascade constraints purge; drop sequence eemb_inner_seq; @@ -538,8 +890,40 @@ drop sequence eopt_one_c_seq; drop table eperson cascade constraints purge; drop sequence eperson_seq; +drop table e_person_online cascade constraints purge; +drop sequence e_person_online_seq; + drop table esimple cascade constraints purge; -drop sequence esimple_seq; + +drop table esoft_del_book cascade constraints purge; +drop sequence esoft_del_book_seq; + +drop table esoft_del_book_esoft_del_user cascade constraints purge; + +drop table esoft_del_down cascade constraints purge; +drop sequence esoft_del_down_seq; + +drop table esoft_del_mid cascade constraints purge; +drop sequence esoft_del_mid_seq; + +drop table esoft_del_role cascade constraints purge; +drop sequence esoft_del_role_seq; + +drop table esoft_del_role_esoft_del_user cascade constraints purge; + +drop table esoft_del_top cascade constraints purge; +drop sequence esoft_del_top_seq; + +drop table esoft_del_up cascade constraints purge; +drop sequence esoft_del_up_seq; + +drop table esoft_del_user cascade constraints purge; +drop sequence esoft_del_user_seq; + +drop table esoft_del_user_esoft_del_role cascade constraints purge; + +drop table esome_convert_type cascade constraints purge; +drop sequence esome_convert_type_seq; drop table esome_type cascade constraints purge; drop sequence esome_type_seq; @@ -547,6 +931,9 @@ drop sequence esome_type_seq; drop table etrans_many cascade constraints purge; drop sequence etrans_many_seq; +drop table rawinherit_uncle cascade constraints purge; +drop sequence rawinherit_uncle_seq; + drop table evanilla_collection cascade constraints purge; drop sequence evanilla_collection_seq; @@ -565,6 +952,9 @@ drop sequence td_child_seq; drop table td_parent cascade constraints purge; drop sequence td_parent_seq; +drop table empl cascade constraints purge; +drop sequence empl_seq; + drop table feature_desc cascade constraints purge; drop sequence feature_desc_seq; @@ -575,17 +965,38 @@ drop table foo cascade constraints purge; drop sequence foo_seq; drop table gen_key_identity cascade constraints purge; -drop sequence gen_key_identity_seq; drop table gen_key_sequence cascade constraints purge; -drop sequence seq; +drop sequence SEQ; drop table gen_key_table cascade constraints purge; drop sequence gen_key_table_seq; +drop table grand_parent_person cascade constraints purge; +drop sequence grand_parent_person_seq; + +drop table survey_group cascade constraints purge; +drop sequence survey_group_seq; + drop table c_group cascade constraints purge; drop sequence c_group_seq; +drop table he_doc cascade constraints purge; +drop sequence he_doc_seq; + +drop table hx_link cascade constraints purge; +drop sequence hx_link_seq; + +drop table hx_link_doc cascade constraints purge; + +drop table hi_doc cascade constraints purge; +drop sequence hi_doc_seq; + +drop table hi_link cascade constraints purge; +drop sequence hi_link_seq; + +drop table hi_link_doc cascade constraints purge; + drop table imrelated cascade constraints purge; drop sequence imrelated_seq; @@ -611,6 +1022,25 @@ drop sequence drel_invoice_seq; drop table item cascade constraints purge; +drop table monkey cascade constraints purge; +drop sequence monkey_seq; + +drop table trainer cascade constraints purge; +drop sequence trainer_seq; + +drop table trainer_monkey cascade constraints purge; + +drop table troop cascade constraints purge; +drop sequence troop_seq; + +drop table troop_monkey cascade constraints purge; + +drop table l2_cldf_reset_bean cascade constraints purge; +drop sequence l2_cldf_reset_bean_seq; + +drop table l2_cldf_reset_bean_child cascade constraints purge; +drop sequence l2_cldf_reset_bean_child_seq; + drop table level1 cascade constraints purge; drop sequence level1_seq; @@ -629,6 +1059,12 @@ drop sequence level3_seq; drop table level4 cascade constraints purge; drop sequence level4_seq; +drop table link cascade constraints purge; +drop sequence link_seq; + +drop table link_draft cascade constraints purge; +drop sequence link_draft_seq; + drop table la_attr_value cascade constraints purge; drop sequence la_attr_value_seq; @@ -666,6 +1102,16 @@ drop sequence muser_seq; drop table muser_type cascade constraints purge; drop sequence muser_type_seq; +drop table mail_box cascade constraints purge; +drop sequence mail_box_seq; + +drop table mail_user cascade constraints purge; +drop sequence mail_user_seq; + +drop table mail_user_inbox cascade constraints purge; + +drop table mail_user_outbox cascade constraints purge; + drop table map_super_actual cascade constraints purge; drop sequence map_super_actual_seq; @@ -680,12 +1126,38 @@ drop sequence mnoc_user_seq; drop table mnoc_user_mnoc_role cascade constraints purge; +drop table mny_a cascade constraints purge; +drop sequence mny_a_seq; + +drop table mny_b cascade constraints purge; +drop sequence mny_b_seq; + +drop table mny_b_mny_c cascade constraints purge; + +drop table mny_c cascade constraints purge; +drop sequence mny_c_seq; + +drop table mny_topic cascade constraints purge; +drop sequence mny_topic_seq; + +drop table subtopics cascade constraints purge; + drop table mp_role cascade constraints purge; drop sequence mp_role_seq; drop table mp_user cascade constraints purge; drop sequence mp_user_seq; +drop table ms_many_a cascade constraints purge; +drop sequence ms_many_a_seq; + +drop table ms_many_a_many_b cascade constraints purge; + +drop table ms_many_b cascade constraints purge; +drop sequence ms_many_b_seq; + +drop table ms_many_b_many_a cascade constraints purge; + drop table my_lob_size cascade constraints purge; drop sequence my_lob_size_seq; @@ -702,13 +1174,31 @@ drop table o_cached_bean_country cascade constraints purge; drop table o_cached_bean_child cascade constraints purge; drop sequence o_cached_bean_child_seq; +drop table o_cached_natkey cascade constraints purge; +drop sequence o_cached_natkey_seq; + +drop table o_cached_natkey3 cascade constraints purge; +drop sequence o_cached_natkey3_seq; + drop table ocar cascade constraints purge; drop sequence ocar_seq; +drop table ocompany cascade constraints purge; +drop sequence ocompany_seq; + drop table oengine cascade constraints purge; drop table ogear_box cascade constraints purge; +drop table oroad_show_msg cascade constraints purge; +drop sequence oroad_show_msg_seq; + +drop table om_ordered_detail cascade constraints purge; +drop sequence om_ordered_detail_seq; + +drop table om_ordered_master cascade constraints purge; +drop sequence om_ordered_master_seq; + drop table o_order cascade constraints purge; drop sequence o_order_seq; @@ -722,12 +1212,49 @@ drop table s_order_items cascade constraints purge; drop table or_order_ship cascade constraints purge; drop sequence or_order_ship_seq; +drop table organisation cascade constraints purge; +drop sequence organisation_seq; + +drop table oto_bchild cascade constraints purge; +drop sequence oto_bchild_seq; + +drop table oto_bmaster cascade constraints purge; +drop sequence oto_bmaster_seq; + drop table oto_child cascade constraints purge; drop sequence oto_child_seq; +drop table oto_cust cascade constraints purge; +drop sequence oto_cust_seq; + +drop table oto_cust_address cascade constraints purge; +drop sequence oto_cust_address_seq; + drop table oto_master cascade constraints purge; drop sequence oto_master_seq; +drop table oto_prime cascade constraints purge; +drop sequence oto_prime_seq; + +drop table oto_prime_extra cascade constraints purge; + +drop table oto_th_many cascade constraints purge; +drop sequence oto_th_many_seq; + +drop table oto_th_one cascade constraints purge; +drop sequence oto_th_one_seq; + +drop table oto_th_top cascade constraints purge; +drop sequence oto_th_top_seq; + +drop table oto_ubprime cascade constraints purge; + +drop table oto_ubprime_extra cascade constraints purge; + +drop table oto_uprime cascade constraints purge; + +drop table oto_uprime_extra cascade constraints purge; + drop table pfile cascade constraints purge; drop sequence pfile_seq; @@ -750,6 +1277,9 @@ drop sequence rawinherit_parent_seq; drop table rawinherit_parent_rawinherit_d cascade constraints purge; +drop table parent_person cascade constraints purge; +drop sequence parent_person_seq; + drop table c_participation cascade constraints purge; drop sequence c_participation_seq; @@ -762,13 +1292,15 @@ drop table persistent_file_content cascade constraints purge; drop sequence persistent_file_content_seq; drop table persons cascade constraints purge; -drop sequence persons_seq; +drop sequence PERSONS_seq; drop table person cascade constraints purge; drop sequence person_seq; drop table phones cascade constraints purge; -drop sequence phones_seq; +drop sequence PHONES_seq; + +drop table primary_revision cascade constraints purge; drop table o_product cascade constraints purge; drop sequence o_product_seq; @@ -777,6 +1309,9 @@ drop table pp cascade constraints purge; drop table pp_to_ww cascade constraints purge; +drop table question cascade constraints purge; +drop sequence question_seq; + drop table rcustomer cascade constraints purge; drop table r_orders cascade constraints purge; @@ -785,13 +1320,13 @@ drop table region cascade constraints purge; drop table resourcefile cascade constraints purge; +drop table em_role cascade constraints purge; +drop sequence em_role_seq; + drop table mt_role cascade constraints purge; drop table mt_role_permission cascade constraints purge; -drop table em_role cascade constraints purge; -drop sequence em_role_seq; - drop table f_second cascade constraints purge; drop sequence f_second_seq; @@ -828,11 +1363,23 @@ drop sequence sub_section_seq; drop table sub_type cascade constraints purge; drop sequence sub_type_seq; +drop table survey cascade constraints purge; +drop sequence survey_seq; + drop table tbytes_only cascade constraints purge; drop sequence tbytes_only_seq; drop table tcar cascade constraints purge; +drop table tevent cascade constraints purge; +drop sequence tevent_seq; + +drop table tevent_many cascade constraints purge; +drop sequence tevent_many_seq; + +drop table tevent_one cascade constraints purge; +drop sequence tevent_one_seq; + drop table tint_root cascade constraints purge; drop sequence tint_root_seq; @@ -867,12 +1414,14 @@ drop sequence twith_pre_insert_seq; drop table mt_tenant cascade constraints purge; -drop table sa_tire cascade constraints purge; -drop sequence sa_tire_seq; +drop table test_annotation_base_entity cascade constraints purge; drop table tire cascade constraints purge; drop sequence tire_seq; +drop table sa_tire cascade constraints purge; +drop sequence sa_tire_seq; + drop table trip cascade constraints purge; drop sequence trip_seq; @@ -881,6 +1430,9 @@ drop sequence truck_ref_seq; drop table type cascade constraints purge; +drop table tz_bean cascade constraints purge; +drop sequence tz_bean_seq; + drop table ut_detail cascade constraints purge; drop sequence ut_detail_seq; @@ -891,14 +1443,17 @@ drop table uuone cascade constraints purge; drop table uutwo cascade constraints purge; -drop table em_user cascade constraints purge; -drop sequence em_user_seq; +drop table c_user cascade constraints purge; +drop sequence c_user_seq; drop table tx_user cascade constraints purge; drop sequence tx_user_seq; -drop table c_user cascade constraints purge; -drop sequence c_user_seq; +drop table g_user cascade constraints purge; +drop sequence g_user_seq; + +drop table em_user cascade constraints purge; +drop sequence em_user_seq; drop table oto_user cascade constraints purge; drop sequence oto_user_seq; @@ -919,11 +1474,14 @@ drop table warehousesshippingzones cascade constraints purge; drop table sa_wheel cascade constraints purge; drop sequence sa_wheel_seq; +drop table wheel cascade constraints purge; +drop sequence wheel_seq; + drop table sp_car_wheel cascade constraints purge; drop sequence sp_car_wheel_seq; -drop table wheel cascade constraints purge; -drop sequence wheel_seq; +drop table g_who_props_otm cascade constraints purge; +drop sequence g_who_props_otm_seq; drop table with_zero cascade constraints purge; drop sequence with_zero_seq; @@ -936,3 +1494,5 @@ drop table wview cascade constraints purge; drop table zones cascade constraints purge; drop sequence zones_seq; +drop index ix_cntct_lst_nm_frst_nm; +drop index ix_e_basic_name; diff --git a/src/test/ddl-review/pg-create-all.sql b/src/test/ddl-review/pg-create-all.sql index 4956fd1bb..d9f99e631 100644 --- a/src/test/ddl-review/pg-create-all.sql +++ b/src/test/ddl-review/pg-create-all.sql @@ -1,3 +1,4 @@ +-- Generated by ebean unknown at 2018-03-08T06:39:45.063Z create table asimple_bean ( id bigserial not null, name varchar(255), @@ -16,20 +17,20 @@ create table oto_account ( id bigserial not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, constraint pk_oto_account primary key (id) ); -create table o_address ( - id smallserial not null, - line_1 varchar(100), - line_2 varchar(100), - city varchar(100), - cretime timestamp, - country_code varchar(2), - updtime timestamp not null, - constraint pk_o_address primary key (id) +create table addr ( + id bigserial not null, + employee_id bigint, + name varchar(255), + address_line1 varchar(255), + address_line2 varchar(255), + city varchar(255), + version bigint not null, + constraint pk_addr primary key (id) ); create table address ( @@ -39,15 +40,38 @@ create table address ( constraint pk_address primary key (oid) ); -create table animals ( - species varchar(31) not null, +create table o_address ( + id smallserial not null, + line_1 varchar(100), + line_2 varchar(100), + city varchar(100), + cretime timestamptz, + country_code varchar(2), + updtime timestamptz not null, + constraint pk_o_address primary key (id) +); + +create table album ( + id bigserial not null, + name varchar(255), + cover_id bigint, + deleted boolean default false not null, + created_at timestamptz not null, + last_update timestamptz not null, + constraint uq_album_cover_id unique (cover_id), + constraint pk_album primary key (id) +); + +create table animal ( + species varchar(255) not null, id bigserial not null, shelter_id bigint, version bigint not null, name varchar(255), registration_number varchar(255), date_of_birth date, - constraint pk_animals primary key (id) + dog_size varchar(255), + constraint pk_animal primary key (id) ); create table animal_shelter ( @@ -61,8 +85,8 @@ create table article ( id serial not null, name varchar(255), author varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_article primary key (id) ); @@ -71,16 +95,16 @@ create table attribute ( option_type integer not null, id serial not null, attribute_holder_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_attribute primary key (id) ); create table attribute_holder ( id serial not null, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_attribute_holder primary key (id) ); @@ -114,10 +138,46 @@ create table bsimple_with_gen ( constraint pk_bsimple_with_gen primary key (id) ); +create table bsite ( + id uuid not null, + name varchar(255), + constraint pk_bsite primary key (id) +); + +create table bsite_user ( + site_id uuid not null, + user_id uuid not null, + access_level integer, + constraint ck_bsite_user_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user primary key (site_id,user_id) +); + +create table bsite_user_b ( + site uuid not null, + usr uuid not null, + access_level integer, + constraint ck_bsite_user_b_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_b primary key (site,usr) +); + +create table bsite_user_c ( + site_uid uuid not null, + user_uid uuid not null, + access_level integer, + constraint ck_bsite_user_c_access_level check ( access_level in (0,1,2)), + constraint pk_bsite_user_c primary key (site_uid,user_uid) +); + +create table buser ( + id uuid not null, + name varchar(255), + constraint pk_buser primary key (id) +); + create table bwith_qident ( id serial not null, - "Name" varchar(255), - last_updated timestamp not null, + "Name" varchar(191), + last_updated timestamptz not null, constraint uq_bwith_qident_name unique ("Name"), constraint pk_bwith_qident primary key (id) ); @@ -125,9 +185,10 @@ create table bwith_qident ( create table basic_joda_entity ( id bigserial not null, name varchar(255), - created timestamp not null, - updated timestamp not null, - version timestamp not null, + period varchar(50), + created timestamptz not null, + updated timestamptz not null, + version timestamptz not null, constraint pk_basic_joda_entity primary key (id) ); @@ -140,15 +201,30 @@ create table bean_with_time_zone ( create table drel_booking ( id bigint not null, + booking_uid bigint, agent_invoice bigint, client_invoice bigint, version integer not null, + constraint uq_drel_booking_booking_uid unique (booking_uid), constraint uq_drel_booking_agent_invoice unique (agent_invoice), constraint uq_drel_booking_client_invoice unique (client_invoice), constraint pk_drel_booking primary key (id) ); create sequence drel_booking_seq; +create table cinh_root ( + dtype varchar(3) not null, + id serial not null, + license_number varchar(255), + cretime timestamptz not null, + updtime timestamptz not null, + version bigint not null, + driver varchar(255), + notes varchar(255), + action varchar(255), + constraint pk_cinh_root primary key (id) +); + create table ckey_assoc ( id serial not null, assoc_one varchar(255), @@ -174,7 +250,7 @@ create table ckey_parent ( create table calculation_result ( id serial not null, - charge float, + charge float not null, product_configuration_id integer, group_configuration_id integer, constraint pk_calculation_result primary key (id) @@ -211,15 +287,41 @@ create table sp_car_car_wheels ( create table car_accessory ( id serial not null, name varchar(255), + fuse_id bigint not null, car_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_car_accessory primary key (id) ); +create table car_fuse ( + id bigserial not null, + location_code varchar(255), + constraint pk_car_fuse primary key (id) +); + +create table category ( + id bigserial not null, + name varchar(255), + surveyobjectid bigint, + sequence_number integer not null, + constraint pk_category primary key (id) +); + +create table child_person ( + identifier serial not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_child_person primary key (identifier) +); + create table configuration ( - type varchar(31) not null, + type varchar(21) not null, id serial not null, name varchar(255), configurations_id integer, @@ -236,23 +338,23 @@ create table configurations ( create table contact ( id serial not null, - first_name varchar(255), - last_name varchar(255), + first_name varchar(127), + last_name varchar(127), phone varchar(255), mobile varchar(255), email varchar(255), customer_id integer not null, group_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, constraint pk_contact primary key (id) ); create table contact_group ( id serial not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_contact_group primary key (id) ); @@ -262,8 +364,8 @@ create table contact_note ( contact_id integer, title varchar(255), note text, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_contact_note primary key (id) ); @@ -271,11 +373,11 @@ create table contact_note ( create table c_conversation ( id bigserial not null, title varchar(255), - isopen boolean, + isopen boolean default false not null, group_id bigint, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, constraint pk_c_conversation primary key (id) ); @@ -285,6 +387,13 @@ create table o_country ( constraint pk_o_country primary key (code) ); +create table cover ( + id bigserial not null, + s3url varchar(255), + deleted boolean default false not null, + constraint pk_cover primary key (id) +); + create table o_customer ( id serial not null, status varchar(1), @@ -293,19 +402,34 @@ create table o_customer ( anniversary date, billing_address_id smallint, shipping_address_id smallint, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, - constraint ck_o_customer_status check (status in ('N','A','I')), + constraint ck_o_customer_status check ( status in ('N','A','I')), constraint pk_o_customer primary key (id) ); +comment on table o_customer is 'Holds external customers'; +comment on column o_customer.status is 'status of the customer'; +comment on column o_customer.smallnote is 'Short notes regarding the customer'; +comment on column o_customer.anniversary is 'Join date of the customer'; + +create table dcredit ( + id bigserial not null, + credit varchar(255), + constraint pk_dcredit primary key (id) +); + +create table dcredit_drol ( + dcredit_id bigint not null, + drol_id bigint not null, + constraint pk_dcredit_drol primary key (dcredit_id,drol_id) +); create table dexh_entity ( oid bigserial not null, - exhange_rate decimal(38), - exhange_cmoney_amount decimal(38), - exhange_cmoney_currency varchar(3), - last_updated timestamp not null, + exhange varchar(255), + an_enum_type varchar(255), + last_updated timestamptz not null, constraint pk_dexh_entity primary key (oid) ); @@ -314,35 +438,203 @@ create table dperson ( first_name varchar(255), last_name varchar(255), salary decimal(38), - a_amt decimal(38), - a_curr varchar(3), - i_start timestamp, - i_end timestamp, constraint pk_dperson primary key (id) ); +create table drol ( + id bigserial not null, + name varchar(255), + constraint pk_drol primary key (id) +); + +create table drot ( + id bigserial not null, + name varchar(255), + constraint pk_drot primary key (id) +); + +create table drot_drol ( + drot_id bigint not null, + drol_id bigint not null, + constraint pk_drot_drol primary key (drot_id,drol_id) +); + create table rawinherit_data ( id bigserial not null, val integer, constraint pk_rawinherit_data primary key (id) ); +create table dfk_cascade ( + id bigserial not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_cascade primary key (id) +); + +create table dfk_cascade_one ( + id bigserial not null, + name varchar(255), + constraint pk_dfk_cascade_one primary key (id) +); + +create table dfk_none ( + id bigserial not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none primary key (id) +); + +create table dfk_none_via_join ( + id bigserial not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_none_via_join primary key (id) +); + +create table dfk_one ( + id bigserial not null, + name varchar(255), + constraint pk_dfk_one primary key (id) +); + +create table dfk_set_null ( + id bigserial not null, + name varchar(255), + one_id bigint, + constraint pk_dfk_set_null primary key (id) +); + +create table doc ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_doc primary key (id) +); + +create table doc_link ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link primary key (doc_id,link_id) +); + +create table doc_link_draft ( + doc_id bigint not null, + link_id bigint not null, + constraint pk_doc_link_draft primary key (doc_id,link_id) +); + +create table doc_draft ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_doc_draft primary key (id) +); + +create table document ( + id bigserial not null, + title varchar(127), + body varchar(255), + organisation_id bigint, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint uq_document_title unique (title), + constraint pk_document primary key (id) +); + +create table document_draft ( + id bigserial not null, + title varchar(127), + body varchar(255), + when_publish timestamptz, + organisation_id bigint, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint uq_document_draft_title unique (title), + constraint pk_document_draft primary key (id) +); + +create table document_media ( + id bigserial not null, + document_id bigint, + name varchar(255), + description varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_document_media primary key (id) +); + +create table document_media_draft ( + id bigserial not null, + document_id bigint, + name varchar(255), + description varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_document_media_draft primary key (id) +); + +create table earray_bean ( + id bigserial not null, + name varchar(255), + phone_numbers varchar[], + uids uuid[], + other_ids bigint[], + doubs float[], + statuses varchar[], + status2 varchar[], + version bigint not null, + constraint pk_earray_bean primary key (id) +); + +create table earray_set_bean ( + id bigserial not null, + name varchar(255), + phone_numbers varchar[], + uids uuid[], + other_ids bigint[], + doubs float[], + version bigint not null, + constraint pk_earray_set_bean primary key (id) +); + create table e_basic ( id serial not null, status varchar(1), - name varchar(255), + name varchar(127), description varchar(255), - some_date timestamp, - constraint ck_e_basic_status check (status in ('N','A','I')), + some_date timestamptz, + constraint ck_e_basic_status check ( status in ('N','A','I')), constraint pk_e_basic primary key (id) ); +create table ebasic_change_log ( + id bigserial not null, + name varchar(20), + short_description varchar(50), + long_description varchar(100), + who_created varchar(255) not null, + who_modified varchar(255) not null, + when_created timestamptz not null, + when_modified timestamptz not null, + version bigint not null, + constraint pk_ebasic_change_log primary key (id) +); + create table ebasic_clob ( id bigserial not null, name varchar(255), title varchar(255), description text, - last_update timestamp not null, + last_update timestamptz not null, constraint pk_ebasic_clob primary key (id) ); @@ -351,7 +643,7 @@ create table ebasic_clob_fetch_eager ( name varchar(255), title varchar(255), description text, - last_update timestamp not null, + last_update timestamptz not null, constraint pk_ebasic_clob_fetch_eager primary key (id) ); @@ -367,7 +659,8 @@ create table e_basicenc ( name varchar(255), description bytea, dob bytea, - last_update timestamp, + status bytea, + last_update timestamptz, constraint pk_e_basicenc primary key (id) ); @@ -377,7 +670,7 @@ create table e_basicenc_bin ( description varchar(255), data bytea, some_time bytea, - last_update timestamp not null, + last_update timestamptz not null, constraint pk_e_basicenc_bin primary key (id) ); @@ -385,10 +678,41 @@ create table e_basic_enum_id ( status varchar(1) not null, name varchar(255), description varchar(255), - constraint ck_e_basic_enum_id_status check (status in ('N','A','I')), + constraint ck_e_basic_enum_id_status check ( status in ('N','A','I')), constraint pk_e_basic_enum_id primary key (status) ); +create table e_basic_eni ( + id serial not null, + status integer, + name varchar(255), + description varchar(255), + some_date timestamptz, + constraint ck_e_basic_eni_status check ( status in (1,2,3)), + constraint pk_e_basic_eni primary key (id) +); + +create table ebasic_hstore ( + id bigserial not null, + name varchar(255), + map hstore, + version bigint not null, + constraint pk_ebasic_hstore primary key (id) +); + +create table ebasic_json_list ( + id bigserial not null, + name varchar(255), + bean_set json, + bean_list jsonb, + bean_map json, + plain_bean json, + flags json, + tags varchar(100), + version bigint not null, + constraint pk_ebasic_json_list primary key (id) +); + create table ebasic_json_map ( id bigserial not null, name varchar(255), @@ -413,6 +737,15 @@ create table ebasic_json_map_clob ( constraint pk_ebasic_json_map_clob primary key (id) ); +create table ebasic_json_map_detail ( + id bigserial not null, + owner_id bigint, + name varchar(255), + content json, + version bigint not null, + constraint pk_ebasic_json_map_detail primary key (id) +); + create table ebasic_json_map_json_b ( id bigserial not null, name varchar(255), @@ -461,39 +794,89 @@ create table ebasic_json_node_varchar ( constraint pk_ebasic_json_node_varchar primary key (id) ); +create table ebasic_json_unmapped ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_ebasic_json_unmapped primary key (id) +); + create table e_basic_ndc ( id serial not null, name varchar(255), constraint pk_e_basic_ndc primary key (id) ); +create table ebasic_no_sdchild ( + id bigserial not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + constraint pk_ebasic_no_sdchild primary key (id) +); + +create table ebasic_sdchild ( + id bigserial not null, + owner_id bigint not null, + child_name varchar(255), + amount bigint not null, + version bigint not null, + deleted boolean default false not null, + constraint pk_ebasic_sdchild primary key (id) +); + +create table ebasic_soft_delete ( + id bigserial not null, + name varchar(255), + description varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_ebasic_soft_delete primary key (id) +); + create table e_basicver ( id serial not null, name varchar(255), description varchar(255), other varchar(255), - last_update timestamp not null, + last_update timestamptz not null, constraint pk_e_basicver primary key (id) ); create table e_basic_withlife ( id bigserial not null, name varchar(255), + deleted boolean default false not null, version bigint not null, constraint pk_e_basic_withlife primary key (id) ); create table e_basicverucon ( id serial not null, - name varchar(255), - other varchar(255), - other_one varchar(255), + name varchar(127), + other varchar(127), + other_one varchar(127), description varchar(255), - last_update timestamp not null, + last_update timestamptz not null, constraint uq_e_basicverucon_name unique (name), + constraint uq_e_basicverucon_other_other_one unique (other,other_one), constraint pk_e_basicverucon primary key (id) ); +create table e_col_ab ( + id bigserial not null, + column_a varchar(255), + column_b varchar(255), + constraint pk_e_col_ab primary key (id) +); + +create table ecustom_id ( + id varchar(127) not null, + name varchar(255), + constraint pk_ecustom_id primary key (id) +); + create table eemb_inner ( id serial not null, nome_inner varchar(255), @@ -505,8 +888,8 @@ create table eemb_inner ( create table eemb_outer ( id serial not null, nome_outer varchar(255), - date1 timestamp, - date2 timestamp, + date1 timestamptz, + date2 timestamptz, update_count integer not null, constraint pk_eemb_outer primary key (id) ); @@ -515,16 +898,18 @@ create table egen_props ( id bigserial not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - ts_created timestamp not null, - ts_updated timestamp not null, - ldt_created timestamp not null, - ldt_updated timestamp not null, - odt_created timestamp not null, - odt_updated timestamp not null, - zdt_created timestamp not null, - zdt_updated timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, + ts_created timestamptz not null, + ts_updated timestamptz not null, + ldt_created timestamptz not null, + ldt_updated timestamptz not null, + odt_created timestamptz not null, + odt_updated timestamptz not null, + zdt_created timestamptz not null, + zdt_updated timestamptz not null, + instant_created timestamptz not null, + instant_updated timestamptz not null, long_created bigint not null, long_updated bigint not null, constraint pk_egen_props primary key (id) @@ -532,17 +917,21 @@ create table egen_props ( create table einvoice ( id bigserial not null, - invoice_date timestamp, + invoice_date timestamptz, state integer, person_id bigint, ship_street varchar(255), ship_suburb varchar(255), ship_city varchar(255), - street varchar(255), - suburb varchar(255), - city varchar(255), + ship_status varchar(3), + bill_street varchar(255), + bill_suburb varchar(255), + bill_city varchar(255), + bill_status varchar(3), version bigint not null, - constraint ck_einvoice_state check (state in (0,1,2)), + constraint ck_einvoice_state check ( state in (0,1,2)), + constraint ck_einvoice_ship_status check ( ship_status in ('ONE','TWO')), + constraint ck_einvoice_bill_status check ( bill_status in ('ONE','TWO')), constraint pk_einvoice primary key (id) ); @@ -571,8 +960,8 @@ create table eopt_one_a ( id serial not null, name_for_a varchar(255), b_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_eopt_one_a primary key (id) ); @@ -581,8 +970,8 @@ create table eopt_one_b ( id serial not null, name_for_b varchar(255), c_id integer not null, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_eopt_one_b primary key (id) ); @@ -590,8 +979,8 @@ create table eopt_one_b ( create table eopt_one_c ( id serial not null, name_for_c varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_eopt_one_c primary key (id) ); @@ -602,17 +991,130 @@ create table eperson ( notes varchar(255), street varchar(255), suburb varchar(255), - city varchar(255), + addr_city varchar(255), + addr_status varchar(3), version bigint not null, + constraint ck_eperson_addr_status check ( addr_status in ('ONE','TWO')), constraint pk_eperson primary key (id) ); +create table e_person_online ( + id bigserial not null, + email varchar(127), + online_status boolean default false not null, + when_updated timestamptz not null, + constraint uq_e_person_online_email unique (email), + constraint pk_e_person_online primary key (id) +); + create table esimple ( usertypeid serial not null, name varchar(255), constraint pk_esimple primary key (usertypeid) ); +create table esoft_del_book ( + id bigserial not null, + book_title varchar(255), + lend_by_id bigint, + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_book primary key (id) +); + +create table esoft_del_book_esoft_del_user ( + esoft_del_book_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_book_esoft_del_user primary key (esoft_del_book_id,esoft_del_user_id) +); + +create table esoft_del_down ( + id bigserial not null, + esoft_del_mid_id bigint not null, + down varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_down primary key (id) +); + +create table esoft_del_mid ( + id bigserial not null, + top_id bigint, + mid varchar(255), + up_id bigint, + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_mid primary key (id) +); + +create table esoft_del_one_a ( + id bigserial not null, + name varchar(255), + oneb_id bigint, + deleted boolean default false not null, + version bigint not null, + constraint uq_esoft_del_one_a_oneb_id unique (oneb_id), + constraint pk_esoft_del_one_a primary key (id) +); + +create table esoft_del_one_b ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_esoft_del_one_b primary key (id) +); + +create table esoft_del_role ( + id bigserial not null, + role_name varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_role primary key (id) +); + +create table esoft_del_role_esoft_del_user ( + esoft_del_role_id bigint not null, + esoft_del_user_id bigint not null, + constraint pk_esoft_del_role_esoft_del_user primary key (esoft_del_role_id,esoft_del_user_id) +); + +create table esoft_del_top ( + id bigserial not null, + name varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_top primary key (id) +); + +create table esoft_del_up ( + id bigserial not null, + up varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_up primary key (id) +); + +create table esoft_del_user ( + id bigserial not null, + user_name varchar(255), + version bigint not null, + deleted boolean default false not null, + constraint pk_esoft_del_user primary key (id) +); + +create table esoft_del_user_esoft_del_role ( + esoft_del_user_id bigint not null, + esoft_del_role_id bigint not null, + constraint pk_esoft_del_user_esoft_del_role primary key (esoft_del_user_id,esoft_del_role_id) +); + +create table esome_convert_type ( + id bigserial not null, + name varchar(255), + money decimal(38), + constraint pk_esome_convert_type primary key (id) +); + create table esome_type ( id serial not null, currency varchar(3), @@ -627,6 +1129,14 @@ create table etrans_many ( constraint pk_etrans_many primary key (id) ); +create table rawinherit_uncle ( + id serial not null, + name varchar(255), + parent_id bigint not null, + version bigint not null, + constraint pk_rawinherit_uncle primary key (id) +); + create table evanilla_collection ( id serial not null, name varchar(255), @@ -643,11 +1153,11 @@ create table evanilla_collection_detail ( create table ewho_props ( id bigserial not null, name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, who_created varchar(255) not null, who_modified varchar(255) not null, - version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, constraint pk_ewho_props primary key (id) ); @@ -674,6 +1184,14 @@ create table td_parent ( constraint pk_td_parent primary key (parent_id) ); +create table empl ( + id bigserial not null, + name varchar(255), + age integer, + default_address_id bigint, + constraint pk_empl primary key (id) +); + create table feature_desc ( id serial not null, name varchar(255), @@ -705,7 +1223,7 @@ create table gen_key_sequence ( description varchar(255), constraint pk_gen_key_sequence primary key (id) ); -create sequence seq; +create sequence SEQ; create table gen_key_table ( id bigserial not null, @@ -713,16 +1231,86 @@ create table gen_key_table ( constraint pk_gen_key_table primary key (id) ); +create table grand_parent_person ( + identifier serial not null, + name varchar(255), + age integer, + some_bean_id integer, + family_name varchar(255), + address varchar(255), + constraint pk_grand_parent_person primary key (identifier) +); + +create table survey_group ( + id bigserial not null, + name varchar(255), + categoryobjectid bigint, + sequence_number integer not null, + constraint pk_survey_group primary key (id) +); + create table c_group ( id bigserial not null, - inactive boolean, + inactive boolean default false not null, name varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, constraint pk_c_group primary key (id) ); +create table he_doc ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_he_doc primary key (id) +); + +create table hx_link ( + id bigserial not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_hx_link primary key (id) +); + +create table hx_link_doc ( + hx_link_id bigint not null, + he_doc_id bigint not null, + constraint pk_hx_link_doc primary key (hx_link_id,he_doc_id) +); + +create table hi_doc ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_hi_doc primary key (id) +); + +create table hi_link ( + id bigserial not null, + name varchar(255), + location varchar(255), + comments varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_hi_link primary key (id) +); + +create table hi_link_doc ( + hi_link_id bigint not null, + hi_doc_id bigint not null, + constraint pk_hi_link_doc primary key (hi_link_id,hi_doc_id) +); + create table imrelated ( id bigserial not null, name varchar(255), @@ -731,17 +1319,17 @@ create table imrelated ( ); create table imroot ( - dtype varchar(10) not null, + dtype varchar(31) not null, id bigserial not null, - title varchar(255), - when_title timestamp, name varchar(255), + title varchar(255), + when_title timestamptz, constraint pk_imroot primary key (id) ); create table ixresource ( dtype varchar(255), - id bytea not null, + id uuid not null, name varchar(255), constraint pk_ixresource primary key (id) ); @@ -788,19 +1376,67 @@ create sequence drel_invoice_seq; create table item ( customer integer not null, - itemnumber varchar(255) not null, + itemnumber varchar(127) not null, description varchar(255), units varchar(255), - type integer, - region integer, - date_modified timestamp, - date_created timestamp, + type integer not null, + region integer not null, + date_modified timestamptz, + date_created timestamptz, modified_by varchar(255), created_by varchar(255), version bigint not null, constraint pk_item primary key (customer,itemnumber) ); +create table monkey ( + mid bigserial not null, + name varchar(255), + food_preference varchar(255), + version bigint not null, + constraint pk_monkey primary key (mid) +); + +create table trainer ( + tid bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_trainer primary key (tid) +); + +create table trainer_monkey ( + trainer_tid bigint not null, + monkey_mid bigint not null, + constraint uq_trainer_monkey_mid unique (monkey_mid), + constraint pk_trainer_monkey primary key (trainer_tid,monkey_mid) +); + +create table troop ( + pid bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_troop primary key (pid) +); + +create table troop_monkey ( + troop_pid bigint not null, + monkey_mid bigint not null, + constraint uq_troop_monkey_mid unique (monkey_mid), + constraint pk_troop_monkey primary key (troop_pid,monkey_mid) +); + +create table l2_cldf_reset_bean ( + id bigserial not null, + name varchar(255), + constraint pk_l2_cldf_reset_bean primary key (id) +); + +create table l2_cldf_reset_bean_child ( + id bigserial not null, + parent_id bigint, + constraint pk_l2_cldf_reset_bean_child primary key (id) +); + create table level1 ( id bigserial not null, name varchar(255), @@ -843,11 +1479,38 @@ create table level4 ( constraint pk_level4 primary key (id) ); +create table link ( + id bigserial not null, + name varchar(255), + location varchar(255), + when_publish timestamptz, + link_comment varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + deleted boolean default false not null, + constraint pk_link primary key (id) +); + +create table link_draft ( + id bigserial not null, + name varchar(255), + location varchar(255), + when_publish timestamptz, + link_comment varchar(255), + dirty boolean default false not null, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + deleted boolean default false not null, + constraint pk_link_draft primary key (id) +); + create table la_attr_value ( id serial not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_la_attr_value primary key (id) ); @@ -871,7 +1534,7 @@ create table non_updateprop ( non_enum varchar(5), name varchar(255), note varchar(255), - constraint ck_non_updateprop_non_enum check (non_enum in ('BEGIN','END')), + constraint ck_non_updateprop_non_enum check ( non_enum in ('BEGIN','END')), constraint pk_non_updateprop primary key (id) ); @@ -886,7 +1549,7 @@ create table mprinter ( last_swap_black_id bigint, version bigint not null, constraint uq_mprinter_last_swap_cyan_id unique (last_swap_cyan_id), - constraint uq_mprinter_last_swap_magenta_2 unique (last_swap_magenta_id), + constraint uq_mprinter_last_swap_magenta_id unique (last_swap_magenta_id), constraint uq_mprinter_last_swap_yellow_id unique (last_swap_yellow_id), constraint uq_mprinter_last_swap_black_id unique (last_swap_black_id), constraint pk_mprinter primary key (id) @@ -894,7 +1557,7 @@ create table mprinter ( create table mprinter_state ( id bigserial not null, - flags bigint, + flags bigint not null, printer_id bigint, version bigint not null, constraint pk_mprinter_state primary key (id) @@ -944,11 +1607,37 @@ create table muser_type ( constraint pk_muser_type primary key (id) ); +create table mail_box ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_mail_box primary key (id) +); + +create table mail_user ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_mail_user primary key (id) +); + +create table mail_user_inbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_inbox primary key (mail_user_id,mail_box_id) +); + +create table mail_user_outbox ( + mail_user_id bigint not null, + mail_box_id bigint not null, + constraint pk_mail_user_outbox primary key (mail_user_id,mail_box_id) +); + create table map_super_actual ( id bigserial not null, name varchar(255), - when_created timestamp not null, - when_updated timestamp not null, + when_created timestamptz not null, + when_updated timestamptz not null, constraint pk_map_super_actual primary key (id) ); @@ -959,8 +1648,8 @@ create table c_message ( conversation_id bigint, user_id bigint, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, constraint pk_c_message primary key (id) ); @@ -984,6 +1673,53 @@ create table mnoc_user_mnoc_role ( constraint pk_mnoc_user_mnoc_role primary key (mnoc_user_user_id,mnoc_role_role_id) ); +create table mny_a ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_mny_a primary key (id) +); + +create table mny_b ( + id bigserial not null, + name varchar(255), + a_id bigint, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_mny_b primary key (id) +); + +create table mny_b_mny_c ( + mny_b_id bigint not null, + mny_c_id bigint not null, + constraint pk_mny_b_mny_c primary key (mny_b_id,mny_c_id) +); + +create table mny_c ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_mny_c primary key (id) +); + +create table mny_topic ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_mny_topic primary key (id) +); + +create table subtopics ( + topic bigint not null, + subtopic bigint not null, + constraint pk_subtopics primary key (topic,subtopic) +); + create table mp_role ( id bigserial not null, mp_user_id bigint not null, @@ -998,10 +1734,38 @@ create table mp_user ( constraint pk_mp_user primary key (id) ); +create table ms_many_a ( + aid bigserial not null, + name varchar(255), + ms_many_a_many_b boolean default false not null, + ms_many_b boolean default false not null, + deleted boolean default false not null, + constraint pk_ms_many_a primary key (aid) +); + +create table ms_many_a_many_b ( + ms_many_a_aid bigint not null, + ms_many_b_bid bigint not null, + constraint pk_ms_many_a_many_b primary key (ms_many_a_aid,ms_many_b_bid) +); + +create table ms_many_b ( + bid bigserial not null, + name varchar(255), + deleted boolean default false not null, + constraint pk_ms_many_b primary key (bid) +); + +create table ms_many_b_many_a ( + ms_many_b_bid bigint not null, + ms_many_a_aid bigint not null, + constraint pk_ms_many_b_many_a primary key (ms_many_b_bid,ms_many_a_aid) +); + create table my_lob_size ( id serial not null, name varchar(255), - my_count integer, + my_count integer not null, my_lob text, constraint pk_my_lob_size primary key (id) ); @@ -1017,7 +1781,7 @@ create table my_lob_size_join_many ( create table noidbean ( name varchar(255), subject varchar(255), - when_created timestamp not null + when_created timestamptz not null ); create table o_cached_bean ( @@ -1038,18 +1802,45 @@ create table o_cached_bean_child ( constraint pk_o_cached_bean_child primary key (id) ); +create table o_cached_natkey ( + id bigserial not null, + store varchar(255), + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey primary key (id) +); + +create table o_cached_natkey3 ( + id bigserial not null, + store varchar(255), + code integer not null, + sku varchar(255), + description varchar(255), + constraint pk_o_cached_natkey3 primary key (id) +); + create table ocar ( id serial not null, vin varchar(255), name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_ocar primary key (id) ); +create table ocompany ( + id serial not null, + corp_id varchar(50), + cretime timestamptz not null, + updtime timestamptz not null, + version bigint not null, + constraint uq_ocompany_corp_id unique (corp_id), + constraint pk_ocompany primary key (id) +); + create table oengine ( - engine_id bytea not null, + engine_id uuid not null, short_desc varchar(255), car_id integer, version integer not null, @@ -1058,7 +1849,7 @@ create table oengine ( ); create table ogear_box ( - id bytea not null, + id uuid not null, box_desc varchar(255), box_size integer, car_id integer, @@ -1067,40 +1858,66 @@ create table ogear_box ( constraint pk_ogear_box primary key (id) ); +create table oroad_show_msg ( + id serial not null, + company_id integer not null, + cretime timestamptz not null, + updtime timestamptz not null, + version bigint not null, + constraint uq_oroad_show_msg_company_id unique (company_id), + constraint pk_oroad_show_msg primary key (id) +); + +create table om_ordered_detail ( + id bigserial not null, + name varchar(255), + master_id bigint, + version bigint not null, + sort_order integer, + constraint pk_om_ordered_detail primary key (id) +); + +create table om_ordered_master ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_om_ordered_master primary key (id) +); + create table o_order ( id serial not null, status integer, order_date date, ship_date date, kcustomer_id integer not null, - cretime timestamp not null, - updtime timestamp not null, - constraint ck_o_order_status check (status in (0,1,2,3)), + cretime timestamptz not null, + updtime timestamptz not null, + constraint ck_o_order_status check ( status in (0,1,2,3)), constraint pk_o_order primary key (id) ); create table o_order_detail ( id serial not null, - order_id integer, + order_id integer not null, order_qty integer, ship_qty integer, unit_price float, product_id integer, - cretime timestamp, - updtime timestamp not null, + cretime timestamptz, + updtime timestamptz not null, constraint pk_o_order_detail primary key (id) ); create table s_orders ( - uuid varchar(255) not null, + uuid varchar(40) not null, constraint pk_s_orders primary key (uuid) ); create table s_order_items ( - uuid varchar(255) not null, + uuid varchar(40) not null, product_variant_uuid varchar(255), - order_uuid varchar(255), - quantity integer, + order_uuid varchar(40), + quantity integer not null, amount decimal(38), constraint pk_s_order_items primary key (uuid) ); @@ -1108,13 +1925,34 @@ create table s_order_items ( create table or_order_ship ( id serial not null, order_id integer, - ship_time timestamp, - cretime timestamp not null, - updtime timestamp not null, + ship_time timestamptz, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_or_order_ship primary key (id) ); +create table organisation ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_organisation primary key (id) +); + +create table oto_bchild ( + master_id bigserial not null, + child varchar(255), + constraint pk_oto_bchild primary key (master_id) +); + +create table oto_bmaster ( + id bigserial not null, + name varchar(255), + constraint pk_oto_bmaster primary key (id) +); + create table oto_child ( id serial not null, name varchar(255), @@ -1123,19 +1961,109 @@ create table oto_child ( constraint pk_oto_child primary key (id) ); +create table oto_cust ( + cid bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_oto_cust primary key (cid) +); + +create table oto_cust_address ( + aid bigserial not null, + line1 varchar(255), + line2 varchar(255), + line3 varchar(255), + customer_cid bigint, + version bigint not null, + constraint uq_oto_cust_address_customer_cid unique (customer_cid), + constraint pk_oto_cust_address primary key (aid) +); + create table oto_master ( id bigserial not null, name varchar(255), constraint pk_oto_master primary key (id) ); +create table oto_prime ( + pid bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_oto_prime primary key (pid) +); + +create table oto_prime_extra ( + eid bigint not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_prime_extra primary key (eid) +); + +create table oto_th_many ( + id bigserial not null, + oto_th_top_id bigint not null, + many varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_oto_th_many primary key (id) +); + +create table oto_th_one ( + id bigserial not null, + one boolean default false not null, + many_id bigint, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint uq_oto_th_one_many_id unique (many_id), + constraint pk_oto_th_one primary key (id) +); + +create table oto_th_top ( + id bigserial not null, + topp varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_oto_th_top primary key (id) +); + +create table oto_ubprime ( + pid uuid not null, + name varchar(255), + version bigint not null, + constraint pk_oto_ubprime primary key (pid) +); + +create table oto_ubprime_extra ( + eid uuid not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_ubprime_extra primary key (eid) +); + +create table oto_uprime ( + pid uuid not null, + name varchar(255), + version bigint not null, + constraint pk_oto_uprime primary key (pid) +); + +create table oto_uprime_extra ( + eid uuid not null, + extra varchar(255), + version bigint not null, + constraint pk_oto_uprime_extra primary key (eid) +); + create table pfile ( id serial not null, name varchar(255), file_content_id integer, file_content2_id integer, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint uq_pfile_file_content_id unique (file_content_id), constraint uq_pfile_file_content2_id unique (file_content2_id), @@ -1145,14 +2073,14 @@ create table pfile ( create table pfile_content ( id serial not null, content bytea, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_pfile_content primary key (id) ); create table paggview ( - pview_id bytea, + pview_id uuid, amount integer not null, constraint uq_paggview_pview_id unique (pview_id) ); @@ -1183,13 +2111,25 @@ create table rawinherit_parent ( type varchar(31) not null, id bigserial not null, val integer, + more varchar(255), constraint pk_rawinherit_parent primary key (id) ); -create table rawinherit_parent_rawinherit_dat ( +create table rawinherit_parent_rawinherit_data ( rawinherit_parent_id bigint not null, rawinherit_data_id bigint not null, - constraint pk_rawinherit_parent_rawinher_0 primary key (rawinherit_parent_id,rawinherit_data_id) + constraint pk_rawinherit_parent_rawinherit_data primary key (rawinherit_parent_id,rawinherit_data_id) +); + +create table parent_person ( + identifier serial not null, + name varchar(255), + age integer, + some_bean_id integer, + parent_identifier integer, + family_name varchar(255), + address varchar(255), + constraint pk_parent_person primary key (identifier) ); create table c_participation ( @@ -1199,14 +2139,14 @@ create table c_participation ( conversation_id bigint not null, user_id bigint not null, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - constraint ck_c_participation_type check (type in (0,1)), + when_created timestamptz not null, + when_modified timestamptz not null, + constraint ck_c_participation_type check ( type in (0,1)), constraint pk_c_participation primary key (id) ); create table mt_permission ( - id bytea not null, + id uuid not null, name varchar(255), constraint pk_mt_permission primary key (id) ); @@ -1214,8 +2154,8 @@ create table mt_permission ( create table persistent_file ( id serial not null, name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_persistent_file primary key (id) ); @@ -1224,10 +2164,10 @@ create table persistent_file_content ( id serial not null, persistent_file_id integer, content bytea, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, - constraint uq_persistent_file_content_pe_1 unique (persistent_file_id), + constraint uq_persistent_file_content_persistent_file_id unique (persistent_file_id), constraint pk_persistent_file_content primary key (id) ); @@ -1253,39 +2193,55 @@ create table phones ( constraint pk_phones primary key (id) ); +create table primary_revision ( + id bigint not null, + revision integer not null, + name varchar(255), + version bigint not null, + constraint pk_primary_revision primary key (id,revision) +); + create table o_product ( id serial not null, sku varchar(20), name varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, constraint pk_o_product primary key (id) ); create table pp ( - id bytea not null, + id uuid not null, name varchar(255), value varchar(100) not null, constraint pk_pp primary key (id) ); create table pp_to_ww ( - pp_id bytea not null, - ww_id bytea not null, + pp_id uuid not null, + ww_id uuid not null, constraint pk_pp_to_ww primary key (pp_id,ww_id) ); +create table question ( + id bigserial not null, + name varchar(255), + groupobjectid bigint, + sequence_number integer not null, + constraint pk_question primary key (id) +); + create table rcustomer ( - company varchar(255) not null, - name varchar(255) not null, + company varchar(127) not null, + name varchar(127) not null, description varchar(255), constraint pk_rcustomer primary key (company,name) ); create table r_orders ( - company varchar(255) not null, + company varchar(127) not null, order_number integer not null, - customername varchar(255), + customername varchar(127), item varchar(255), constraint pk_r_orders primary key (company,order_number) ); @@ -1305,28 +2261,29 @@ create table resourcefile ( constraint pk_resourcefile primary key (id) ); -create table mt_role ( - id bytea not null, - name varchar(50), - tenant_id bytea, - version bigint not null, - constraint pk_mt_role primary key (id) -); - -create table mt_role_permission ( - mt_role_id bytea not null, - mt_permission_id bytea not null, - constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) -); - create table em_role ( id bigserial not null, name varchar(255), constraint pk_em_role primary key (id) ); +create table mt_role ( + id uuid not null, + name varchar(50), + tenant_id uuid, + version bigint not null, + constraint pk_mt_role primary key (id) +); + +create table mt_role_permission ( + mt_role_id uuid not null, + mt_permission_id uuid not null, + constraint pk_mt_role_permission primary key (mt_role_id,mt_permission_id) +); + create table f_second ( id bigserial not null, + mod_name varchar(255), first bigint, title varchar(255), constraint uq_f_second_first unique (first), @@ -1338,10 +2295,10 @@ create table section ( article_id integer, type integer, content text, - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, - constraint ck_section_type check (type in (0,1)), + constraint ck_section_type check ( type in (0,1)), constraint pk_section primary key (id) ); @@ -1371,7 +2328,7 @@ create table some_enum_bean ( id bigserial not null, some_enum integer, name varchar(255), - constraint ck_some_enum_bean_some_enum check (some_enum in (0,1)), + constraint ck_some_enum_bean_some_enum check ( some_enum in (0,1)), constraint pk_some_enum_bean primary key (id) ); @@ -1390,23 +2347,22 @@ create table some_new_types_bean ( yr integer, yr_mth date, local_date date, - local_date_time timestamp, - offset_date_time timestamp, - zoned_date_time timestamp, - instant timestamp, + local_date_time timestamptz, + offset_date_time timestamptz, + zoned_date_time timestamptz, + instant timestamptz, zone_id varchar(60), zone_offset varchar(60), + path varchar(255), + period varchar(20), version bigint not null, - constraint ck_some_new_types_bean_dow check (dow in ('1','2','3','4','5','6','7')), - constraint ck_some_new_types_bean_mth check (mth in ('1','2','3','4','5','6','7','8','9','10','11','12')), + constraint ck_some_new_types_bean_dow check ( dow in (1,2,3,4,5,6,7)), + constraint ck_some_new_types_bean_mth check ( mth in (1,2,3,4,5,6,7,8,9,10,11,12)), constraint pk_some_new_types_bean primary key (id) ); create table some_period_bean ( id bigserial not null, - period_years integer, - period_months integer, - period_days integer, anniversary date, version bigint not null, constraint pk_some_period_bean primary key (id) @@ -1423,8 +2379,8 @@ create table sub_section ( id serial not null, section_id integer, title varchar(255), - cretime timestamp not null, - updtime timestamp not null, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_sub_section primary key (id) ); @@ -1436,6 +2392,12 @@ create table sub_type ( constraint pk_sub_type primary key (sub_type_id) ); +create table survey ( + id bigserial not null, + name varchar(255), + constraint pk_survey primary key (id) +); + create table tbytes_only ( id serial not null, content bytea, @@ -1444,11 +2406,39 @@ create table tbytes_only ( create table tcar ( type varchar(31) not null, - plate_no varchar(255) not null, + plate_no varchar(32) not null, truckload bigint, constraint pk_tcar primary key (plate_no) ); +create table tevent ( + id bigserial not null, + name varchar(255), + version bigint not null, + constraint pk_tevent primary key (id) +); + +create table tevent_many ( + id bigserial not null, + description varchar(255), + event_id bigint, + units integer not null, + amount float not null, + version bigint not null, + constraint pk_tevent_many primary key (id) +); + +create table tevent_one ( + id bigserial not null, + name varchar(255), + status integer, + event_id bigint, + version bigint not null, + constraint ck_tevent_one_status check ( status in (0,1)), + constraint uq_tevent_one_event_id unique (event_id), + constraint pk_tevent_one primary key (id) +); + create table tint_root ( my_type integer not null, id serial not null, @@ -1475,7 +2465,7 @@ create table t_oneb ( id serial not null, name varchar(255), description varchar(255), - active boolean, + active boolean default false not null, constraint pk_t_oneb primary key (id) ); @@ -1483,9 +2473,11 @@ create table t_detail_with_other_namexxxyy ( id integer not null, name varchar(255), description varchar(255), - active boolean, + some_unique_value varchar(127), + active boolean default false not null, master_id integer, - constraint pk_t_detail_with_other_namexx_0 primary key (id) + constraint uq_t_detail_with_other_namexxxyy_some_unique_value unique (some_unique_value), + constraint pk_t_detail_with_other_namexxxyy primary key (id) ); create sequence t_atable_detail_seq; @@ -1493,7 +2485,7 @@ create table ts_detail_two ( id serial not null, name varchar(255), description varchar(255), - active boolean, + active boolean default false not null, master_id integer, constraint pk_ts_detail_two primary key (id) ); @@ -1502,7 +2494,7 @@ create table t_atable_thatisrelatively ( id integer not null, name varchar(255), description varchar(255), - active boolean, + active boolean default false not null, constraint pk_t_atable_thatisrelatively primary key (id) ); create sequence t_atable_master_seq; @@ -1511,19 +2503,19 @@ create table ts_master_two ( id serial not null, name varchar(255), description varchar(255), - active boolean, + active boolean default false not null, constraint pk_ts_master_two primary key (id) ); create table tuuid_entity ( - id bytea not null, + id uuid not null, name varchar(255), constraint pk_tuuid_entity primary key (id) ); create table twheel ( id bigserial not null, - owner_plate_no varchar(255) not null, + owner_plate_no varchar(32) not null, constraint pk_twheel primary key (id) ); @@ -1535,18 +2527,21 @@ create table twith_pre_insert ( ); create table mt_tenant ( - id bytea not null, + id uuid not null, name varchar(255), version bigint not null, constraint pk_mt_tenant primary key (id) ); -create table sa_tire ( - id bigint not null, - version integer not null, - constraint pk_sa_tire primary key (id) +create table test_annotation_base_entity ( + direct varchar(255), + meta varchar(255), + mixed varchar(255), + constraint_annotation varchar(40), + null1 varchar(255) not null, + null2 varchar(255), + null3 varchar(255) ); -create sequence sa_tire_seq; create table tire ( id bigint not null, @@ -1557,14 +2552,21 @@ create table tire ( ); create sequence tire_seq; +create table sa_tire ( + id bigint not null, + version integer not null, + constraint pk_sa_tire primary key (id) +); +create sequence sa_tire_seq; + create table trip ( id serial not null, vehicle_driver_id integer, destination varchar(255), address_id smallint, - star_date timestamp, - cretime timestamp not null, - updtime timestamp not null, + star_date timestamptz, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_trip primary key (id) ); @@ -1584,6 +2586,14 @@ create table type ( constraint pk_type primary key (customer,type) ); +create table tz_bean ( + id bigserial not null, + moda varchar(255), + ts timestamptz, + tstz timestamptz, + constraint pk_tz_bean primary key (id) +); + create table ut_detail ( id serial not null, utmaster_id integer not null, @@ -1603,22 +2613,29 @@ create table ut_master ( ); create table uuone ( - id bytea not null, + id uuid not null, name varchar(255), constraint pk_uuone primary key (id) ); create table uutwo ( - id bytea not null, + id uuid not null, name varchar(255), - master_id bytea, + master_id uuid, constraint pk_uutwo primary key (id) ); -create table em_user ( +create table c_user ( id bigserial not null, + inactive boolean default false not null, name varchar(255), - constraint pk_em_user primary key (id) + email varchar(255), + password_hash varchar(255), + group_id bigint, + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + constraint pk_c_user primary key (id) ); create table tx_user ( @@ -1627,16 +2644,17 @@ create table tx_user ( constraint pk_tx_user primary key (id) ); -create table c_user ( +create table g_user ( id bigserial not null, - inactive boolean, - name varchar(255), - email varchar(255), - group_id bigint, + username varchar(255), version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, - constraint pk_c_user primary key (id) + constraint pk_g_user primary key (id) +); + +create table em_user ( + id bigserial not null, + name varchar(255), + constraint pk_em_user primary key (id) ); create table oto_user ( @@ -1644,8 +2662,8 @@ create table oto_user ( name varchar(255), account_id bigint not null, version bigint not null, - when_created timestamp not null, - when_modified timestamp not null, + when_created timestamptz not null, + when_modified timestamptz not null, constraint uq_oto_user_account_id unique (account_id), constraint pk_oto_user primary key (id) ); @@ -1660,14 +2678,17 @@ create table vehicle ( dtype varchar(3) not null, id serial not null, license_number varchar(255), - registration_date timestamp, - cretime timestamp not null, - updtime timestamp not null, + registration_date timestamptz, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, - truck_ref_id integer, - capacity float, + siz varchar(1), driver varchar(255), car_ref_id integer, + notes varchar(255), + truck_ref_id integer, + capacity float, + constraint ck_vehicle_siz check ( siz in ('S','M','L','H')), constraint pk_vehicle primary key (id) ); @@ -1676,9 +2697,9 @@ create table vehicle_driver ( name varchar(255), vehicle_id integer, address_id smallint, - license_issued_on timestamp, - cretime timestamp not null, - updtime timestamp not null, + license_issued_on timestamptz, + cretime timestamptz not null, + updtime timestamptz not null, version bigint not null, constraint pk_vehicle_driver primary key (id) ); @@ -1704,13 +2725,6 @@ create table sa_wheel ( ); create sequence sa_wheel_seq; -create table sp_car_wheel ( - id bigint not null, - version integer not null, - constraint pk_sp_car_wheel primary key (id) -); -create sequence sp_car_wheel_seq; - create table wheel ( id bigint not null, version integer not null, @@ -1718,10 +2732,29 @@ create table wheel ( ); create sequence wheel_seq; +create table sp_car_wheel ( + id bigint not null, + version integer not null, + constraint pk_sp_car_wheel primary key (id) +); +create sequence sp_car_wheel_seq; + +create table g_who_props_otm ( + id bigserial not null, + name varchar(255), + version bigint not null, + when_created timestamptz not null, + when_modified timestamptz not null, + who_created_id bigint, + who_modified_id bigint, + constraint pk_g_who_props_otm primary key (id) +); + create table with_zero ( id bigserial not null, name varchar(255), parent_id integer, + lang varchar(2) default 'en' not null, version bigint not null, constraint pk_with_zero primary key (id) ); @@ -1733,8 +2766,8 @@ create table parent ( ); create table wview ( - id bytea not null, - name varchar(255) not null, + id uuid not null, + name varchar(127) not null, constraint uq_wview_name unique (name), constraint pk_wview primary key (id) ); @@ -1746,341 +2779,684 @@ create table zones ( constraint pk_zones primary key (id) ); -alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; +create index ix_contact_last_name_first_name on contact (last_name,first_name); +create index ix_e_basic_name on e_basic (name); create index ix_bar_foo_id on bar (foo_id); +alter table bar add constraint fk_bar_foo_id foreign key (foo_id) references foo (foo_id) on delete restrict on update restrict; + +create index ix_addr_employee_id on addr (employee_id); +alter table addr add constraint fk_addr_employee_id foreign key (employee_id) references empl (id) on delete restrict on update restrict; -alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; create index ix_o_address_country_code on o_address (country_code); +alter table o_address add constraint fk_o_address_country_code foreign key (country_code) references o_country (code) on delete restrict on update restrict; -alter table animals add constraint fk_animals_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; -create index ix_animals_shelter_id on animals (shelter_id); +alter table album add constraint fk_album_cover_id foreign key (cover_id) references cover (id) on delete restrict on update restrict; -alter table attribute add constraint fk_attribute_attribute_holder_1 foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; -create index ix_attribute_attribute_holder_1 on attribute (attribute_holder_id); +create index ix_animal_shelter_id on animal (shelter_id); +alter table animal add constraint fk_animal_shelter_id foreign key (shelter_id) references animal_shelter (id) on delete restrict on update restrict; + +create index ix_attribute_attribute_holder_id on attribute (attribute_holder_id); +alter table attribute add constraint fk_attribute_attribute_holder_id foreign key (attribute_holder_id) references attribute_holder (id) on delete restrict on update restrict; -alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; create index ix_bbookmark_user_id on bbookmark (user_id); +alter table bbookmark add constraint fk_bbookmark_user_id foreign key (user_id) references bbookmark_user (id) on delete restrict on update restrict; + +create index ix_bsite_user_site_id on bsite_user (site_id); +alter table bsite_user add constraint fk_bsite_user_site_id foreign key (site_id) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_user_id on bsite_user (user_id); +alter table bsite_user add constraint fk_bsite_user_user_id foreign key (user_id) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_site on bsite_user_b (site); +alter table bsite_user_b add constraint fk_bsite_user_b_site foreign key (site) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_b_usr on bsite_user_b (usr); +alter table bsite_user_b add constraint fk_bsite_user_b_usr foreign key (usr) references buser (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_site_uid on bsite_user_c (site_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_site_uid foreign key (site_uid) references bsite (id) on delete restrict on update restrict; + +create index ix_bsite_user_c_user_uid on bsite_user_c (user_uid); +alter table bsite_user_c add constraint fk_bsite_user_c_user_uid foreign key (user_uid) references buser (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_agent_invoice foreign key (agent_invoice) references drel_invoice (id) on delete restrict on update restrict; alter table drel_booking add constraint fk_drel_booking_client_invoice foreign key (client_invoice) references drel_invoice (id) on delete restrict on update restrict; -alter table ckey_detail add constraint fk_ckey_detail_ckey_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -create index ix_ckey_detail_one_key_two_key on ckey_detail (one_key,two_key); +create index ix_ckey_detail_parent on ckey_detail (one_key,two_key); +alter table ckey_detail add constraint fk_ckey_detail_parent foreign key (one_key,two_key) references ckey_parent (one_key,two_key) on delete restrict on update restrict; -alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; create index ix_ckey_parent_assoc_id on ckey_parent (assoc_id); +alter table ckey_parent add constraint fk_ckey_parent_assoc_id foreign key (assoc_id) references ckey_assoc (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_product_1 foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; -create index ix_calculation_result_product_1 on calculation_result (product_configuration_id); +create index ix_calculation_result_product_configuration_id on calculation_result (product_configuration_id); +alter table calculation_result add constraint fk_calculation_result_product_configuration_id foreign key (product_configuration_id) references configuration (id) on delete restrict on update restrict; -alter table calculation_result add constraint fk_calculation_result_group_c_2 foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; -create index ix_calculation_result_group_c_2 on calculation_result (group_configuration_id); +create index ix_calculation_result_group_configuration_id on calculation_result (group_configuration_id); +alter table calculation_result add constraint fk_calculation_result_group_configuration_id foreign key (group_configuration_id) references configuration (id) on delete restrict on update restrict; +create index ix_sp_car_car_wheels_sp_car_car on sp_car_car_wheels (car); alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_car foreign key (car) references sp_car_car (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_car on sp_car_car_wheels (car); -alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_w_2 foreign key (wheel) references sp_car_wheel (id) on delete restrict on update restrict; -create index ix_sp_car_car_wheels_wheel on sp_car_car_wheels (wheel); +create index ix_sp_car_car_wheels_sp_car_wheel on sp_car_car_wheels (wheel); +alter table sp_car_car_wheels add constraint fk_sp_car_car_wheels_sp_car_wheel foreign key (wheel) references sp_car_wheel (id) on delete restrict on update restrict; + +create index ix_car_accessory_fuse_id on car_accessory (fuse_id); +alter table car_accessory add constraint fk_car_accessory_fuse_id foreign key (fuse_id) references car_fuse (id) on delete restrict on update restrict; -alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; create index ix_car_accessory_car_id on car_accessory (car_id); +alter table car_accessory add constraint fk_car_accessory_car_id foreign key (car_id) references vehicle (id) on delete restrict on update restrict; -alter table configuration add constraint fk_configuration_configuratio_1 foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; -create index ix_configuration_configuratio_1 on configuration (configurations_id); +create index ix_category_surveyobjectid on category (surveyobjectid); +alter table category add constraint fk_category_surveyobjectid foreign key (surveyobjectid) references survey (id) on delete restrict on update restrict; + +create index ix_child_person_some_bean_id on child_person (some_bean_id); +alter table child_person add constraint fk_child_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_child_person_parent_identifier on child_person (parent_identifier); +alter table child_person add constraint fk_child_person_parent_identifier foreign key (parent_identifier) references parent_person (identifier) on delete restrict on update restrict; + +create index ix_configuration_configurations_id on configuration (configurations_id); +alter table configuration add constraint fk_configuration_configurations_id foreign key (configurations_id) references configurations (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; create index ix_contact_customer_id on contact (customer_id); +alter table contact add constraint fk_contact_customer_id foreign key (customer_id) references o_customer (id) on delete restrict on update restrict; -alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; create index ix_contact_group_id on contact (group_id); +alter table contact add constraint fk_contact_group_id foreign key (group_id) references contact_group (id) on delete restrict on update restrict; -alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; create index ix_contact_note_contact_id on contact_note (contact_id); +alter table contact_note add constraint fk_contact_note_contact_id foreign key (contact_id) references contact (id) on delete restrict on update restrict; -alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_conversation_group_id on c_conversation (group_id); +alter table c_conversation add constraint fk_c_conversation_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_billing_address_1 foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; -create index ix_o_customer_billing_address_1 on o_customer (billing_address_id); +create index ix_o_customer_billing_address_id on o_customer (billing_address_id); +alter table o_customer add constraint fk_o_customer_billing_address_id foreign key (billing_address_id) references o_address (id) on delete restrict on update restrict; -alter table o_customer add constraint fk_o_customer_shipping_addres_2 foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; -create index ix_o_customer_shipping_addres_2 on o_customer (shipping_address_id); +create index ix_o_customer_shipping_address_id on o_customer (shipping_address_id); +alter table o_customer add constraint fk_o_customer_shipping_address_id foreign key (shipping_address_id) references o_address (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_dcredit on dcredit_drol (dcredit_id); +alter table dcredit_drol add constraint fk_dcredit_drol_dcredit foreign key (dcredit_id) references dcredit (id) on delete restrict on update restrict; + +create index ix_dcredit_drol_drol on dcredit_drol (drol_id); +alter table dcredit_drol add constraint fk_dcredit_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_drot_drol_drot on drot_drol (drot_id); +alter table drot_drol add constraint fk_drot_drol_drot foreign key (drot_id) references drot (id) on delete restrict on update restrict; + +create index ix_drot_drol_drol on drot_drol (drol_id); +alter table drot_drol add constraint fk_drot_drol_drol foreign key (drol_id) references drol (id) on delete restrict on update restrict; + +create index ix_dfk_cascade_one_id on dfk_cascade (one_id); +alter table dfk_cascade add constraint fk_dfk_cascade_one_id foreign key (one_id) references dfk_cascade_one (id) on delete cascade on update cascade; + +create index ix_dfk_set_null_one_id on dfk_set_null (one_id); +alter table dfk_set_null add constraint fk_dfk_set_null_one_id foreign key (one_id) references dfk_one (id) on delete set null on update set null; + +alter table doc add constraint fk_doc_id foreign key (id) references doc_draft (id) on delete restrict on update restrict; + +create index ix_doc_link_doc on doc_link (doc_id); +alter table doc_link add constraint fk_doc_link_doc foreign key (doc_id) references doc (id) on delete restrict on update restrict; + +create index ix_doc_link_link on doc_link (link_id); +alter table doc_link add constraint fk_doc_link_link foreign key (link_id) references link (id) on delete restrict on update restrict; + +alter table document add constraint fk_document_id foreign key (id) references document_draft (id) on delete restrict on update restrict; + +create index ix_document_organisation_id on document (organisation_id); +alter table document add constraint fk_document_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_draft_organisation_id on document_draft (organisation_id); +alter table document_draft add constraint fk_document_draft_organisation_id foreign key (organisation_id) references organisation (id) on delete restrict on update restrict; + +create index ix_document_media_document_id on document_media (document_id); +alter table document_media add constraint fk_document_media_document_id foreign key (document_id) references document (id) on delete restrict on update restrict; + +create index ix_document_media_draft_document_id on document_media_draft (document_id); +alter table document_media_draft add constraint fk_document_media_draft_document_id foreign key (document_id) references document_draft (id) on delete restrict on update restrict; + +create index ix_ebasic_json_map_detail_owner_id on ebasic_json_map_detail (owner_id); +alter table ebasic_json_map_detail add constraint fk_ebasic_json_map_detail_owner_id foreign key (owner_id) references ebasic_json_map (id) on delete restrict on update restrict; + +create index ix_ebasic_no_sdchild_owner_id on ebasic_no_sdchild (owner_id); +alter table ebasic_no_sdchild add constraint fk_ebasic_no_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; + +create index ix_ebasic_sdchild_owner_id on ebasic_sdchild (owner_id); +alter table ebasic_sdchild add constraint fk_ebasic_sdchild_owner_id foreign key (owner_id) references ebasic_soft_delete (id) on delete restrict on update restrict; -alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; create index ix_eemb_inner_outer_id on eemb_inner (outer_id); +alter table eemb_inner add constraint fk_eemb_inner_outer_id foreign key (outer_id) references eemb_outer (id) on delete restrict on update restrict; -alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; create index ix_einvoice_person_id on einvoice (person_id); +alter table einvoice add constraint fk_einvoice_person_id foreign key (person_id) references eperson (id) on delete restrict on update restrict; -alter table enull_collection_detail add constraint fk_enull_collection_detail_en_1 foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; -create index ix_enull_collection_detail_en_1 on enull_collection_detail (enull_collection_id); +create index ix_enull_collection_detail_enull_collection_id on enull_collection_detail (enull_collection_id); +alter table enull_collection_detail add constraint fk_enull_collection_detail_enull_collection_id foreign key (enull_collection_id) references enull_collection (id) on delete restrict on update restrict; -alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; create index ix_eopt_one_a_b_id on eopt_one_a (b_id); +alter table eopt_one_a add constraint fk_eopt_one_a_b_id foreign key (b_id) references eopt_one_b (id) on delete restrict on update restrict; -alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; create index ix_eopt_one_b_c_id on eopt_one_b (c_id); +alter table eopt_one_b add constraint fk_eopt_one_b_c_id foreign key (c_id) references eopt_one_c (id) on delete restrict on update restrict; -alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_1 foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; -create index ix_evanilla_collection_detail_1 on evanilla_collection_detail (evanilla_collection_id); +create index ix_esoft_del_book_lend_by_id on esoft_del_book (lend_by_id); +alter table esoft_del_book add constraint fk_esoft_del_book_lend_by_id foreign key (lend_by_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_book on esoft_del_book_esoft_del_user (esoft_del_book_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_book foreign key (esoft_del_book_id) references esoft_del_book (id) on delete restrict on update restrict; + +create index ix_esoft_del_book_esoft_del_user_esoft_del_user on esoft_del_book_esoft_del_user (esoft_del_user_id); +alter table esoft_del_book_esoft_del_user add constraint fk_esoft_del_book_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_down_esoft_del_mid_id on esoft_del_down (esoft_del_mid_id); +alter table esoft_del_down add constraint fk_esoft_del_down_esoft_del_mid_id foreign key (esoft_del_mid_id) references esoft_del_mid (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_top_id on esoft_del_mid (top_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_top_id foreign key (top_id) references esoft_del_top (id) on delete restrict on update restrict; + +create index ix_esoft_del_mid_up_id on esoft_del_mid (up_id); +alter table esoft_del_mid add constraint fk_esoft_del_mid_up_id foreign key (up_id) references esoft_del_up (id) on delete restrict on update restrict; + +alter table esoft_del_one_a add constraint fk_esoft_del_one_a_oneb_id foreign key (oneb_id) references esoft_del_one_b (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_role on esoft_del_role_esoft_del_user (esoft_del_role_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_esoft_del_role_esoft_del_user_esoft_del_user on esoft_del_role_esoft_del_user (esoft_del_user_id); +alter table esoft_del_role_esoft_del_user add constraint fk_esoft_del_role_esoft_del_user_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_user on esoft_del_user_esoft_del_role (esoft_del_user_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_user foreign key (esoft_del_user_id) references esoft_del_user (id) on delete restrict on update restrict; + +create index ix_esoft_del_user_esoft_del_role_esoft_del_role on esoft_del_user_esoft_del_role (esoft_del_role_id); +alter table esoft_del_user_esoft_del_role add constraint fk_esoft_del_user_esoft_del_role_esoft_del_role foreign key (esoft_del_role_id) references esoft_del_role (id) on delete restrict on update restrict; + +create index ix_rawinherit_uncle_parent_id on rawinherit_uncle (parent_id); +alter table rawinherit_uncle add constraint fk_rawinherit_uncle_parent_id foreign key (parent_id) references rawinherit_parent (id) on delete restrict on update restrict; + +create index ix_evanilla_collection_detail_evanilla_collection_id on evanilla_collection_detail (evanilla_collection_id); +alter table evanilla_collection_detail add constraint fk_evanilla_collection_detail_evanilla_collection_id foreign key (evanilla_collection_id) references evanilla_collection (id) on delete restrict on update restrict; -alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; create index ix_td_child_parent_id on td_child (parent_id); +alter table td_child add constraint fk_td_child_parent_id foreign key (parent_id) references td_parent (parent_id) on delete restrict on update restrict; + +create index ix_empl_default_address_id on empl (default_address_id); +alter table empl add constraint fk_empl_default_address_id foreign key (default_address_id) references addr (id) on delete restrict on update restrict; + +create index ix_grand_parent_person_some_bean_id on grand_parent_person (some_bean_id); +alter table grand_parent_person add constraint fk_grand_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_survey_group_categoryobjectid on survey_group (categoryobjectid); +alter table survey_group add constraint fk_survey_group_categoryobjectid foreign key (categoryobjectid) references category (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_hx_link on hx_link_doc (hx_link_id); +alter table hx_link_doc add constraint fk_hx_link_doc_hx_link foreign key (hx_link_id) references hx_link (id) on delete restrict on update restrict; + +create index ix_hx_link_doc_he_doc on hx_link_doc (he_doc_id); +alter table hx_link_doc add constraint fk_hx_link_doc_he_doc foreign key (he_doc_id) references he_doc (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_link on hi_link_doc (hi_link_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_link foreign key (hi_link_id) references hi_link (id) on delete restrict on update restrict; + +create index ix_hi_link_doc_hi_doc on hi_link_doc (hi_doc_id); +alter table hi_link_doc add constraint fk_hi_link_doc_hi_doc foreign key (hi_doc_id) references hi_doc (id) on delete restrict on update restrict; -alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; create index ix_imrelated_owner_id on imrelated (owner_id); +alter table imrelated add constraint fk_imrelated_owner_id foreign key (owner_id) references imroot (id) on delete restrict on update restrict; -alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; create index ix_info_contact_company_id on info_contact (company_id); +alter table info_contact add constraint fk_info_contact_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table info_customer add constraint fk_info_customer_company_id foreign key (company_id) references info_company (id) on delete restrict on update restrict; alter table inner_report add constraint fk_inner_report_forecast_id foreign key (forecast_id) references stockforecast (id) on delete restrict on update restrict; -alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; create index ix_drel_invoice_booking on drel_invoice (booking); +alter table drel_invoice add constraint fk_drel_invoice_booking foreign key (booking) references drel_booking (id) on delete restrict on update restrict; -alter table item add constraint fk_item_type foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -create index ix_item_customer_type on item (customer,type); +create index ix_item_etype on item (customer,type); +alter table item add constraint fk_item_etype foreign key (customer,type) references type (customer,type) on delete restrict on update restrict; -alter table item add constraint fk_item_region foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; -create index ix_item_customer_region on item (customer,region); +create index ix_item_eregion on item (customer,region); +alter table item add constraint fk_item_eregion foreign key (customer,region) references region (customer,type) on delete restrict on update restrict; +alter table trainer_monkey add constraint fk_trainer_monkey_trainer foreign key (trainer_tid) references trainer (tid) on delete restrict on update restrict; + +alter table trainer_monkey add constraint fk_trainer_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_troop foreign key (troop_pid) references troop (pid) on delete restrict on update restrict; + +alter table troop_monkey add constraint fk_troop_monkey_monkey foreign key (monkey_mid) references monkey (mid) on delete restrict on update restrict; + +create index ix_l2_cldf_reset_bean_child_parent_id on l2_cldf_reset_bean_child (parent_id); +alter table l2_cldf_reset_bean_child add constraint fk_l2_cldf_reset_bean_child_parent_id foreign key (parent_id) references l2_cldf_reset_bean (id) on delete restrict on update restrict; + +create index ix_level1_level4_level1 on level1_level4 (level1_id); alter table level1_level4 add constraint fk_level1_level4_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level4_level1_id on level1_level4 (level1_id); +create index ix_level1_level4_level4 on level1_level4 (level4_id); alter table level1_level4 add constraint fk_level1_level4_level4 foreign key (level4_id) references level4 (id) on delete restrict on update restrict; -create index ix_level1_level4_level4_id on level1_level4 (level4_id); +create index ix_level1_level2_level1 on level1_level2 (level1_id); alter table level1_level2 add constraint fk_level1_level2_level1 foreign key (level1_id) references level1 (id) on delete restrict on update restrict; -create index ix_level1_level2_level1_id on level1_level2 (level1_id); +create index ix_level1_level2_level2 on level1_level2 (level2_id); alter table level1_level2 add constraint fk_level1_level2_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level1_level2_level2_id on level1_level2 (level2_id); +create index ix_level2_level3_level2 on level2_level3 (level2_id); alter table level2_level3 add constraint fk_level2_level3_level2 foreign key (level2_id) references level2 (id) on delete restrict on update restrict; -create index ix_level2_level3_level2_id on level2_level3 (level2_id); +create index ix_level2_level3_level3 on level2_level3 (level3_id); alter table level2_level3 add constraint fk_level2_level3_level3 foreign key (level3_id) references level3 (id) on delete restrict on update restrict; -create index ix_level2_level3_level3_id on level2_level3 (level3_id); -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_1 foreign key (la_attr_value_id) references la_attr_value (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_la_1 on la_attr_value_attribute (la_attr_value_id); +alter table link add constraint fk_link_id foreign key (id) references link_draft (id) on delete restrict on update restrict; -alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_at_2 foreign key (attribute_id) references attribute (id) on delete restrict on update restrict; -create index ix_la_attr_value_attribute_at_2 on la_attr_value_attribute (attribute_id); +create index ix_la_attr_value_attribute_la_attr_value on la_attr_value_attribute (la_attr_value_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_la_attr_value foreign key (la_attr_value_id) references la_attr_value (id) on delete restrict on update restrict; + +create index ix_la_attr_value_attribute_attribute on la_attr_value_attribute (attribute_id); +alter table la_attr_value_attribute add constraint fk_la_attr_value_attribute_attribute foreign key (attribute_id) references attribute (id) on delete restrict on update restrict; -alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; create index ix_mprinter_current_state_id on mprinter (current_state_id); +alter table mprinter add constraint fk_mprinter_current_state_id foreign key (current_state_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_cyan_id foreign key (last_swap_cyan_id) references mprinter_state (id) on delete restrict on update restrict; -alter table mprinter add constraint fk_mprinter_last_swap_magenta_3 foreign key (last_swap_magenta_id) references mprinter_state (id) on delete restrict on update restrict; +alter table mprinter add constraint fk_mprinter_last_swap_magenta_id foreign key (last_swap_magenta_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_yellow_id foreign key (last_swap_yellow_id) references mprinter_state (id) on delete restrict on update restrict; alter table mprinter add constraint fk_mprinter_last_swap_black_id foreign key (last_swap_black_id) references mprinter_state (id) on delete restrict on update restrict; -alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; create index ix_mprinter_state_printer_id on mprinter_state (printer_id); +alter table mprinter_state add constraint fk_mprinter_state_printer_id foreign key (printer_id) references mprinter (id) on delete restrict on update restrict; -alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; create index ix_mprofile_picture_id on mprofile (picture_id); +alter table mprofile add constraint fk_mprofile_picture_id foreign key (picture_id) references mmedia (id) on delete restrict on update restrict; +create index ix_mrole_muser_mrole on mrole_muser (mrole_roleid); alter table mrole_muser add constraint fk_mrole_muser_mrole foreign key (mrole_roleid) references mrole (roleid) on delete restrict on update restrict; -create index ix_mrole_muser_mrole_roleid on mrole_muser (mrole_roleid); +create index ix_mrole_muser_muser on mrole_muser (muser_userid); alter table mrole_muser add constraint fk_mrole_muser_muser foreign key (muser_userid) references muser (userid) on delete restrict on update restrict; -create index ix_mrole_muser_muser_userid on mrole_muser (muser_userid); -alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; create index ix_muser_user_type_id on muser (user_type_id); +alter table muser add constraint fk_muser_user_type_id foreign key (user_type_id) references muser_type (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_user on mail_user_inbox (mail_user_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_inbox_mail_box on mail_user_inbox (mail_box_id); +alter table mail_user_inbox add constraint fk_mail_user_inbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_user on mail_user_outbox (mail_user_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_user foreign key (mail_user_id) references mail_user (id) on delete restrict on update restrict; + +create index ix_mail_user_outbox_mail_box on mail_user_outbox (mail_box_id); +alter table mail_user_outbox add constraint fk_mail_user_outbox_mail_box foreign key (mail_box_id) references mail_box (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; create index ix_c_message_conversation_id on c_message (conversation_id); +alter table c_message add constraint fk_c_message_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_message_user_id on c_message (user_id); +alter table c_message add constraint fk_c_message_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_u_1 foreign key (mnoc_user_user_id) references mnoc_user (user_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_u_1 on mnoc_user_mnoc_role (mnoc_user_user_id); +create index ix_mnoc_user_mnoc_role_mnoc_user on mnoc_user_mnoc_role (mnoc_user_user_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_user foreign key (mnoc_user_user_id) references mnoc_user (user_id) on delete restrict on update restrict; -alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_r_2 foreign key (mnoc_role_role_id) references mnoc_role (role_id) on delete restrict on update restrict; -create index ix_mnoc_user_mnoc_role_mnoc_r_2 on mnoc_user_mnoc_role (mnoc_role_role_id); +create index ix_mnoc_user_mnoc_role_mnoc_role on mnoc_user_mnoc_role (mnoc_role_role_id); +alter table mnoc_user_mnoc_role add constraint fk_mnoc_user_mnoc_role_mnoc_role foreign key (mnoc_role_role_id) references mnoc_role (role_id) on delete restrict on update restrict; + +create index ix_mny_b_a_id on mny_b (a_id); +alter table mny_b add constraint fk_mny_b_a_id foreign key (a_id) references mny_a (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_b on mny_b_mny_c (mny_b_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_b foreign key (mny_b_id) references mny_b (id) on delete restrict on update restrict; + +create index ix_mny_b_mny_c_mny_c on mny_b_mny_c (mny_c_id); +alter table mny_b_mny_c add constraint fk_mny_b_mny_c_mny_c foreign key (mny_c_id) references mny_c (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_1 on subtopics (topic); +alter table subtopics add constraint fk_subtopics_mny_topic_1 foreign key (topic) references mny_topic (id) on delete restrict on update restrict; + +create index ix_subtopics_mny_topic_2 on subtopics (subtopic); +alter table subtopics add constraint fk_subtopics_mny_topic_2 foreign key (subtopic) references mny_topic (id) on delete restrict on update restrict; -alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; create index ix_mp_role_mp_user_id on mp_role (mp_user_id); +alter table mp_role add constraint fk_mp_role_mp_user_id foreign key (mp_user_id) references mp_user (id) on delete restrict on update restrict; -alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_pare_1 foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; -create index ix_my_lob_size_join_many_pare_1 on my_lob_size_join_many (parent_id); +create index ix_ms_many_a_many_b_ms_many_a on ms_many_a_many_b (ms_many_a_aid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_ca_1 foreign key (o_cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_ca_1 on o_cached_bean_country (o_cached_bean_id); +create index ix_ms_many_a_many_b_ms_many_b on ms_many_a_many_b (ms_many_b_bid); +alter table ms_many_a_many_b add constraint fk_ms_many_a_many_b_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; -alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_co_2 foreign key (o_country_code) references o_country (code) on delete restrict on update restrict; -create index ix_o_cached_bean_country_o_co_2 on o_cached_bean_country (o_country_code); +create index ix_ms_many_b_many_a_ms_many_b on ms_many_b_many_a (ms_many_b_bid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_b foreign key (ms_many_b_bid) references ms_many_b (bid) on delete restrict on update restrict; -alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_1 foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; -create index ix_o_cached_bean_child_cached_1 on o_cached_bean_child (cached_bean_id); +create index ix_ms_many_b_many_a_ms_many_a on ms_many_b_many_a (ms_many_a_aid); +alter table ms_many_b_many_a add constraint fk_ms_many_b_many_a_ms_many_a foreign key (ms_many_a_aid) references ms_many_a (aid) on delete restrict on update restrict; + +create index ix_my_lob_size_join_many_parent_id on my_lob_size_join_many (parent_id); +alter table my_lob_size_join_many add constraint fk_my_lob_size_join_many_parent_id foreign key (parent_id) references my_lob_size (id) on delete restrict on update restrict; + +create index ix_o_cached_bean_country_o_cached_bean on o_cached_bean_country (o_cached_bean_id); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_cached_bean foreign key (o_cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; + +create index ix_o_cached_bean_country_o_country on o_cached_bean_country (o_country_code); +alter table o_cached_bean_country add constraint fk_o_cached_bean_country_o_country foreign key (o_country_code) references o_country (code) on delete restrict on update restrict; + +create index ix_o_cached_bean_child_cached_bean_id on o_cached_bean_child (cached_bean_id); +alter table o_cached_bean_child add constraint fk_o_cached_bean_child_cached_bean_id foreign key (cached_bean_id) references o_cached_bean (id) on delete restrict on update restrict; alter table oengine add constraint fk_oengine_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; alter table ogear_box add constraint fk_ogear_box_car_id foreign key (car_id) references ocar (id) on delete restrict on update restrict; -alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; +alter table oroad_show_msg add constraint fk_oroad_show_msg_company_id foreign key (company_id) references ocompany (id) on delete restrict on update restrict; + +create index ix_om_ordered_detail_master_id on om_ordered_detail (master_id); +alter table om_ordered_detail add constraint fk_om_ordered_detail_master_id foreign key (master_id) references om_ordered_master (id) on delete restrict on update restrict; + create index ix_o_order_kcustomer_id on o_order (kcustomer_id); +alter table o_order add constraint fk_o_order_kcustomer_id foreign key (kcustomer_id) references o_customer (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_o_order_detail_order_id on o_order_detail (order_id); +alter table o_order_detail add constraint fk_o_order_detail_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; -alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; create index ix_o_order_detail_product_id on o_order_detail (product_id); +alter table o_order_detail add constraint fk_o_order_detail_product_id foreign key (product_id) references o_product (id) on delete restrict on update restrict; -alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; create index ix_s_order_items_order_uuid on s_order_items (order_uuid); +alter table s_order_items add constraint fk_s_order_items_order_uuid foreign key (order_uuid) references s_orders (uuid) on delete restrict on update restrict; -alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; create index ix_or_order_ship_order_id on or_order_ship (order_id); +alter table or_order_ship add constraint fk_or_order_ship_order_id foreign key (order_id) references o_order (id) on delete restrict on update restrict; + +alter table oto_bchild add constraint fk_oto_bchild_master_id foreign key (master_id) references oto_bmaster (id) on delete restrict on update restrict; alter table oto_child add constraint fk_oto_child_master_id foreign key (master_id) references oto_master (id) on delete restrict on update restrict; +alter table oto_cust_address add constraint fk_oto_cust_address_customer_cid foreign key (customer_cid) references oto_cust (cid) on delete restrict on update restrict; + +alter table oto_prime_extra add constraint fk_oto_prime_extra_eid foreign key (eid) references oto_prime (pid) on delete restrict on update restrict; + +create index ix_oto_th_many_oto_th_top_id on oto_th_many (oto_th_top_id); +alter table oto_th_many add constraint fk_oto_th_many_oto_th_top_id foreign key (oto_th_top_id) references oto_th_top (id) on delete restrict on update restrict; + +alter table oto_th_one add constraint fk_oto_th_one_many_id foreign key (many_id) references oto_th_many (id) on delete restrict on update restrict; + +alter table oto_ubprime_extra add constraint fk_oto_ubprime_extra_eid foreign key (eid) references oto_ubprime (pid) on delete restrict on update restrict; + +alter table oto_uprime_extra add constraint fk_oto_uprime_extra_eid foreign key (eid) references oto_uprime (pid) on delete restrict on update restrict; + alter table pfile add constraint fk_pfile_file_content_id foreign key (file_content_id) references pfile_content (id) on delete restrict on update restrict; alter table pfile add constraint fk_pfile_file_content2_id foreign key (file_content2_id) references pfile_content (id) on delete restrict on update restrict; alter table paggview add constraint fk_paggview_pview_id foreign key (pview_id) references pp (id) on delete restrict on update restrict; -alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; create index ix_pallet_location_zone_sid on pallet_location (zone_sid); +alter table pallet_location add constraint fk_pallet_location_zone_sid foreign key (zone_sid) references zones (id) on delete restrict on update restrict; alter table parcel_location add constraint fk_parcel_location_parcelid foreign key (parcelid) references parcel (parcelid) on delete restrict on update restrict; -alter table rawinherit_parent_rawinherit_dat add constraint fk_rawinherit_parent_rawinher_1 foreign key (rawinherit_parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinher_1 on rawinherit_parent_rawinherit_dat (rawinherit_parent_id); +create index ix_rawinherit_parent_rawinherit_data_rawinherit_parent on rawinherit_parent_rawinherit_data (rawinherit_parent_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_parent foreign key (rawinherit_parent_id) references rawinherit_parent (id) on delete restrict on update restrict; -alter table rawinherit_parent_rawinherit_dat add constraint fk_rawinherit_parent_rawinher_2 foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict; -create index ix_rawinherit_parent_rawinher_2 on rawinherit_parent_rawinherit_dat (rawinherit_data_id); +create index ix_rawinherit_parent_rawinherit_data_rawinherit_data on rawinherit_parent_rawinherit_data (rawinherit_data_id); +alter table rawinherit_parent_rawinherit_data add constraint fk_rawinherit_parent_rawinherit_data_rawinherit_data foreign key (rawinherit_data_id) references rawinherit_data (id) on delete restrict on update restrict; -alter table c_participation add constraint fk_c_participation_conversati_1 foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -create index ix_c_participation_conversati_1 on c_participation (conversation_id); +create index ix_parent_person_some_bean_id on parent_person (some_bean_id); +alter table parent_person add constraint fk_parent_person_some_bean_id foreign key (some_bean_id) references e_basic (id) on delete restrict on update restrict; + +create index ix_parent_person_parent_identifier on parent_person (parent_identifier); +alter table parent_person add constraint fk_parent_person_parent_identifier foreign key (parent_identifier) references grand_parent_person (identifier) on delete restrict on update restrict; + +create index ix_c_participation_conversation_id on c_participation (conversation_id); +alter table c_participation add constraint fk_c_participation_conversation_id foreign key (conversation_id) references c_conversation (id) on delete restrict on update restrict; -alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; create index ix_c_participation_user_id on c_participation (user_id); +alter table c_participation add constraint fk_c_participation_user_id foreign key (user_id) references c_user (id) on delete restrict on update restrict; -alter table persistent_file_content add constraint fk_persistent_file_content_pe_1 foreign key (persistent_file_id) references persistent_file (id) on delete restrict on update restrict; +alter table persistent_file_content add constraint fk_persistent_file_content_persistent_file_id foreign key (persistent_file_id) references persistent_file (id) on delete restrict on update restrict; -alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; create index ix_person_default_address_oid on person (default_address_oid); +alter table person add constraint fk_person_default_address_oid foreign key (default_address_oid) references address (oid) on delete restrict on update restrict; -alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; create index ix_phones_person_id on phones (person_id); +alter table phones add constraint fk_phones_person_id foreign key (person_id) references persons (id) on delete restrict on update restrict; +create index ix_pp_to_ww_pp on pp_to_ww (pp_id); alter table pp_to_ww add constraint fk_pp_to_ww_pp foreign key (pp_id) references pp (id) on delete restrict on update restrict; -create index ix_pp_to_ww_pp_id on pp_to_ww (pp_id); +create index ix_pp_to_ww_wview on pp_to_ww (ww_id); alter table pp_to_ww add constraint fk_pp_to_ww_wview foreign key (ww_id) references wview (id) on delete restrict on update restrict; -create index ix_pp_to_ww_ww_id on pp_to_ww (ww_id); -alter table r_orders add constraint fk_r_orders_rcustomer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; -create index ix_r_orders_company_customern_1 on r_orders (company,customername); +create index ix_question_groupobjectid on question (groupobjectid); +alter table question add constraint fk_question_groupobjectid foreign key (groupobjectid) references survey_group (id) on delete restrict on update restrict; -alter table resourcefile add constraint fk_resourcefile_parentresourc_1 foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; -create index ix_resourcefile_parentresourc_1 on resourcefile (parentresourcefileid); +create index ix_r_orders_customer on r_orders (company,customername); +alter table r_orders add constraint fk_r_orders_customer foreign key (company,customername) references rcustomer (company,name) on delete restrict on update restrict; + +create index ix_resourcefile_parentresourcefileid on resourcefile (parentresourcefileid); +alter table resourcefile add constraint fk_resourcefile_parentresourcefileid foreign key (parentresourcefileid) references resourcefile (id) on delete restrict on update restrict; -alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; create index ix_mt_role_tenant_id on mt_role (tenant_id); +alter table mt_role add constraint fk_mt_role_tenant_id foreign key (tenant_id) references mt_tenant (id) on delete restrict on update restrict; +create index ix_mt_role_permission_mt_role on mt_role_permission (mt_role_id); alter table mt_role_permission add constraint fk_mt_role_permission_mt_role foreign key (mt_role_id) references mt_role (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_role_1 on mt_role_permission (mt_role_id); -alter table mt_role_permission add constraint fk_mt_role_permission_mt_perm_2 foreign key (mt_permission_id) references mt_permission (id) on delete restrict on update restrict; -create index ix_mt_role_permission_mt_perm_2 on mt_role_permission (mt_permission_id); +create index ix_mt_role_permission_mt_permission on mt_role_permission (mt_permission_id); +alter table mt_role_permission add constraint fk_mt_role_permission_mt_permission foreign key (mt_permission_id) references mt_permission (id) on delete restrict on update restrict; alter table f_second add constraint fk_f_second_first foreign key (first) references f_first (id) on delete restrict on update restrict; -alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; create index ix_section_article_id on section (article_id); +alter table section add constraint fk_section_article_id foreign key (article_id) references article (id) on delete restrict on update restrict; -alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; create index ix_self_parent_parent_id on self_parent (parent_id); +alter table self_parent add constraint fk_self_parent_parent_id foreign key (parent_id) references self_parent (id) on delete restrict on update restrict; -alter table self_ref_customer add constraint fk_self_ref_customer_referred_1 foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; -create index ix_self_ref_customer_referred_1 on self_ref_customer (referred_by_id); +create index ix_self_ref_customer_referred_by_id on self_ref_customer (referred_by_id); +alter table self_ref_customer add constraint fk_self_ref_customer_referred_by_id foreign key (referred_by_id) references self_ref_customer (id) on delete restrict on update restrict; -alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; create index ix_self_ref_example_parent_id on self_ref_example (parent_id); +alter table self_ref_example add constraint fk_self_ref_example_parent_id foreign key (parent_id) references self_ref_example (id) on delete restrict on update restrict; -alter table stockforecast add constraint fk_stockforecast_inner_report_1 foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; -create index ix_stockforecast_inner_report_1 on stockforecast (inner_report_id); +create index ix_stockforecast_inner_report_id on stockforecast (inner_report_id); +alter table stockforecast add constraint fk_stockforecast_inner_report_id foreign key (inner_report_id) references inner_report (id) on delete restrict on update restrict; -alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; create index ix_sub_section_section_id on sub_section (section_id); +alter table sub_section add constraint fk_sub_section_section_id foreign key (section_id) references section (id) on delete restrict on update restrict; -alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexx_1 foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; -create index ix_t_detail_with_other_namexx_1 on t_detail_with_other_namexxxyy (master_id); +create index ix_tevent_many_event_id on tevent_many (event_id); +alter table tevent_many add constraint fk_tevent_many_event_id foreign key (event_id) references tevent_one (id) on delete restrict on update restrict; + +alter table tevent_one add constraint fk_tevent_one_event_id foreign key (event_id) references tevent (id) on delete restrict on update restrict; + +create index ix_t_detail_with_other_namexxxyy_master_id on t_detail_with_other_namexxxyy (master_id); +alter table t_detail_with_other_namexxxyy add constraint fk_t_detail_with_other_namexxxyy_master_id foreign key (master_id) references t_atable_thatisrelatively (id) on delete restrict on update restrict; -alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; create index ix_ts_detail_two_master_id on ts_detail_two (master_id); +alter table ts_detail_two add constraint fk_ts_detail_two_master_id foreign key (master_id) references ts_master_two (id) on delete restrict on update restrict; -alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; create index ix_twheel_owner_plate_no on twheel (owner_plate_no); +alter table twheel add constraint fk_twheel_owner_plate_no foreign key (owner_plate_no) references tcar (plate_no) on delete restrict on update restrict; alter table tire add constraint fk_tire_wheel foreign key (wheel) references wheel (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; create index ix_trip_vehicle_driver_id on trip (vehicle_driver_id); +alter table trip add constraint fk_trip_vehicle_driver_id foreign key (vehicle_driver_id) references vehicle_driver (id) on delete restrict on update restrict; -alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_trip_address_id on trip (address_id); +alter table trip add constraint fk_trip_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; create index ix_type_sub_type_id on type (sub_type_id); +alter table type add constraint fk_type_sub_type_id foreign key (sub_type_id) references sub_type (sub_type_id) on delete restrict on update restrict; -alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; create index ix_ut_detail_utmaster_id on ut_detail (utmaster_id); +alter table ut_detail add constraint fk_ut_detail_utmaster_id foreign key (utmaster_id) references ut_master (id) on delete restrict on update restrict; -alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; create index ix_uutwo_master_id on uutwo (master_id); +alter table uutwo add constraint fk_uutwo_master_id foreign key (master_id) references uuone (id) on delete restrict on update restrict; -alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; create index ix_c_user_group_id on c_user (group_id); +alter table c_user add constraint fk_c_user_group_id foreign key (group_id) references c_group (id) on delete restrict on update restrict; alter table oto_user add constraint fk_oto_user_account_id foreign key (account_id) references oto_account (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; create index ix_em_user_role_user_id on em_user_role (user_id); +alter table em_user_role add constraint fk_em_user_role_user_id foreign key (user_id) references em_user (id) on delete restrict on update restrict; -alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; create index ix_em_user_role_role_id on em_user_role (role_id); +alter table em_user_role add constraint fk_em_user_role_role_id foreign key (role_id) references em_role (id) on delete restrict on update restrict; -alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); - -alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; create index ix_vehicle_car_ref_id on vehicle (car_ref_id); +alter table vehicle add constraint fk_vehicle_car_ref_id foreign key (car_ref_id) references truck_ref (id) on delete restrict on update restrict; + +create index ix_vehicle_truck_ref_id on vehicle (truck_ref_id); +alter table vehicle add constraint fk_vehicle_truck_ref_id foreign key (truck_ref_id) references truck_ref (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; create index ix_vehicle_driver_vehicle_id on vehicle_driver (vehicle_id); +alter table vehicle_driver add constraint fk_vehicle_driver_vehicle_id foreign key (vehicle_id) references vehicle (id) on delete restrict on update restrict; -alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; create index ix_vehicle_driver_address_id on vehicle_driver (address_id); +alter table vehicle_driver add constraint fk_vehicle_driver_address_id foreign key (address_id) references o_address (id) on delete restrict on update restrict; -alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; create index ix_warehouses_officezoneid on warehouses (officezoneid); +alter table warehouses add constraint fk_warehouses_officezoneid foreign key (officezoneid) references zones (id) on delete restrict on update restrict; -alter table warehousesshippingzones add constraint fk_warehousesshippingzones_wa_1 foreign key (warehouseid) references warehouses (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_wa_1 on warehousesshippingzones (warehouseid); +create index ix_warehousesshippingzones_warehouses on warehousesshippingzones (warehouseid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_warehouses foreign key (warehouseid) references warehouses (id) on delete restrict on update restrict; -alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zo_2 foreign key (shippingzoneid) references zones (id) on delete restrict on update restrict; -create index ix_warehousesshippingzones_sh_2 on warehousesshippingzones (shippingzoneid); +create index ix_warehousesshippingzones_zones on warehousesshippingzones (shippingzoneid); +alter table warehousesshippingzones add constraint fk_warehousesshippingzones_zones foreign key (shippingzoneid) references zones (id) on delete restrict on update restrict; -alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; create index ix_sa_wheel_tire on sa_wheel (tire); +alter table sa_wheel add constraint fk_sa_wheel_tire foreign key (tire) references sa_tire (id) on delete restrict on update restrict; -alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; create index ix_sa_wheel_car on sa_wheel (car); +alter table sa_wheel add constraint fk_sa_wheel_car foreign key (car) references sa_car (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_created_id on g_who_props_otm (who_created_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_created_id foreign key (who_created_id) references g_user (id) on delete restrict on update restrict; + +create index ix_g_who_props_otm_who_modified_id on g_who_props_otm (who_modified_id); +alter table g_who_props_otm add constraint fk_g_who_props_otm_who_modified_id foreign key (who_modified_id) references g_user (id) on delete restrict on update restrict; -alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; create index ix_with_zero_parent_id on with_zero (parent_id); +alter table with_zero add constraint fk_with_zero_parent_id foreign key (parent_id) references parent (id) on delete restrict on update restrict; + +alter table hx_link add column sys_period tstzrange not null default tstzrange(current_timestamp, null); +update hx_link set sys_period = tstzrange(when_created, null); +create table hx_link_history(like hx_link); +create view hx_link_with_history as select * from hx_link union all select * from hx_link_history; + +create or replace function hx_link_history_version() returns trigger as $$ +begin + if (TG_OP = 'UPDATE') then + insert into hx_link_history (sys_period,id, name, location, comments, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + NEW.sys_period = tstzrange(current_timestamp,null); + return new; + elsif (TG_OP = 'DELETE') then + insert into hx_link_history (sys_period,id, name, location, comments, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + return old; + end if; +end; +$$ LANGUAGE plpgsql; + +create trigger hx_link_history_upd + before update or delete on hx_link + for each row execute procedure hx_link_history_version(); + +alter table hi_link add column sys_period tstzrange not null default tstzrange(current_timestamp, null); +update hi_link set sys_period = tstzrange(when_created, null); +create table hi_link_history(like hi_link); +create view hi_link_with_history as select * from hi_link union all select * from hi_link_history; + +create or replace function hi_link_history_version() returns trigger as $$ +begin + if (TG_OP = 'UPDATE') then + insert into hi_link_history (sys_period,id, name, location, comments, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + NEW.sys_period = tstzrange(current_timestamp,null); + return new; + elsif (TG_OP = 'DELETE') then + insert into hi_link_history (sys_period,id, name, location, comments, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.comments, OLD.version, OLD.when_created, OLD.when_modified); + return old; + end if; +end; +$$ LANGUAGE plpgsql; + +create trigger hi_link_history_upd + before update or delete on hi_link + for each row execute procedure hi_link_history_version(); + +alter table hi_link_doc add column sys_period tstzrange not null default tstzrange(current_timestamp, null); +create table hi_link_doc_history(like hi_link_doc); +create view hi_link_doc_with_history as select * from hi_link_doc union all select * from hi_link_doc_history; + +create or replace function hi_link_doc_history_version() returns trigger as $$ +begin + if (TG_OP = 'UPDATE') then + insert into hi_link_doc_history (sys_period,hi_link_id, hi_doc_id) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.hi_link_id, OLD.hi_doc_id); + NEW.sys_period = tstzrange(current_timestamp,null); + return new; + elsif (TG_OP = 'DELETE') then + insert into hi_link_doc_history (sys_period,hi_link_id, hi_doc_id) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.hi_link_id, OLD.hi_doc_id); + return old; + end if; +end; +$$ LANGUAGE plpgsql; + +create trigger hi_link_doc_history_upd + before update or delete on hi_link_doc + for each row execute procedure hi_link_doc_history_version(); + +alter table link add column sys_period tstzrange not null default tstzrange(current_timestamp, null); +update link set sys_period = tstzrange(when_created, null); +create table link_history(like link); +create view link_with_history as select * from link union all select * from link_history; + +create or replace function link_history_version() returns trigger as $$ +begin + if (TG_OP = 'UPDATE') then + insert into link_history (sys_period,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); + NEW.sys_period = tstzrange(current_timestamp,null); + return new; + elsif (TG_OP = 'DELETE') then + insert into link_history (sys_period,id, name, location, when_publish, link_comment, version, when_created, when_modified, deleted) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.name, OLD.location, OLD.when_publish, OLD.link_comment, OLD.version, OLD.when_created, OLD.when_modified, OLD.deleted); + return old; + end if; +end; +$$ LANGUAGE plpgsql; + +create trigger link_history_upd + before update or delete on link + for each row execute procedure link_history_version(); + +alter table c_user add column sys_period tstzrange not null default tstzrange(current_timestamp, null); +update c_user set sys_period = tstzrange(when_created, null); +create table c_user_history(like c_user); +create view c_user_with_history as select * from c_user union all select * from c_user_history; + +create or replace function c_user_history_version() returns trigger as $$ +begin + if (TG_OP = 'UPDATE') then + insert into c_user_history (sys_period,id, inactive, name, email, group_id, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); + NEW.sys_period = tstzrange(current_timestamp,null); + return new; + elsif (TG_OP = 'DELETE') then + insert into c_user_history (sys_period,id, inactive, name, email, group_id, version, when_created, when_modified) values (tstzrange(lower(OLD.sys_period), current_timestamp), OLD.id, OLD.inactive, OLD.name, OLD.email, OLD.group_id, OLD.version, OLD.when_created, OLD.when_modified); + return old; + end if; +end; +$$ LANGUAGE plpgsql; + +create trigger c_user_history_upd + before update or delete on c_user + for each row execute procedure c_user_history_version(); diff --git a/src/test/ddl-review/pg-drop-all.sql b/src/test/ddl-review/pg-drop-all.sql index cf7ea95f8..e02947028 100644 --- a/src/test/ddl-review/pg-drop-all.sql +++ b/src/test/ddl-review/pg-drop-all.sql @@ -1,340 +1,573 @@ -alter table bar drop constraint fk_bar_foo_id; -drop index ix_bar_foo_id; +-- Generated by ebean unknown at 2018-03-08T06:39:45.063Z +alter table if exists bar drop constraint if exists fk_bar_foo_id; +drop index if exists ix_bar_foo_id; -alter table o_address drop constraint fk_o_address_country_code; -drop index ix_o_address_country_code; +alter table if exists addr drop constraint if exists fk_addr_employee_id; +drop index if exists ix_addr_employee_id; -alter table animals drop constraint fk_animals_shelter_id; -drop index ix_animals_shelter_id; +alter table if exists o_address drop constraint if exists fk_o_address_country_code; +drop index if exists ix_o_address_country_code; -alter table attribute drop constraint fk_attribute_attribute_holder_1; -drop index ix_attribute_attribute_holder_1; +alter table if exists album drop constraint if exists fk_album_cover_id; -alter table bbookmark drop constraint fk_bbookmark_user_id; -drop index ix_bbookmark_user_id; +alter table if exists animal drop constraint if exists fk_animal_shelter_id; +drop index if exists ix_animal_shelter_id; -alter table drel_booking drop constraint fk_drel_booking_agent_invoice; +alter table if exists attribute drop constraint if exists fk_attribute_attribute_holder_id; +drop index if exists ix_attribute_attribute_holder_id; -alter table drel_booking drop constraint fk_drel_booking_client_invoice; +alter table if exists bbookmark drop constraint if exists fk_bbookmark_user_id; +drop index if exists ix_bbookmark_user_id; -alter table ckey_detail drop constraint fk_ckey_detail_ckey_parent; -drop index ix_ckey_detail_one_key_two_key; +alter table if exists bsite_user drop constraint if exists fk_bsite_user_site_id; +drop index if exists ix_bsite_user_site_id; -alter table ckey_parent drop constraint fk_ckey_parent_assoc_id; -drop index ix_ckey_parent_assoc_id; +alter table if exists bsite_user drop constraint if exists fk_bsite_user_user_id; +drop index if exists ix_bsite_user_user_id; -alter table calculation_result drop constraint fk_calculation_result_product_1; -drop index ix_calculation_result_product_1; +alter table if exists bsite_user_b drop constraint if exists fk_bsite_user_b_site; +drop index if exists ix_bsite_user_b_site; -alter table calculation_result drop constraint fk_calculation_result_group_c_2; -drop index ix_calculation_result_group_c_2; +alter table if exists bsite_user_b drop constraint if exists fk_bsite_user_b_usr; +drop index if exists ix_bsite_user_b_usr; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_car; -drop index ix_sp_car_car_wheels_car; +alter table if exists bsite_user_c drop constraint if exists fk_bsite_user_c_site_uid; +drop index if exists ix_bsite_user_c_site_uid; -alter table sp_car_car_wheels drop constraint fk_sp_car_car_wheels_sp_car_w_2; -drop index ix_sp_car_car_wheels_wheel; +alter table if exists bsite_user_c drop constraint if exists fk_bsite_user_c_user_uid; +drop index if exists ix_bsite_user_c_user_uid; -alter table car_accessory drop constraint fk_car_accessory_car_id; -drop index ix_car_accessory_car_id; +alter table if exists drel_booking drop constraint if exists fk_drel_booking_agent_invoice; -alter table configuration drop constraint fk_configuration_configuratio_1; -drop index ix_configuration_configuratio_1; +alter table if exists drel_booking drop constraint if exists fk_drel_booking_client_invoice; -alter table contact drop constraint fk_contact_customer_id; -drop index ix_contact_customer_id; +alter table if exists ckey_detail drop constraint if exists fk_ckey_detail_parent; +drop index if exists ix_ckey_detail_parent; -alter table contact drop constraint fk_contact_group_id; -drop index ix_contact_group_id; +alter table if exists ckey_parent drop constraint if exists fk_ckey_parent_assoc_id; +drop index if exists ix_ckey_parent_assoc_id; -alter table contact_note drop constraint fk_contact_note_contact_id; -drop index ix_contact_note_contact_id; +alter table if exists calculation_result drop constraint if exists fk_calculation_result_product_configuration_id; +drop index if exists ix_calculation_result_product_configuration_id; -alter table c_conversation drop constraint fk_c_conversation_group_id; -drop index ix_c_conversation_group_id; +alter table if exists calculation_result drop constraint if exists fk_calculation_result_group_configuration_id; +drop index if exists ix_calculation_result_group_configuration_id; -alter table o_customer drop constraint fk_o_customer_billing_address_1; -drop index ix_o_customer_billing_address_1; +alter table if exists sp_car_car_wheels drop constraint if exists fk_sp_car_car_wheels_sp_car_car; +drop index if exists ix_sp_car_car_wheels_sp_car_car; -alter table o_customer drop constraint fk_o_customer_shipping_addres_2; -drop index ix_o_customer_shipping_addres_2; +alter table if exists sp_car_car_wheels drop constraint if exists fk_sp_car_car_wheels_sp_car_wheel; +drop index if exists ix_sp_car_car_wheels_sp_car_wheel; -alter table eemb_inner drop constraint fk_eemb_inner_outer_id; -drop index ix_eemb_inner_outer_id; +alter table if exists car_accessory drop constraint if exists fk_car_accessory_fuse_id; +drop index if exists ix_car_accessory_fuse_id; -alter table einvoice drop constraint fk_einvoice_person_id; -drop index ix_einvoice_person_id; +alter table if exists car_accessory drop constraint if exists fk_car_accessory_car_id; +drop index if exists ix_car_accessory_car_id; -alter table enull_collection_detail drop constraint fk_enull_collection_detail_en_1; -drop index ix_enull_collection_detail_en_1; +alter table if exists category drop constraint if exists fk_category_surveyobjectid; +drop index if exists ix_category_surveyobjectid; -alter table eopt_one_a drop constraint fk_eopt_one_a_b_id; -drop index ix_eopt_one_a_b_id; +alter table if exists child_person drop constraint if exists fk_child_person_some_bean_id; +drop index if exists ix_child_person_some_bean_id; -alter table eopt_one_b drop constraint fk_eopt_one_b_c_id; -drop index ix_eopt_one_b_c_id; +alter table if exists child_person drop constraint if exists fk_child_person_parent_identifier; +drop index if exists ix_child_person_parent_identifier; -alter table evanilla_collection_detail drop constraint fk_evanilla_collection_detail_1; -drop index ix_evanilla_collection_detail_1; +alter table if exists configuration drop constraint if exists fk_configuration_configurations_id; +drop index if exists ix_configuration_configurations_id; -alter table td_child drop constraint fk_td_child_parent_id; -drop index ix_td_child_parent_id; +alter table if exists contact drop constraint if exists fk_contact_customer_id; +drop index if exists ix_contact_customer_id; -alter table imrelated drop constraint fk_imrelated_owner_id; -drop index ix_imrelated_owner_id; +alter table if exists contact drop constraint if exists fk_contact_group_id; +drop index if exists ix_contact_group_id; -alter table info_contact drop constraint fk_info_contact_company_id; -drop index ix_info_contact_company_id; +alter table if exists contact_note drop constraint if exists fk_contact_note_contact_id; +drop index if exists ix_contact_note_contact_id; -alter table info_customer drop constraint fk_info_customer_company_id; +alter table if exists c_conversation drop constraint if exists fk_c_conversation_group_id; +drop index if exists ix_c_conversation_group_id; -alter table inner_report drop constraint fk_inner_report_forecast_id; +alter table if exists o_customer drop constraint if exists fk_o_customer_billing_address_id; +drop index if exists ix_o_customer_billing_address_id; -alter table drel_invoice drop constraint fk_drel_invoice_booking; -drop index ix_drel_invoice_booking; +alter table if exists o_customer drop constraint if exists fk_o_customer_shipping_address_id; +drop index if exists ix_o_customer_shipping_address_id; -alter table item drop constraint fk_item_type; -drop index ix_item_customer_type; +alter table if exists dcredit_drol drop constraint if exists fk_dcredit_drol_dcredit; +drop index if exists ix_dcredit_drol_dcredit; -alter table item drop constraint fk_item_region; -drop index ix_item_customer_region; +alter table if exists dcredit_drol drop constraint if exists fk_dcredit_drol_drol; +drop index if exists ix_dcredit_drol_drol; -alter table level1_level4 drop constraint fk_level1_level4_level1; -drop index ix_level1_level4_level1_id; +alter table if exists drot_drol drop constraint if exists fk_drot_drol_drot; +drop index if exists ix_drot_drol_drot; -alter table level1_level4 drop constraint fk_level1_level4_level4; -drop index ix_level1_level4_level4_id; +alter table if exists drot_drol drop constraint if exists fk_drot_drol_drol; +drop index if exists ix_drot_drol_drol; -alter table level1_level2 drop constraint fk_level1_level2_level1; -drop index ix_level1_level2_level1_id; +alter table if exists dfk_cascade drop constraint if exists fk_dfk_cascade_one_id; +drop index if exists ix_dfk_cascade_one_id; -alter table level1_level2 drop constraint fk_level1_level2_level2; -drop index ix_level1_level2_level2_id; +alter table if exists dfk_set_null drop constraint if exists fk_dfk_set_null_one_id; +drop index if exists ix_dfk_set_null_one_id; -alter table level2_level3 drop constraint fk_level2_level3_level2; -drop index ix_level2_level3_level2_id; +alter table if exists doc drop constraint if exists fk_doc_id; -alter table level2_level3 drop constraint fk_level2_level3_level3; -drop index ix_level2_level3_level3_id; +alter table if exists doc_link drop constraint if exists fk_doc_link_doc; +drop index if exists ix_doc_link_doc; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_la_1; -drop index ix_la_attr_value_attribute_la_1; +alter table if exists doc_link drop constraint if exists fk_doc_link_link; +drop index if exists ix_doc_link_link; -alter table la_attr_value_attribute drop constraint fk_la_attr_value_attribute_at_2; -drop index ix_la_attr_value_attribute_at_2; +alter table if exists document drop constraint if exists fk_document_id; -alter table mprinter drop constraint fk_mprinter_current_state_id; -drop index ix_mprinter_current_state_id; +alter table if exists document drop constraint if exists fk_document_organisation_id; +drop index if exists ix_document_organisation_id; -alter table mprinter drop constraint fk_mprinter_last_swap_cyan_id; +alter table if exists document_draft drop constraint if exists fk_document_draft_organisation_id; +drop index if exists ix_document_draft_organisation_id; -alter table mprinter drop constraint fk_mprinter_last_swap_magenta_3; +alter table if exists document_media drop constraint if exists fk_document_media_document_id; +drop index if exists ix_document_media_document_id; -alter table mprinter drop constraint fk_mprinter_last_swap_yellow_id; +alter table if exists document_media_draft drop constraint if exists fk_document_media_draft_document_id; +drop index if exists ix_document_media_draft_document_id; -alter table mprinter drop constraint fk_mprinter_last_swap_black_id; +alter table if exists ebasic_json_map_detail drop constraint if exists fk_ebasic_json_map_detail_owner_id; +drop index if exists ix_ebasic_json_map_detail_owner_id; -alter table mprinter_state drop constraint fk_mprinter_state_printer_id; -drop index ix_mprinter_state_printer_id; +alter table if exists ebasic_no_sdchild drop constraint if exists fk_ebasic_no_sdchild_owner_id; +drop index if exists ix_ebasic_no_sdchild_owner_id; -alter table mprofile drop constraint fk_mprofile_picture_id; -drop index ix_mprofile_picture_id; +alter table if exists ebasic_sdchild drop constraint if exists fk_ebasic_sdchild_owner_id; +drop index if exists ix_ebasic_sdchild_owner_id; -alter table mrole_muser drop constraint fk_mrole_muser_mrole; -drop index ix_mrole_muser_mrole_roleid; +alter table if exists eemb_inner drop constraint if exists fk_eemb_inner_outer_id; +drop index if exists ix_eemb_inner_outer_id; -alter table mrole_muser drop constraint fk_mrole_muser_muser; -drop index ix_mrole_muser_muser_userid; +alter table if exists einvoice drop constraint if exists fk_einvoice_person_id; +drop index if exists ix_einvoice_person_id; -alter table muser drop constraint fk_muser_user_type_id; -drop index ix_muser_user_type_id; +alter table if exists enull_collection_detail drop constraint if exists fk_enull_collection_detail_enull_collection_id; +drop index if exists ix_enull_collection_detail_enull_collection_id; -alter table c_message drop constraint fk_c_message_conversation_id; -drop index ix_c_message_conversation_id; +alter table if exists eopt_one_a drop constraint if exists fk_eopt_one_a_b_id; +drop index if exists ix_eopt_one_a_b_id; -alter table c_message drop constraint fk_c_message_user_id; -drop index ix_c_message_user_id; +alter table if exists eopt_one_b drop constraint if exists fk_eopt_one_b_c_id; +drop index if exists ix_eopt_one_b_c_id; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_u_1; -drop index ix_mnoc_user_mnoc_role_mnoc_u_1; +alter table if exists esoft_del_book drop constraint if exists fk_esoft_del_book_lend_by_id; +drop index if exists ix_esoft_del_book_lend_by_id; -alter table mnoc_user_mnoc_role drop constraint fk_mnoc_user_mnoc_role_mnoc_r_2; -drop index ix_mnoc_user_mnoc_role_mnoc_r_2; +alter table if exists esoft_del_book_esoft_del_user drop constraint if exists fk_esoft_del_book_esoft_del_user_esoft_del_book; +drop index if exists ix_esoft_del_book_esoft_del_user_esoft_del_book; -alter table mp_role drop constraint fk_mp_role_mp_user_id; -drop index ix_mp_role_mp_user_id; +alter table if exists esoft_del_book_esoft_del_user drop constraint if exists fk_esoft_del_book_esoft_del_user_esoft_del_user; +drop index if exists ix_esoft_del_book_esoft_del_user_esoft_del_user; -alter table my_lob_size_join_many drop constraint fk_my_lob_size_join_many_pare_1; -drop index ix_my_lob_size_join_many_pare_1; +alter table if exists esoft_del_down drop constraint if exists fk_esoft_del_down_esoft_del_mid_id; +drop index if exists ix_esoft_del_down_esoft_del_mid_id; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_ca_1; -drop index ix_o_cached_bean_country_o_ca_1; +alter table if exists esoft_del_mid drop constraint if exists fk_esoft_del_mid_top_id; +drop index if exists ix_esoft_del_mid_top_id; -alter table o_cached_bean_country drop constraint fk_o_cached_bean_country_o_co_2; -drop index ix_o_cached_bean_country_o_co_2; +alter table if exists esoft_del_mid drop constraint if exists fk_esoft_del_mid_up_id; +drop index if exists ix_esoft_del_mid_up_id; -alter table o_cached_bean_child drop constraint fk_o_cached_bean_child_cached_1; -drop index ix_o_cached_bean_child_cached_1; +alter table if exists esoft_del_one_a drop constraint if exists fk_esoft_del_one_a_oneb_id; -alter table oengine drop constraint fk_oengine_car_id; +alter table if exists esoft_del_role_esoft_del_user drop constraint if exists fk_esoft_del_role_esoft_del_user_esoft_del_role; +drop index if exists ix_esoft_del_role_esoft_del_user_esoft_del_role; -alter table ogear_box drop constraint fk_ogear_box_car_id; +alter table if exists esoft_del_role_esoft_del_user drop constraint if exists fk_esoft_del_role_esoft_del_user_esoft_del_user; +drop index if exists ix_esoft_del_role_esoft_del_user_esoft_del_user; -alter table o_order drop constraint fk_o_order_kcustomer_id; -drop index ix_o_order_kcustomer_id; +alter table if exists esoft_del_user_esoft_del_role drop constraint if exists fk_esoft_del_user_esoft_del_role_esoft_del_user; +drop index if exists ix_esoft_del_user_esoft_del_role_esoft_del_user; -alter table o_order_detail drop constraint fk_o_order_detail_order_id; -drop index ix_o_order_detail_order_id; +alter table if exists esoft_del_user_esoft_del_role drop constraint if exists fk_esoft_del_user_esoft_del_role_esoft_del_role; +drop index if exists ix_esoft_del_user_esoft_del_role_esoft_del_role; -alter table o_order_detail drop constraint fk_o_order_detail_product_id; -drop index ix_o_order_detail_product_id; +alter table if exists rawinherit_uncle drop constraint if exists fk_rawinherit_uncle_parent_id; +drop index if exists ix_rawinherit_uncle_parent_id; -alter table s_order_items drop constraint fk_s_order_items_order_uuid; -drop index ix_s_order_items_order_uuid; +alter table if exists evanilla_collection_detail drop constraint if exists fk_evanilla_collection_detail_evanilla_collection_id; +drop index if exists ix_evanilla_collection_detail_evanilla_collection_id; -alter table or_order_ship drop constraint fk_or_order_ship_order_id; -drop index ix_or_order_ship_order_id; +alter table if exists td_child drop constraint if exists fk_td_child_parent_id; +drop index if exists ix_td_child_parent_id; -alter table oto_child drop constraint fk_oto_child_master_id; +alter table if exists empl drop constraint if exists fk_empl_default_address_id; +drop index if exists ix_empl_default_address_id; -alter table pfile drop constraint fk_pfile_file_content_id; +alter table if exists grand_parent_person drop constraint if exists fk_grand_parent_person_some_bean_id; +drop index if exists ix_grand_parent_person_some_bean_id; -alter table pfile drop constraint fk_pfile_file_content2_id; +alter table if exists survey_group drop constraint if exists fk_survey_group_categoryobjectid; +drop index if exists ix_survey_group_categoryobjectid; -alter table paggview drop constraint fk_paggview_pview_id; +alter table if exists hx_link_doc drop constraint if exists fk_hx_link_doc_hx_link; +drop index if exists ix_hx_link_doc_hx_link; -alter table pallet_location drop constraint fk_pallet_location_zone_sid; -drop index ix_pallet_location_zone_sid; +alter table if exists hx_link_doc drop constraint if exists fk_hx_link_doc_he_doc; +drop index if exists ix_hx_link_doc_he_doc; -alter table parcel_location drop constraint fk_parcel_location_parcelid; +alter table if exists hi_link_doc drop constraint if exists fk_hi_link_doc_hi_link; +drop index if exists ix_hi_link_doc_hi_link; -alter table rawinherit_parent_rawinherit_dat drop constraint fk_rawinherit_parent_rawinher_1; -drop index ix_rawinherit_parent_rawinher_1; +alter table if exists hi_link_doc drop constraint if exists fk_hi_link_doc_hi_doc; +drop index if exists ix_hi_link_doc_hi_doc; -alter table rawinherit_parent_rawinherit_dat drop constraint fk_rawinherit_parent_rawinher_2; -drop index ix_rawinherit_parent_rawinher_2; +alter table if exists imrelated drop constraint if exists fk_imrelated_owner_id; +drop index if exists ix_imrelated_owner_id; -alter table c_participation drop constraint fk_c_participation_conversati_1; -drop index ix_c_participation_conversati_1; +alter table if exists info_contact drop constraint if exists fk_info_contact_company_id; +drop index if exists ix_info_contact_company_id; -alter table c_participation drop constraint fk_c_participation_user_id; -drop index ix_c_participation_user_id; +alter table if exists info_customer drop constraint if exists fk_info_customer_company_id; -alter table persistent_file_content drop constraint fk_persistent_file_content_pe_1; +alter table if exists inner_report drop constraint if exists fk_inner_report_forecast_id; -alter table person drop constraint fk_person_default_address_oid; -drop index ix_person_default_address_oid; +alter table if exists drel_invoice drop constraint if exists fk_drel_invoice_booking; +drop index if exists ix_drel_invoice_booking; -alter table phones drop constraint fk_phones_person_id; -drop index ix_phones_person_id; +alter table if exists item drop constraint if exists fk_item_etype; +drop index if exists ix_item_etype; -alter table pp_to_ww drop constraint fk_pp_to_ww_pp; -drop index ix_pp_to_ww_pp_id; +alter table if exists item drop constraint if exists fk_item_eregion; +drop index if exists ix_item_eregion; -alter table pp_to_ww drop constraint fk_pp_to_ww_wview; -drop index ix_pp_to_ww_ww_id; +alter table if exists trainer_monkey drop constraint if exists fk_trainer_monkey_trainer; -alter table r_orders drop constraint fk_r_orders_rcustomer; -drop index ix_r_orders_company_customern_1; +alter table if exists trainer_monkey drop constraint if exists fk_trainer_monkey_monkey; -alter table resourcefile drop constraint fk_resourcefile_parentresourc_1; -drop index ix_resourcefile_parentresourc_1; +alter table if exists troop_monkey drop constraint if exists fk_troop_monkey_troop; -alter table mt_role drop constraint fk_mt_role_tenant_id; -drop index ix_mt_role_tenant_id; +alter table if exists troop_monkey drop constraint if exists fk_troop_monkey_monkey; -alter table mt_role_permission drop constraint fk_mt_role_permission_mt_role; -drop index ix_mt_role_permission_mt_role_1; +alter table if exists l2_cldf_reset_bean_child drop constraint if exists fk_l2_cldf_reset_bean_child_parent_id; +drop index if exists ix_l2_cldf_reset_bean_child_parent_id; -alter table mt_role_permission drop constraint fk_mt_role_permission_mt_perm_2; -drop index ix_mt_role_permission_mt_perm_2; +alter table if exists level1_level4 drop constraint if exists fk_level1_level4_level1; +drop index if exists ix_level1_level4_level1; -alter table f_second drop constraint fk_f_second_first; +alter table if exists level1_level4 drop constraint if exists fk_level1_level4_level4; +drop index if exists ix_level1_level4_level4; -alter table section drop constraint fk_section_article_id; -drop index ix_section_article_id; +alter table if exists level1_level2 drop constraint if exists fk_level1_level2_level1; +drop index if exists ix_level1_level2_level1; -alter table self_parent drop constraint fk_self_parent_parent_id; -drop index ix_self_parent_parent_id; +alter table if exists level1_level2 drop constraint if exists fk_level1_level2_level2; +drop index if exists ix_level1_level2_level2; -alter table self_ref_customer drop constraint fk_self_ref_customer_referred_1; -drop index ix_self_ref_customer_referred_1; +alter table if exists level2_level3 drop constraint if exists fk_level2_level3_level2; +drop index if exists ix_level2_level3_level2; -alter table self_ref_example drop constraint fk_self_ref_example_parent_id; -drop index ix_self_ref_example_parent_id; +alter table if exists level2_level3 drop constraint if exists fk_level2_level3_level3; +drop index if exists ix_level2_level3_level3; -alter table stockforecast drop constraint fk_stockforecast_inner_report_1; -drop index ix_stockforecast_inner_report_1; +alter table if exists link drop constraint if exists fk_link_id; -alter table sub_section drop constraint fk_sub_section_section_id; -drop index ix_sub_section_section_id; +alter table if exists la_attr_value_attribute drop constraint if exists fk_la_attr_value_attribute_la_attr_value; +drop index if exists ix_la_attr_value_attribute_la_attr_value; -alter table t_detail_with_other_namexxxyy drop constraint fk_t_detail_with_other_namexx_1; -drop index ix_t_detail_with_other_namexx_1; +alter table if exists la_attr_value_attribute drop constraint if exists fk_la_attr_value_attribute_attribute; +drop index if exists ix_la_attr_value_attribute_attribute; -alter table ts_detail_two drop constraint fk_ts_detail_two_master_id; -drop index ix_ts_detail_two_master_id; +alter table if exists mprinter drop constraint if exists fk_mprinter_current_state_id; +drop index if exists ix_mprinter_current_state_id; -alter table twheel drop constraint fk_twheel_owner_plate_no; -drop index ix_twheel_owner_plate_no; +alter table if exists mprinter drop constraint if exists fk_mprinter_last_swap_cyan_id; -alter table tire drop constraint fk_tire_wheel; +alter table if exists mprinter drop constraint if exists fk_mprinter_last_swap_magenta_id; -alter table trip drop constraint fk_trip_vehicle_driver_id; -drop index ix_trip_vehicle_driver_id; +alter table if exists mprinter drop constraint if exists fk_mprinter_last_swap_yellow_id; -alter table trip drop constraint fk_trip_address_id; -drop index ix_trip_address_id; +alter table if exists mprinter drop constraint if exists fk_mprinter_last_swap_black_id; -alter table type drop constraint fk_type_sub_type_id; -drop index ix_type_sub_type_id; +alter table if exists mprinter_state drop constraint if exists fk_mprinter_state_printer_id; +drop index if exists ix_mprinter_state_printer_id; -alter table ut_detail drop constraint fk_ut_detail_utmaster_id; -drop index ix_ut_detail_utmaster_id; +alter table if exists mprofile drop constraint if exists fk_mprofile_picture_id; +drop index if exists ix_mprofile_picture_id; -alter table uutwo drop constraint fk_uutwo_master_id; -drop index ix_uutwo_master_id; +alter table if exists mrole_muser drop constraint if exists fk_mrole_muser_mrole; +drop index if exists ix_mrole_muser_mrole; -alter table c_user drop constraint fk_c_user_group_id; -drop index ix_c_user_group_id; +alter table if exists mrole_muser drop constraint if exists fk_mrole_muser_muser; +drop index if exists ix_mrole_muser_muser; -alter table oto_user drop constraint fk_oto_user_account_id; +alter table if exists muser drop constraint if exists fk_muser_user_type_id; +drop index if exists ix_muser_user_type_id; -alter table em_user_role drop constraint fk_em_user_role_user_id; -drop index ix_em_user_role_user_id; +alter table if exists mail_user_inbox drop constraint if exists fk_mail_user_inbox_mail_user; +drop index if exists ix_mail_user_inbox_mail_user; -alter table em_user_role drop constraint fk_em_user_role_role_id; -drop index ix_em_user_role_role_id; +alter table if exists mail_user_inbox drop constraint if exists fk_mail_user_inbox_mail_box; +drop index if exists ix_mail_user_inbox_mail_box; -alter table vehicle drop constraint fk_vehicle_truck_ref_id; -drop index ix_vehicle_truck_ref_id; +alter table if exists mail_user_outbox drop constraint if exists fk_mail_user_outbox_mail_user; +drop index if exists ix_mail_user_outbox_mail_user; -alter table vehicle drop constraint fk_vehicle_car_ref_id; -drop index ix_vehicle_car_ref_id; +alter table if exists mail_user_outbox drop constraint if exists fk_mail_user_outbox_mail_box; +drop index if exists ix_mail_user_outbox_mail_box; -alter table vehicle_driver drop constraint fk_vehicle_driver_vehicle_id; -drop index ix_vehicle_driver_vehicle_id; +alter table if exists c_message drop constraint if exists fk_c_message_conversation_id; +drop index if exists ix_c_message_conversation_id; -alter table vehicle_driver drop constraint fk_vehicle_driver_address_id; -drop index ix_vehicle_driver_address_id; +alter table if exists c_message drop constraint if exists fk_c_message_user_id; +drop index if exists ix_c_message_user_id; -alter table warehouses drop constraint fk_warehouses_officezoneid; -drop index ix_warehouses_officezoneid; +alter table if exists mnoc_user_mnoc_role drop constraint if exists fk_mnoc_user_mnoc_role_mnoc_user; +drop index if exists ix_mnoc_user_mnoc_role_mnoc_user; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_wa_1; -drop index ix_warehousesshippingzones_wa_1; +alter table if exists mnoc_user_mnoc_role drop constraint if exists fk_mnoc_user_mnoc_role_mnoc_role; +drop index if exists ix_mnoc_user_mnoc_role_mnoc_role; -alter table warehousesshippingzones drop constraint fk_warehousesshippingzones_zo_2; -drop index ix_warehousesshippingzones_sh_2; +alter table if exists mny_b drop constraint if exists fk_mny_b_a_id; +drop index if exists ix_mny_b_a_id; -alter table sa_wheel drop constraint fk_sa_wheel_tire; -drop index ix_sa_wheel_tire; +alter table if exists mny_b_mny_c drop constraint if exists fk_mny_b_mny_c_mny_b; +drop index if exists ix_mny_b_mny_c_mny_b; -alter table sa_wheel drop constraint fk_sa_wheel_car; -drop index ix_sa_wheel_car; +alter table if exists mny_b_mny_c drop constraint if exists fk_mny_b_mny_c_mny_c; +drop index if exists ix_mny_b_mny_c_mny_c; -alter table with_zero drop constraint fk_with_zero_parent_id; -drop index ix_with_zero_parent_id; +alter table if exists subtopics drop constraint if exists fk_subtopics_mny_topic_1; +drop index if exists ix_subtopics_mny_topic_1; + +alter table if exists subtopics drop constraint if exists fk_subtopics_mny_topic_2; +drop index if exists ix_subtopics_mny_topic_2; + +alter table if exists mp_role drop constraint if exists fk_mp_role_mp_user_id; +drop index if exists ix_mp_role_mp_user_id; + +alter table if exists ms_many_a_many_b drop constraint if exists fk_ms_many_a_many_b_ms_many_a; +drop index if exists ix_ms_many_a_many_b_ms_many_a; + +alter table if exists ms_many_a_many_b drop constraint if exists fk_ms_many_a_many_b_ms_many_b; +drop index if exists ix_ms_many_a_many_b_ms_many_b; + +alter table if exists ms_many_b_many_a drop constraint if exists fk_ms_many_b_many_a_ms_many_b; +drop index if exists ix_ms_many_b_many_a_ms_many_b; + +alter table if exists ms_many_b_many_a drop constraint if exists fk_ms_many_b_many_a_ms_many_a; +drop index if exists ix_ms_many_b_many_a_ms_many_a; + +alter table if exists my_lob_size_join_many drop constraint if exists fk_my_lob_size_join_many_parent_id; +drop index if exists ix_my_lob_size_join_many_parent_id; + +alter table if exists o_cached_bean_country drop constraint if exists fk_o_cached_bean_country_o_cached_bean; +drop index if exists ix_o_cached_bean_country_o_cached_bean; + +alter table if exists o_cached_bean_country drop constraint if exists fk_o_cached_bean_country_o_country; +drop index if exists ix_o_cached_bean_country_o_country; + +alter table if exists o_cached_bean_child drop constraint if exists fk_o_cached_bean_child_cached_bean_id; +drop index if exists ix_o_cached_bean_child_cached_bean_id; + +alter table if exists oengine drop constraint if exists fk_oengine_car_id; + +alter table if exists ogear_box drop constraint if exists fk_ogear_box_car_id; + +alter table if exists oroad_show_msg drop constraint if exists fk_oroad_show_msg_company_id; + +alter table if exists om_ordered_detail drop constraint if exists fk_om_ordered_detail_master_id; +drop index if exists ix_om_ordered_detail_master_id; + +alter table if exists o_order drop constraint if exists fk_o_order_kcustomer_id; +drop index if exists ix_o_order_kcustomer_id; + +alter table if exists o_order_detail drop constraint if exists fk_o_order_detail_order_id; +drop index if exists ix_o_order_detail_order_id; + +alter table if exists o_order_detail drop constraint if exists fk_o_order_detail_product_id; +drop index if exists ix_o_order_detail_product_id; + +alter table if exists s_order_items drop constraint if exists fk_s_order_items_order_uuid; +drop index if exists ix_s_order_items_order_uuid; + +alter table if exists or_order_ship drop constraint if exists fk_or_order_ship_order_id; +drop index if exists ix_or_order_ship_order_id; + +alter table if exists oto_bchild drop constraint if exists fk_oto_bchild_master_id; + +alter table if exists oto_child drop constraint if exists fk_oto_child_master_id; + +alter table if exists oto_cust_address drop constraint if exists fk_oto_cust_address_customer_cid; + +alter table if exists oto_prime_extra drop constraint if exists fk_oto_prime_extra_eid; + +alter table if exists oto_th_many drop constraint if exists fk_oto_th_many_oto_th_top_id; +drop index if exists ix_oto_th_many_oto_th_top_id; + +alter table if exists oto_th_one drop constraint if exists fk_oto_th_one_many_id; + +alter table if exists oto_ubprime_extra drop constraint if exists fk_oto_ubprime_extra_eid; + +alter table if exists oto_uprime_extra drop constraint if exists fk_oto_uprime_extra_eid; + +alter table if exists pfile drop constraint if exists fk_pfile_file_content_id; + +alter table if exists pfile drop constraint if exists fk_pfile_file_content2_id; + +alter table if exists paggview drop constraint if exists fk_paggview_pview_id; + +alter table if exists pallet_location drop constraint if exists fk_pallet_location_zone_sid; +drop index if exists ix_pallet_location_zone_sid; + +alter table if exists parcel_location drop constraint if exists fk_parcel_location_parcelid; + +alter table if exists rawinherit_parent_rawinherit_data drop constraint if exists fk_rawinherit_parent_rawinherit_data_rawinherit_parent; +drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_parent; + +alter table if exists rawinherit_parent_rawinherit_data drop constraint if exists fk_rawinherit_parent_rawinherit_data_rawinherit_data; +drop index if exists ix_rawinherit_parent_rawinherit_data_rawinherit_data; + +alter table if exists parent_person drop constraint if exists fk_parent_person_some_bean_id; +drop index if exists ix_parent_person_some_bean_id; + +alter table if exists parent_person drop constraint if exists fk_parent_person_parent_identifier; +drop index if exists ix_parent_person_parent_identifier; + +alter table if exists c_participation drop constraint if exists fk_c_participation_conversation_id; +drop index if exists ix_c_participation_conversation_id; + +alter table if exists c_participation drop constraint if exists fk_c_participation_user_id; +drop index if exists ix_c_participation_user_id; + +alter table if exists persistent_file_content drop constraint if exists fk_persistent_file_content_persistent_file_id; + +alter table if exists person drop constraint if exists fk_person_default_address_oid; +drop index if exists ix_person_default_address_oid; + +alter table if exists phones drop constraint if exists fk_phones_person_id; +drop index if exists ix_phones_person_id; + +alter table if exists pp_to_ww drop constraint if exists fk_pp_to_ww_pp; +drop index if exists ix_pp_to_ww_pp; + +alter table if exists pp_to_ww drop constraint if exists fk_pp_to_ww_wview; +drop index if exists ix_pp_to_ww_wview; + +alter table if exists question drop constraint if exists fk_question_groupobjectid; +drop index if exists ix_question_groupobjectid; + +alter table if exists r_orders drop constraint if exists fk_r_orders_customer; +drop index if exists ix_r_orders_customer; + +alter table if exists resourcefile drop constraint if exists fk_resourcefile_parentresourcefileid; +drop index if exists ix_resourcefile_parentresourcefileid; + +alter table if exists mt_role drop constraint if exists fk_mt_role_tenant_id; +drop index if exists ix_mt_role_tenant_id; + +alter table if exists mt_role_permission drop constraint if exists fk_mt_role_permission_mt_role; +drop index if exists ix_mt_role_permission_mt_role; + +alter table if exists mt_role_permission drop constraint if exists fk_mt_role_permission_mt_permission; +drop index if exists ix_mt_role_permission_mt_permission; + +alter table if exists f_second drop constraint if exists fk_f_second_first; + +alter table if exists section drop constraint if exists fk_section_article_id; +drop index if exists ix_section_article_id; + +alter table if exists self_parent drop constraint if exists fk_self_parent_parent_id; +drop index if exists ix_self_parent_parent_id; + +alter table if exists self_ref_customer drop constraint if exists fk_self_ref_customer_referred_by_id; +drop index if exists ix_self_ref_customer_referred_by_id; + +alter table if exists self_ref_example drop constraint if exists fk_self_ref_example_parent_id; +drop index if exists ix_self_ref_example_parent_id; + +alter table if exists stockforecast drop constraint if exists fk_stockforecast_inner_report_id; +drop index if exists ix_stockforecast_inner_report_id; + +alter table if exists sub_section drop constraint if exists fk_sub_section_section_id; +drop index if exists ix_sub_section_section_id; + +alter table if exists tevent_many drop constraint if exists fk_tevent_many_event_id; +drop index if exists ix_tevent_many_event_id; + +alter table if exists tevent_one drop constraint if exists fk_tevent_one_event_id; + +alter table if exists t_detail_with_other_namexxxyy drop constraint if exists fk_t_detail_with_other_namexxxyy_master_id; +drop index if exists ix_t_detail_with_other_namexxxyy_master_id; + +alter table if exists ts_detail_two drop constraint if exists fk_ts_detail_two_master_id; +drop index if exists ix_ts_detail_two_master_id; + +alter table if exists twheel drop constraint if exists fk_twheel_owner_plate_no; +drop index if exists ix_twheel_owner_plate_no; + +alter table if exists tire drop constraint if exists fk_tire_wheel; + +alter table if exists trip drop constraint if exists fk_trip_vehicle_driver_id; +drop index if exists ix_trip_vehicle_driver_id; + +alter table if exists trip drop constraint if exists fk_trip_address_id; +drop index if exists ix_trip_address_id; + +alter table if exists type drop constraint if exists fk_type_sub_type_id; +drop index if exists ix_type_sub_type_id; + +alter table if exists ut_detail drop constraint if exists fk_ut_detail_utmaster_id; +drop index if exists ix_ut_detail_utmaster_id; + +alter table if exists uutwo drop constraint if exists fk_uutwo_master_id; +drop index if exists ix_uutwo_master_id; + +alter table if exists c_user drop constraint if exists fk_c_user_group_id; +drop index if exists ix_c_user_group_id; + +alter table if exists oto_user drop constraint if exists fk_oto_user_account_id; + +alter table if exists em_user_role drop constraint if exists fk_em_user_role_user_id; +drop index if exists ix_em_user_role_user_id; + +alter table if exists em_user_role drop constraint if exists fk_em_user_role_role_id; +drop index if exists ix_em_user_role_role_id; + +alter table if exists vehicle drop constraint if exists fk_vehicle_car_ref_id; +drop index if exists ix_vehicle_car_ref_id; + +alter table if exists vehicle drop constraint if exists fk_vehicle_truck_ref_id; +drop index if exists ix_vehicle_truck_ref_id; + +alter table if exists vehicle_driver drop constraint if exists fk_vehicle_driver_vehicle_id; +drop index if exists ix_vehicle_driver_vehicle_id; + +alter table if exists vehicle_driver drop constraint if exists fk_vehicle_driver_address_id; +drop index if exists ix_vehicle_driver_address_id; + +alter table if exists warehouses drop constraint if exists fk_warehouses_officezoneid; +drop index if exists ix_warehouses_officezoneid; + +alter table if exists warehousesshippingzones drop constraint if exists fk_warehousesshippingzones_warehouses; +drop index if exists ix_warehousesshippingzones_warehouses; + +alter table if exists warehousesshippingzones drop constraint if exists fk_warehousesshippingzones_zones; +drop index if exists ix_warehousesshippingzones_zones; + +alter table if exists sa_wheel drop constraint if exists fk_sa_wheel_tire; +drop index if exists ix_sa_wheel_tire; + +alter table if exists sa_wheel drop constraint if exists fk_sa_wheel_car; +drop index if exists ix_sa_wheel_car; + +alter table if exists g_who_props_otm drop constraint if exists fk_g_who_props_otm_who_created_id; +drop index if exists ix_g_who_props_otm_who_created_id; + +alter table if exists g_who_props_otm drop constraint if exists fk_g_who_props_otm_who_modified_id; +drop index if exists ix_g_who_props_otm_who_modified_id; + +alter table if exists with_zero drop constraint if exists fk_with_zero_parent_id; +drop index if exists ix_with_zero_parent_id; drop table if exists asimple_bean cascade; @@ -342,11 +575,15 @@ drop table if exists bar cascade; drop table if exists oto_account cascade; -drop table if exists o_address cascade; +drop table if exists addr cascade; drop table if exists address cascade; -drop table if exists animals cascade; +drop table if exists o_address cascade; + +drop table if exists album cascade; + +drop table if exists animal cascade; drop table if exists animal_shelter cascade; @@ -364,6 +601,16 @@ drop table if exists bbookmark_user cascade; drop table if exists bsimple_with_gen cascade; +drop table if exists bsite cascade; + +drop table if exists bsite_user cascade; + +drop table if exists bsite_user_b cascade; + +drop table if exists bsite_user_c cascade; + +drop table if exists buser cascade; + drop table if exists bwith_qident cascade; drop table if exists basic_joda_entity cascade; @@ -373,6 +620,8 @@ drop table if exists bean_with_time_zone cascade; drop table if exists drel_booking cascade; drop sequence if exists drel_booking_seq; +drop table if exists cinh_root cascade; + drop table if exists ckey_assoc cascade; drop table if exists ckey_detail cascade; @@ -393,6 +642,12 @@ drop table if exists sp_car_car_wheels cascade; drop table if exists car_accessory cascade; +drop table if exists car_fuse cascade; + +drop table if exists category cascade; + +drop table if exists child_person cascade; + drop table if exists configuration cascade; drop table if exists configurations cascade; @@ -407,16 +662,62 @@ drop table if exists c_conversation cascade; drop table if exists o_country cascade; +drop table if exists cover cascade; + drop table if exists o_customer cascade; +drop table if exists dcredit cascade; + +drop table if exists dcredit_drol cascade; + drop table if exists dexh_entity cascade; drop table if exists dperson cascade; +drop table if exists drol cascade; + +drop table if exists drot cascade; + +drop table if exists drot_drol cascade; + drop table if exists rawinherit_data cascade; +drop table if exists dfk_cascade cascade; + +drop table if exists dfk_cascade_one cascade; + +drop table if exists dfk_none cascade; + +drop table if exists dfk_none_via_join cascade; + +drop table if exists dfk_one cascade; + +drop table if exists dfk_set_null cascade; + +drop table if exists doc cascade; + +drop table if exists doc_link cascade; + +drop table if exists doc_link_draft cascade; + +drop table if exists doc_draft cascade; + +drop table if exists document cascade; + +drop table if exists document_draft cascade; + +drop table if exists document_media cascade; + +drop table if exists document_media_draft cascade; + +drop table if exists earray_bean cascade; + +drop table if exists earray_set_bean cascade; + drop table if exists e_basic cascade; +drop table if exists ebasic_change_log cascade; + drop table if exists ebasic_clob cascade; drop table if exists ebasic_clob_fetch_eager cascade; @@ -429,12 +730,20 @@ drop table if exists e_basicenc_bin cascade; drop table if exists e_basic_enum_id cascade; +drop table if exists e_basic_eni cascade; + +drop table if exists ebasic_hstore cascade; + +drop table if exists ebasic_json_list cascade; + drop table if exists ebasic_json_map cascade; drop table if exists ebasic_json_map_blob cascade; drop table if exists ebasic_json_map_clob cascade; +drop table if exists ebasic_json_map_detail cascade; + drop table if exists ebasic_json_map_json_b cascade; drop table if exists ebasic_json_map_varchar cascade; @@ -447,14 +756,26 @@ drop table if exists ebasic_json_node_json_b cascade; drop table if exists ebasic_json_node_varchar cascade; +drop table if exists ebasic_json_unmapped cascade; + drop table if exists e_basic_ndc cascade; +drop table if exists ebasic_no_sdchild cascade; + +drop table if exists ebasic_sdchild cascade; + +drop table if exists ebasic_soft_delete cascade; + drop table if exists e_basicver cascade; drop table if exists e_basic_withlife cascade; drop table if exists e_basicverucon cascade; +drop table if exists e_col_ab cascade; + +drop table if exists ecustom_id cascade; + drop table if exists eemb_inner cascade; drop table if exists eemb_outer cascade; @@ -477,12 +798,42 @@ drop table if exists eopt_one_c cascade; drop table if exists eperson cascade; +drop table if exists e_person_online cascade; + drop table if exists esimple cascade; +drop table if exists esoft_del_book cascade; + +drop table if exists esoft_del_book_esoft_del_user cascade; + +drop table if exists esoft_del_down cascade; + +drop table if exists esoft_del_mid cascade; + +drop table if exists esoft_del_one_a cascade; + +drop table if exists esoft_del_one_b cascade; + +drop table if exists esoft_del_role cascade; + +drop table if exists esoft_del_role_esoft_del_user cascade; + +drop table if exists esoft_del_top cascade; + +drop table if exists esoft_del_up cascade; + +drop table if exists esoft_del_user cascade; + +drop table if exists esoft_del_user_esoft_del_role cascade; + +drop table if exists esome_convert_type cascade; + drop table if exists esome_type cascade; drop table if exists etrans_many cascade; +drop table if exists rawinherit_uncle cascade; + drop table if exists evanilla_collection cascade; drop table if exists evanilla_collection_detail cascade; @@ -495,6 +846,8 @@ drop table if exists td_child cascade; drop table if exists td_parent cascade; +drop table if exists empl cascade; + drop table if exists feature_desc cascade; drop table if exists f_first cascade; @@ -504,12 +857,49 @@ drop table if exists foo cascade; drop table if exists gen_key_identity cascade; drop table if exists gen_key_sequence cascade; -drop sequence if exists seq; +drop sequence if exists SEQ; drop table if exists gen_key_table cascade; +drop table if exists grand_parent_person cascade; + +drop table if exists survey_group cascade; + drop table if exists c_group cascade; +drop table if exists he_doc cascade; + +drop trigger if exists hx_link_history_upd on hx_link cascade; +drop function if exists hx_link_history_version(); + +drop view hx_link_with_history; +alter table hx_link drop column sys_period; +drop table hx_link_history; + +drop table if exists hx_link cascade; + +drop table if exists hx_link_doc cascade; + +drop table if exists hi_doc cascade; + +drop trigger if exists hi_link_history_upd on hi_link cascade; +drop function if exists hi_link_history_version(); + +drop view hi_link_with_history; +alter table hi_link drop column sys_period; +drop table hi_link_history; + +drop table if exists hi_link cascade; + +drop trigger if exists hi_link_doc_history_upd on hi_link_doc cascade; +drop function if exists hi_link_doc_history_version(); + +drop view hi_link_doc_with_history; +alter table hi_link_doc drop column sys_period; +drop table hi_link_doc_history; + +drop table if exists hi_link_doc cascade; + drop table if exists imrelated cascade; drop table if exists imroot cascade; @@ -529,6 +919,20 @@ drop sequence if exists drel_invoice_seq; drop table if exists item cascade; +drop table if exists monkey cascade; + +drop table if exists trainer cascade; + +drop table if exists trainer_monkey cascade; + +drop table if exists troop cascade; + +drop table if exists troop_monkey cascade; + +drop table if exists l2_cldf_reset_bean cascade; + +drop table if exists l2_cldf_reset_bean_child cascade; + drop table if exists level1 cascade; drop table if exists level1_level4 cascade; @@ -543,6 +947,17 @@ drop table if exists level3 cascade; drop table if exists level4 cascade; +drop trigger if exists link_history_upd on link cascade; +drop function if exists link_history_version(); + +drop view link_with_history; +alter table link drop column sys_period; +drop table link_history; + +drop table if exists link cascade; + +drop table if exists link_draft cascade; + drop table if exists la_attr_value cascade; drop table if exists la_attr_value_attribute cascade; @@ -569,6 +984,14 @@ drop table if exists muser cascade; drop table if exists muser_type cascade; +drop table if exists mail_box cascade; + +drop table if exists mail_user cascade; + +drop table if exists mail_user_inbox cascade; + +drop table if exists mail_user_outbox cascade; + drop table if exists map_super_actual cascade; drop table if exists c_message cascade; @@ -579,10 +1002,30 @@ drop table if exists mnoc_user cascade; drop table if exists mnoc_user_mnoc_role cascade; +drop table if exists mny_a cascade; + +drop table if exists mny_b cascade; + +drop table if exists mny_b_mny_c cascade; + +drop table if exists mny_c cascade; + +drop table if exists mny_topic cascade; + +drop table if exists subtopics cascade; + drop table if exists mp_role cascade; drop table if exists mp_user cascade; +drop table if exists ms_many_a cascade; + +drop table if exists ms_many_a_many_b cascade; + +drop table if exists ms_many_b cascade; + +drop table if exists ms_many_b_many_a cascade; + drop table if exists my_lob_size cascade; drop table if exists my_lob_size_join_many cascade; @@ -595,12 +1038,24 @@ drop table if exists o_cached_bean_country cascade; drop table if exists o_cached_bean_child cascade; +drop table if exists o_cached_natkey cascade; + +drop table if exists o_cached_natkey3 cascade; + drop table if exists ocar cascade; +drop table if exists ocompany cascade; + drop table if exists oengine cascade; drop table if exists ogear_box cascade; +drop table if exists oroad_show_msg cascade; + +drop table if exists om_ordered_detail cascade; + +drop table if exists om_ordered_master cascade; + drop table if exists o_order cascade; drop table if exists o_order_detail cascade; @@ -611,10 +1066,38 @@ drop table if exists s_order_items cascade; drop table if exists or_order_ship cascade; +drop table if exists organisation cascade; + +drop table if exists oto_bchild cascade; + +drop table if exists oto_bmaster cascade; + drop table if exists oto_child cascade; +drop table if exists oto_cust cascade; + +drop table if exists oto_cust_address cascade; + drop table if exists oto_master cascade; +drop table if exists oto_prime cascade; + +drop table if exists oto_prime_extra cascade; + +drop table if exists oto_th_many cascade; + +drop table if exists oto_th_one cascade; + +drop table if exists oto_th_top cascade; + +drop table if exists oto_ubprime cascade; + +drop table if exists oto_ubprime_extra cascade; + +drop table if exists oto_uprime cascade; + +drop table if exists oto_uprime_extra cascade; + drop table if exists pfile cascade; drop table if exists pfile_content cascade; @@ -629,7 +1112,9 @@ drop table if exists parcel_location cascade; drop table if exists rawinherit_parent cascade; -drop table if exists rawinherit_parent_rawinherit_dat cascade; +drop table if exists rawinherit_parent_rawinherit_data cascade; + +drop table if exists parent_person cascade; drop table if exists c_participation cascade; @@ -645,12 +1130,16 @@ drop table if exists person cascade; drop table if exists phones cascade; +drop table if exists primary_revision cascade; + drop table if exists o_product cascade; drop table if exists pp cascade; drop table if exists pp_to_ww cascade; +drop table if exists question cascade; + drop table if exists rcustomer cascade; drop table if exists r_orders cascade; @@ -659,12 +1148,12 @@ drop table if exists region cascade; drop table if exists resourcefile cascade; +drop table if exists em_role cascade; + drop table if exists mt_role cascade; drop table if exists mt_role_permission cascade; -drop table if exists em_role cascade; - drop table if exists f_second cascade; drop table if exists section cascade; @@ -689,10 +1178,18 @@ drop table if exists sub_section cascade; drop table if exists sub_type cascade; +drop table if exists survey cascade; + drop table if exists tbytes_only cascade; drop table if exists tcar cascade; +drop table if exists tevent cascade; + +drop table if exists tevent_many cascade; + +drop table if exists tevent_one cascade; + drop table if exists tint_root cascade; drop table if exists tjoda_entity cascade; @@ -719,18 +1216,22 @@ drop table if exists twith_pre_insert cascade; drop table if exists mt_tenant cascade; -drop table if exists sa_tire cascade; -drop sequence if exists sa_tire_seq; +drop table if exists test_annotation_base_entity cascade; drop table if exists tire cascade; drop sequence if exists tire_seq; +drop table if exists sa_tire cascade; +drop sequence if exists sa_tire_seq; + drop table if exists trip cascade; drop table if exists truck_ref cascade; drop table if exists type cascade; +drop table if exists tz_bean cascade; + drop table if exists ut_detail cascade; drop table if exists ut_master cascade; @@ -739,11 +1240,20 @@ drop table if exists uuone cascade; drop table if exists uutwo cascade; -drop table if exists em_user cascade; +drop trigger if exists c_user_history_upd on c_user cascade; +drop function if exists c_user_history_version(); + +drop view c_user_with_history; +alter table c_user drop column sys_period; +drop table c_user_history; + +drop table if exists c_user cascade; drop table if exists tx_user cascade; -drop table if exists c_user cascade; +drop table if exists g_user cascade; + +drop table if exists em_user cascade; drop table if exists oto_user cascade; @@ -760,11 +1270,13 @@ drop table if exists warehousesshippingzones cascade; drop table if exists sa_wheel cascade; drop sequence if exists sa_wheel_seq; +drop table if exists wheel cascade; +drop sequence if exists wheel_seq; + drop table if exists sp_car_wheel cascade; drop sequence if exists sp_car_wheel_seq; -drop table if exists wheel cascade; -drop sequence if exists wheel_seq; +drop table if exists g_who_props_otm cascade; drop table if exists with_zero cascade; @@ -774,3 +1286,5 @@ drop table if exists wview cascade; drop table if exists zones cascade; +drop index if exists ix_contact_last_name_first_name; +drop index if exists ix_e_basic_name; From 4f327c27519a04b5731b3b19be653cd2ef597ed5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 20:47:48 +1300 Subject: [PATCH 0174/1036] No effective change - default h2 platform for testing --- src/test/resources/ebean.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 86880510b..3b048c4c2 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -19,7 +19,7 @@ ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests -datasource.default=mysql +datasource.default=h2 ebean.autoReadOnlyDataSource=true From 2042bdf29a78597900015f852ac360a3f54fc73d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 8 Mar 2018 23:23:50 +1300 Subject: [PATCH 0175/1036] #1342 - Refactor and rename DbTypeConfig to Platform config to support multi-platform db migration --- pom.xml | 2 +- .../java/io/ebean/config/DbTypeConfig.java | 124 ------- .../java/io/ebean/config/PlatformConfig.java | 335 ++++++++++++++++++ .../io/ebean/config/PropertiesWrapper.java | 35 +- .../java/io/ebean/config/ServerConfig.java | 234 ++++-------- .../config/dbplatform/DatabasePlatform.java | 9 +- .../dbplatform/DbPlatformTypeMapping.java | 4 +- .../sqlserver/SqlServerBasePlatform.java | 4 +- .../dbmigration/DefaultDbMigration.java | 19 +- .../server/core/DefaultContainer.java | 2 +- .../server/core/InternalConfiguration.java | 2 +- .../server/type/DefaultTypeManager.java | 3 +- .../ebean/config/DbMigrationConfigTest.java | 6 +- .../io/ebean/config/DocStoreConfigTest.java | 10 +- .../config/MatchingNamingConventionTest.java | 2 +- .../ebean/config/PropertiesWrapperTest.java | 10 +- .../io/ebean/config/ServerConfigTest.java | 2 +- .../dbplatform/DatabasePlatformTest.java | 8 +- .../config/dbplatform/MySqlPlatformTest.java | 9 +- .../config/dbplatform/OraclePlatformTest.java | 9 +- .../dbplatform/PostgresPlatformTest.java | 4 +- 21 files changed, 491 insertions(+), 342 deletions(-) delete mode 100644 src/main/java/io/ebean/config/DbTypeConfig.java create mode 100644 src/main/java/io/ebean/config/PlatformConfig.java diff --git a/pom.xml b/pom.xml index 9d9eee542..f5e65dff5 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.14.4-SNAPSHOT + 11.15.1-SNAPSHOT jar ebean diff --git a/src/main/java/io/ebean/config/DbTypeConfig.java b/src/main/java/io/ebean/config/DbTypeConfig.java deleted file mode 100644 index 3a48dbd32..000000000 --- a/src/main/java/io/ebean/config/DbTypeConfig.java +++ /dev/null @@ -1,124 +0,0 @@ -package io.ebean.config; - -import io.ebean.config.dbplatform.DbType; -import io.ebean.config.dbplatform.IdType; -import io.ebean.annotation.Platform; - -import java.util.ArrayList; -import java.util.List; - -/** - * Configuration for DB types such as UUID, Geometry etc. - */ -public class DbTypeConfig { - - /** - * The Geometry SRID value (default 4326). - */ - private int geometrySRID = 4326; - - /** - * Set for DB's that support both Sequence and Identity (and the default choice is not desired). - */ - private IdType idType; - - /** - * Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres). - */ - private ServerConfig.DbUuid dbUuid = ServerConfig.DbUuid.AUTO_VARCHAR; - - /** - * Modify the default mapping of standard types such as default precision for DECIMAL etc. - */ - private List customDbTypeMappings = new ArrayList<>(); - - /** - * Return the Geometry SRID. - */ - public int getGeometrySRID() { - return geometrySRID; - } - - /** - * Set the Geometry SRID. - */ - public void setGeometrySRID(int geometrySRID) { - this.geometrySRID = geometrySRID; - } - - /** - * Return the DB type used to store UUID. - */ - public ServerConfig.DbUuid getDbUuid() { - return dbUuid; - } - - /** - * Set the DB type used to store UUID. - */ - public void setDbUuid(ServerConfig.DbUuid dbUuid) { - this.dbUuid = dbUuid; - } - - /** - * Return the IdType to use (or null for the default choice). - */ - public IdType getIdType() { - return idType; - } - - /** - * Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired). - */ - public void setIdType(IdType idType) { - this.idType = idType; - } - - /** - * Add a custom type mapping. - *

- *

{@code
-   *
-   *   // set the default mapping for BigDecimal.class/decimal
-   *   serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
-   *
-   *   // set the default mapping for String.class/varchar but only for Postgres
-   *   serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
-   *
-   * }
- * - * @param type The DB type this mapping should apply to - * @param columnDefinition The column definition that should be used - * @param platform Optionally specify the platform this mapping should apply to. - */ - public void addCustomMapping(DbType type, String columnDefinition, Platform platform) { - customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform)); - } - - /** - * Add a custom type mapping that applies to all platforms. - *

- *

{@code
-   *
-   *   // set the default mapping for BigDecimal/decimal
-   *   serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
-   *
-   *   // set the default mapping for String/varchar
-   *   serverConfig.addCustomMapping(DbType.VARCHAR, "text");
-   *
-   * }
- * - * @param type The DB type this mapping should apply to - * @param columnDefinition The column definition that should be used - */ - public void addCustomMapping(DbType type, String columnDefinition) { - customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition)); - } - - /** - * Return the list of custom type mappings. - */ - public List getCustomTypeMappings() { - return customDbTypeMappings; - } -} diff --git a/src/main/java/io/ebean/config/PlatformConfig.java b/src/main/java/io/ebean/config/PlatformConfig.java new file mode 100644 index 000000000..9a0ada54b --- /dev/null +++ b/src/main/java/io/ebean/config/PlatformConfig.java @@ -0,0 +1,335 @@ +package io.ebean.config; + +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DbType; +import io.ebean.config.dbplatform.IdType; +import io.ebean.util.StringHelper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Configuration for DB types such as UUID, Geometry etc. + */ +public class PlatformConfig { + + private boolean allQuotedIdentifiers; + + /** + * The database boolean true value (typically either 1, T, or Y). + */ + private String databaseBooleanTrue; + + /** + * The database boolean false value (typically either 0, F or N). + */ + private String databaseBooleanFalse; + + /** + * For DB's using sequences this is the number of sequence values prefetched. + */ + private int databaseSequenceBatchSize = 20; + + /** + * Set for DB's that support both Sequence and Identity (and the default choice is not desired). + */ + private IdType idType; + + /** + * The Geometry SRID value (default 4326). + */ + private int geometrySRID = 4326; + + /** + * Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres). + */ + private DbUuid dbUuid = DbUuid.AUTO_VARCHAR; + + /** + * Modify the default mapping of standard types such as default precision for DECIMAL etc. + */ + private List customDbTypeMappings = new ArrayList<>(); + + /** + * Construct with defaults. + */ + public PlatformConfig() { + + } + + /** + * Construct based on given config - typically for DbMigration generation with many platforms. + */ + public PlatformConfig(PlatformConfig platformConfig) { + this.databaseBooleanFalse = platformConfig.databaseBooleanFalse; + this.databaseBooleanTrue = platformConfig.databaseBooleanTrue; + this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize; + this.idType = platformConfig.idType; + this.geometrySRID = platformConfig.geometrySRID; + this.dbUuid = platformConfig.dbUuid; + } + + /** + * Return true if all DB column and table names should use quoted identifiers. + */ + public boolean isAllQuotedIdentifiers() { + return allQuotedIdentifiers; + } + + /** + * Set to true if all DB column and table names should use quoted identifiers. + */ + public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) { + this.allQuotedIdentifiers = allQuotedIdentifiers; + } + + /** + * Return a value used to represent TRUE in the database. + *

+ * This is used for databases that do not support boolean natively. + *

+ *

+ * The value returned is either a Integer or a String (e.g. "1", or "T"). + *

+ */ + public String getDatabaseBooleanTrue() { + return databaseBooleanTrue; + } + + /** + * Set the value to represent TRUE in the database. + *

+ * This is used for databases that do not support boolean natively. + *

+ *

+ * The value set is either a Integer or a String (e.g. "1", or "T"). + *

+ */ + public void setDatabaseBooleanTrue(String databaseBooleanTrue) { + this.databaseBooleanTrue = databaseBooleanTrue; + } + + /** + * Return a value used to represent FALSE in the database. + */ + public String getDatabaseBooleanFalse() { + return databaseBooleanFalse; + } + + /** + * Set the value used to represent FALSE in the database. + */ + public void setDatabaseBooleanFalse(String databaseBooleanFalse) { + this.databaseBooleanFalse = databaseBooleanFalse; + } + + /** + * Return the number of DB sequence values that should be preallocated. + */ + public int getDatabaseSequenceBatchSize() { + return databaseSequenceBatchSize; + } + + /** + * Set the number of DB sequence values that should be preallocated. + */ + public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) { + this.databaseSequenceBatchSize = databaseSequenceBatchSize; + } + + /** + * Return the Geometry SRID. + */ + public int getGeometrySRID() { + return geometrySRID; + } + + /** + * Set the Geometry SRID. + */ + public void setGeometrySRID(int geometrySRID) { + this.geometrySRID = geometrySRID; + } + + /** + * Return the DB type used to store UUID. + */ + public DbUuid getDbUuid() { + return dbUuid; + } + + /** + * Set the DB type used to store UUID. + */ + public void setDbUuid(DbUuid dbUuid) { + this.dbUuid = dbUuid; + } + + /** + * Return the IdType to use (or null for the default choice). + */ + public IdType getIdType() { + return idType; + } + + /** + * Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired). + */ + public void setIdType(IdType idType) { + this.idType = idType; + } + + /** + * Add a custom type mapping. + *

+ *

{@code
+   *
+   *   // set the default mapping for BigDecimal.class/decimal
+   *   serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
+   *
+   *   // set the default mapping for String.class/varchar but only for Postgres
+   *   serverConfig.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
+   *
+   * }
+ * + * @param type The DB type this mapping should apply to + * @param columnDefinition The column definition that should be used + * @param platform Optionally specify the platform this mapping should apply to. + */ + public void addCustomMapping(DbType type, String columnDefinition, Platform platform) { + customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform)); + } + + /** + * Add a custom type mapping that applies to all platforms. + *

+ *

{@code
+   *
+   *   // set the default mapping for BigDecimal/decimal
+   *   serverConfig.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
+   *
+   *   // set the default mapping for String/varchar
+   *   serverConfig.addCustomMapping(DbType.VARCHAR, "text");
+   *
+   * }
+ * + * @param type The DB type this mapping should apply to + * @param columnDefinition The column definition that should be used + */ + public void addCustomMapping(DbType type, String columnDefinition) { + customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition)); + } + + /** + * Return the list of custom type mappings. + */ + public List getCustomTypeMappings() { + return customDbTypeMappings; + } + + public void loadSettings(PropertiesWrapper p) { + + idType = p.getEnum(IdType.class, "idType", idType); + databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize); + databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue); + databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse); + + DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null); + if (dbUuid != null) { + setDbUuid(dbUuid); + } + if (p.getBoolean("uuidStoreAsBinary", false)) { + setDbUuid(DbUuid.BINARY); + } + + int srid = p.getInt("geometrySRID", 0); + if (srid > 0) { + setGeometrySRID(srid); + } + + // Mapping is specified in the form: BOOLEAN=int(1);BIT=int(1); + String mapping = p.get("mapping"); + if (mapping != null && !mapping.isEmpty()) { + Map map = StringHelper.delimitedToMap(mapping, ";", "="); + for (Entry entry : map.entrySet()) { + addCustomMapping(DbType.valueOf(entry.getKey()), entry.getValue()); + } + } + + boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers); + if (quotedIdentifiers != allQuotedIdentifiers) { + // potentially also set to use matching naming convention + setAllQuotedIdentifiers(quotedIdentifiers); + } + } + + /** + * Specify how UUID is stored. + */ + public enum DbUuid { + + + /** + * Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40). + */ + AUTO_VARCHAR(true, false, false), + + /** + * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16). + */ + AUTO_BINARY(true, true, false), + + /** + * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing. + */ + AUTO_BINARY_OPTIMIZED(true, true, true), + + /** + * Store using DB VARCHAR(40). + */ + VARCHAR(false, false, false), + + /** + * Store using DB BINARY(16). + */ + BINARY(false, true, false), + + /** + * Store using DB BINARY(16). + */ + BINARY_OPTIMIZED(false, true, true); + + boolean nativeType; + boolean binary; + boolean binaryOptimized; + + DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) { + this.nativeType = nativeType; + this.binary = binary; + this.binaryOptimized = binaryOptimized; + } + + /** + * Return true if native UUID type is preferred. + */ + public boolean useNativeType() { + return nativeType; + } + + /** + * Return true if BINARY(16) storage is preferred over VARCHAR(40). + */ + public boolean useBinary() { + return binary; + } + + /** + * Return true, if optimized packing should be used. + */ + public boolean useBinaryOptimized() { + return binaryOptimized; + } + } +} diff --git a/src/main/java/io/ebean/config/PropertiesWrapper.java b/src/main/java/io/ebean/config/PropertiesWrapper.java index a3d9f0364..c739a8dda 100644 --- a/src/main/java/io/ebean/config/PropertiesWrapper.java +++ b/src/main/java/io/ebean/config/PropertiesWrapper.java @@ -10,20 +10,23 @@ public class PropertiesWrapper { protected final String serverName; + private final ClassLoadConfig classLoadConfig; + /** * Construct with a prefix, serverName and properties. */ - public PropertiesWrapper(String prefix, String serverName, Properties properties) { + public PropertiesWrapper(String prefix, String serverName, Properties properties, ClassLoadConfig classLoadConfig) { this.serverName = serverName; this.prefix = prefix; this.properties = properties; + this.classLoadConfig = classLoadConfig; } /** * Construct without prefix of serverName. */ - public PropertiesWrapper(Properties properties) { - this(null, null, properties); + public PropertiesWrapper(Properties properties, ClassLoadConfig classLoadConfig) { + this(null, null, properties, classLoadConfig); } /** @@ -115,4 +118,30 @@ public class PropertiesWrapper { return (level == null) ? defaultValue : Enum.valueOf(enumType, level.toUpperCase()); } + /** + * Return the instance to use (can be null) for the given plugin. + * + * @param pluginType the type of plugin + * @param key properties key + * @param instance existing instance + */ + public T createInstance(Class pluginType, String key, T instance) { + + if (instance != null) { + return instance; + } + String classname = get(key, null); + return createInstance(pluginType, classname); + } + + /** + * Return the instance to use (can be null) for the given plugin. + * + * @param pluginType the type of plugin + * @param classname the implementation class as per properties + */ + @SuppressWarnings("unchecked") + public T createInstance(Class pluginType, String classname) { + return classname == null ? null : (T) classLoadConfig.newInstance(classname); + } } diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index f32473ec6..f4b59039c 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -183,16 +183,6 @@ public class ServerConfig { */ private DatabasePlatform databasePlatform; - /** - * The preferred IdType (to override the default Platform type). - */ - private IdType idType; - - /** - * For DB's using sequences this is the number of sequence values prefetched. - */ - private int databaseSequenceBatchSize = 20; - /** * JDBC fetchSize hint when using findList. Defaults to 0 leaving it up to the JDBC driver. */ @@ -330,18 +320,6 @@ public class ServerConfig { */ private String dataSourceJndiName; - /** - * The database boolean true value (typically either 1, T, or Y). - */ - private String databaseBooleanTrue; - - /** - * The database boolean false value (typically either 0, F or N). - */ - private String databaseBooleanFalse; - - private boolean allQuotedIdentifiers; - /** * The naming convention. */ @@ -368,9 +346,9 @@ public class ServerConfig { private boolean updatesDeleteMissingChildren = true; /** - * Database type configuration. + * Database platform configuration. */ - private DbTypeConfig dbTypeConfig = new DbTypeConfig(); + private PlatformConfig platformConfig = new PlatformConfig(); /** * The UUID version to use. @@ -946,7 +924,7 @@ public class ServerConfig { *

*/ public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) { - this.databaseSequenceBatchSize = databaseSequenceBatchSize; + platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize); } /** @@ -1128,14 +1106,14 @@ public class ServerConfig { * Return the Geometry SRID. */ public int getGeometrySRID() { - return dbTypeConfig.getGeometrySRID(); + return platformConfig.getGeometrySRID(); } /** * Set the Geometry SRID. */ public void setGeometrySRID(int geometrySRID) { - dbTypeConfig.setGeometrySRID(geometrySRID); + platformConfig.setGeometrySRID(geometrySRID); } /** @@ -1425,15 +1403,21 @@ public class ServerConfig { * Return true if all DB column and table names should use quoted identifiers. */ public boolean isAllQuotedIdentifiers() { - return allQuotedIdentifiers; + return platformConfig.isAllQuotedIdentifiers(); } /** * Set to true if all DB column and table names should use quoted identifiers. */ public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) { - this.allQuotedIdentifiers = allQuotedIdentifiers; - if (allQuotedIdentifiers && namingConvention instanceof UnderscoreNamingConvention) { + platformConfig.setAllQuotedIdentifiers(allQuotedIdentifiers); + if (allQuotedIdentifiers) { + adjustNamingConventionForAllQuoted(); + } + } + + private void adjustNamingConventionForAllQuoted() { + if (namingConvention instanceof UnderscoreNamingConvention) { // we need to use matching naming convention this.namingConvention = new MatchingNamingConvention(); } @@ -1648,7 +1632,7 @@ public class ServerConfig { *

*/ public String getDatabaseBooleanTrue() { - return databaseBooleanTrue; + return platformConfig.getDatabaseBooleanTrue(); } /** @@ -1661,7 +1645,7 @@ public class ServerConfig { *

*/ public void setDatabaseBooleanTrue(String databaseTrue) { - this.databaseBooleanTrue = databaseTrue; + platformConfig.setDatabaseBooleanTrue(databaseTrue); } /** @@ -1674,7 +1658,7 @@ public class ServerConfig { *

*/ public String getDatabaseBooleanFalse() { - return databaseBooleanFalse; + return platformConfig.getDatabaseBooleanFalse(); } /** @@ -1687,14 +1671,14 @@ public class ServerConfig { *

*/ public void setDatabaseBooleanFalse(String databaseFalse) { - this.databaseBooleanFalse = databaseFalse; + this.platformConfig.setDatabaseBooleanFalse(databaseFalse); } /** * Return the number of DB sequence values that should be preallocated. */ public int getDatabaseSequenceBatchSize() { - return databaseSequenceBatchSize; + return platformConfig.getDatabaseSequenceBatchSize(); } /** @@ -1713,7 +1697,7 @@ public class ServerConfig { *

*/ public void setDatabaseSequenceBatch(int databaseSequenceBatchSize) { - this.databaseSequenceBatchSize = databaseSequenceBatchSize; + this.platformConfig.setDatabaseSequenceBatchSize(databaseSequenceBatchSize); } /** @@ -1769,14 +1753,14 @@ public class ServerConfig { * Return the preferred DB platform IdType. */ public IdType getIdType() { - return idType; + return platformConfig.getIdType(); } /** * Set the preferred DB platform IdType. */ public void setIdType(IdType idType) { - this.idType = idType; + this.platformConfig.setIdType(idType); } /** @@ -1889,15 +1873,22 @@ public class ServerConfig { /** * Return the configuration for DB types (such as UUID and custom mappings). */ - public DbTypeConfig getDbTypeConfig() { - return dbTypeConfig; + public PlatformConfig getPlatformConfig() { + return platformConfig; + } + + /** + * Set the configuration for DB platform (such as UUID and custom mappings). + */ + public void setPlatformConfig(PlatformConfig platformConfig) { + this.platformConfig = platformConfig; } /** * Set the DB type used to store UUID. */ - public void setDbUuid(DbUuid dbUuid) { - this.dbTypeConfig.setDbUuid(dbUuid); + public void setDbUuid(PlatformConfig.DbUuid dbUuid) { + this.platformConfig.setDbUuid(dbUuid); } /** @@ -2353,7 +2344,7 @@ public class ServerConfig { * @param platform Optionally specify the platform this mapping should apply to. */ public void addCustomMapping(DbType type, String columnDefinition, Platform platform) { - dbTypeConfig.addCustomMapping(type, columnDefinition, platform); + platformConfig.addCustomMapping(type, columnDefinition, platform); } /** @@ -2373,7 +2364,7 @@ public class ServerConfig { * @param columnDefinition The column definition that should be used */ public void addCustomMapping(DbType type, String columnDefinition) { - dbTypeConfig.addCustomMapping(type, columnDefinition); + platformConfig.addCustomMapping(type, columnDefinition); } /** @@ -2660,7 +2651,7 @@ public class ServerConfig { */ private void configureFromProperties() { autoConfiguration(); - PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties); + PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties, classLoadConfig); loadSettings(p); } @@ -2695,34 +2686,6 @@ public class ServerConfig { return properties; } - /** - * Return the instance to use (can be null) for the given plugin. - * - * @param properties the properties - * @param pluginType the type of plugin - * @param key properties key - * @param instance existing instance - */ - protected T createInstance(PropertiesWrapper properties, Class pluginType, String key, T instance) { - - if (instance != null) { - return instance; - } - String classname = properties.get(key, null); - return createInstance(pluginType, classname); - } - - /** - * Return the instance to use (can be null) for the given plugin. - * - * @param pluginType the type of plugin - * @param classname the implementation class as per properties - */ - @SuppressWarnings("unchecked") - protected T createInstance(Class pluginType, String classname) { - return classname == null ? null : (T) classLoadConfig.newInstance(classname); - } - /** * loads the data source settings to preserve existing behaviour. IMHO, if someone has set the datasource config already, * they don't want the settings to be reloaded and reset. This allows a descending class to override this behaviour and prevent it @@ -2756,11 +2719,9 @@ public class ServerConfig { profilingConfig.loadSettings(p, name); migrationConfig.loadSettings(p, name); - - boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers); - if (quotedIdentifiers != allQuotedIdentifiers) { - // potentially also set to use matching naming convention - setAllQuotedIdentifiers(quotedIdentifiers); + platformConfig.loadSettings(p); + if (platformConfig.isAllQuotedIdentifiers()) { + adjustNamingConventionForAllQuoted(); } namingConvention = createNamingConvention(p, namingConvention); if (namingConvention != null) { @@ -2781,11 +2742,6 @@ public class ServerConfig { } loadDocStoreSettings(p); - int srid = p.getInt("geometrySRID", 0); - if (srid > 0) { - dbTypeConfig.setGeometrySRID(srid); - } - queryPlanTTLSeconds = p.getInt("queryPlanTTLSeconds", queryPlanTTLSeconds); slowQueryMillis = p.getLong("slowQueryMillis", slowQueryMillis); docStoreOnly = p.getBoolean("docStoreOnly", docStoreOnly); @@ -2800,14 +2756,14 @@ public class ServerConfig { backgroundExecutorSchedulePoolSize = p.getInt("backgroundExecutorSchedulePoolSize", backgroundExecutorSchedulePoolSize); backgroundExecutorShutdownSecs = p.getInt("backgroundExecutorShutdownSecs", backgroundExecutorShutdownSecs); disableClasspathSearch = p.getBoolean("disableClasspathSearch", disableClasspathSearch); - currentUserProvider = createInstance(p, CurrentUserProvider.class, "currentUserProvider", currentUserProvider); - databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform", databasePlatform); - encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager", encryptKeyManager); - encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager); - encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor); - dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt); + currentUserProvider = p.createInstance(CurrentUserProvider.class, "currentUserProvider", currentUserProvider); + databasePlatform = p.createInstance(DatabasePlatform.class, "databasePlatform", databasePlatform); + encryptKeyManager = p.createInstance(EncryptKeyManager.class, "encryptKeyManager", encryptKeyManager); + encryptDeployManager = p.createInstance(EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager); + encryptor = p.createInstance(Encryptor.class, "encryptor", encryptor); + dbEncrypt = p.createInstance(DbEncrypt.class, "dbEncrypt", dbEncrypt); dbOffline = p.getBoolean("dbOffline", dbOffline); - serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin); + serverCachePlugin = p.createInstance(ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin); if (packages != null) { String packagesProp = p.get("search.packages", p.get("packages", null)); @@ -2828,7 +2784,6 @@ public class ServerConfig { throw new IllegalArgumentException("Property 'batch.mode' or 'persistBatching' is being set but no longer used. Please change to use 'persistBatchMode'"); } - idType = p.getEnum(IdType.class, "idType", idType); persistBatch = p.getEnum(PersistBatch.class, "persistBatch", persistBatch); persistBatchOnCascade = p.getEnum(PersistBatch.class, "persistBatchOnCascade", persistBatchOnCascade); @@ -2849,20 +2804,9 @@ public class ServerConfig { dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName); jdbcFetchSizeFindEach = p.getInt("jdbcFetchSizeFindEach", jdbcFetchSizeFindEach); jdbcFetchSizeFindList = p.getInt("jdbcFetchSizeFindList", jdbcFetchSizeFindList); - databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize); - databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue); - databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse); databasePlatformName = p.get("databasePlatformName", databasePlatformName); defaultOrderById = p.getBoolean("defaultOrderById", defaultOrderById); - DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null); - if (dbUuid != null) { - dbTypeConfig.setDbUuid(dbUuid); - } - if (p.getBoolean("uuidStoreAsBinary", false)) { - dbTypeConfig.setDbUuid(DbUuid.BINARY); - } - uuidVersion = p.getEnum(UuidVersion.class, "uuidVersion", uuidVersion); uuidStateFile = p.get("uuidStateFile", uuidStateFile); @@ -2898,16 +2842,15 @@ public class ServerConfig { } } - currentTenantProvider = createInstance(p, CurrentTenantProvider.class, "tenant.currentTenantProvider", currentTenantProvider); - tenantCatalogProvider = createInstance(p, TenantCatalogProvider.class, "tenant.catalogProvider", tenantCatalogProvider); - tenantSchemaProvider = createInstance(p, TenantSchemaProvider.class, "tenant.schemaProvider", tenantSchemaProvider); + currentTenantProvider = p.createInstance(CurrentTenantProvider.class, "tenant.currentTenantProvider", currentTenantProvider); + tenantCatalogProvider = p.createInstance(TenantCatalogProvider.class, "tenant.catalogProvider", tenantCatalogProvider); + tenantSchemaProvider = p.createInstance(TenantSchemaProvider.class, "tenant.schemaProvider", tenantSchemaProvider); tenantPartitionColumn = p.get("tenant.partitionColumn", tenantPartitionColumn); classes = getClasses(p); } private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) { - - NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention", null); + NamingConvention nc = properties.createInstance(NamingConvention.class, "namingconvention", null); return (nc != null) ? nc : namingConvention; } @@ -3098,71 +3041,24 @@ public class ServerConfig { } /** - * Specify how UUID is stored. + * Create a new PlatformConfig based of the one held but with overridden properties by reading + * properties with the given path and prefix. + *

+ * Typically used in Db Migration generation for many platform targets that might have different + * configuration for IdType, UUID, quoted identifiers etc. + *

+ * + * @param propertiesPath The properties path used for loading and setting properties + * @param platformPrefix The prefix used for loading and setting properties + * @return A copy of the PlatformConfig with overridden properties */ - public enum DbUuid { + public PlatformConfig newPlatformConfig(String propertiesPath, String platformPrefix) { + PropertiesWrapper p = new PropertiesWrapper(propertiesPath, platformPrefix, properties, classLoadConfig); - /** - * Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40). - */ - AUTO_VARCHAR(true, false, false), - - /** - * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16). - */ - AUTO_BINARY(true, true, false), - - /** - * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing. - */ - AUTO_BINARY_OPTIMIZED(true, true, true), - - /** - * Store using DB VARCHAR(40). - */ - VARCHAR(false, false, false), - - /** - * Store using DB BINARY(16). - */ - BINARY(false, true, false), - - /** - * Store using DB BINARY(16). - */ - BINARY_OPTIMIZED(false, true, true); - - boolean nativeType; - boolean binary; - boolean binaryOptimized; - - DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) { - this.nativeType = nativeType; - this.binary = binary; - this.binaryOptimized = binaryOptimized; - } - - /** - * Return true if native UUID type is preferred. - */ - public boolean useNativeType() { - return nativeType; - } - - /** - * Return true if BINARY(16) storage is preferred over VARCHAR(40). - */ - public boolean useBinary() { - return binary; - } - - /** - * Return true, if optimized packing should be used. - */ - public boolean useBinaryOptimized() { - return binaryOptimized; - } + PlatformConfig config = new PlatformConfig(platformConfig); + config.loadSettings(p); + return config; } public enum UuidVersion { diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 166a9b5df..c1a014095 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -5,8 +5,7 @@ import io.ebean.Query; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; import io.ebean.config.CustomDbTypeMapping; -import io.ebean.config.DbTypeConfig; -import io.ebean.config.ServerConfig; +import io.ebean.config.PlatformConfig; import io.ebean.util.JdbcClose; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -215,16 +214,16 @@ public class DatabasePlatform { /** * Configure the platform given the server configuration. */ - public void configure(ServerConfig config) { + public void configure(PlatformConfig config) { this.sequenceBatchSize = config.getDatabaseSequenceBatchSize(); configureIdType(config.getIdType()); - configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); + configure(config, config.isAllQuotedIdentifiers()); } /** * Configure UUID Storage etc based on ServerConfig settings. */ - protected void configure(DbTypeConfig config, boolean allQuotedIdentifiers) { + protected void configure(PlatformConfig config, boolean allQuotedIdentifiers) { this.allQuotedIdentifiers = allQuotedIdentifiers; addGeoTypes(config.getGeometrySRID()); configureIdType(config.getIdType()); diff --git a/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java b/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java index c1c4896e3..3376f617c 100644 --- a/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java +++ b/src/main/java/io/ebean/config/dbplatform/DbPlatformTypeMapping.java @@ -1,6 +1,6 @@ package io.ebean.config.dbplatform; -import io.ebean.config.ServerConfig; +import io.ebean.config.PlatformConfig; import java.util.EnumMap; import java.util.Map; @@ -198,7 +198,7 @@ public class DbPlatformTypeMapping { /** * Map the UUID appropriately based on native DB support and ServerConfig.DbUuid. */ - public void config(boolean nativeUuidType, ServerConfig.DbUuid dbUuid) { + public void config(boolean nativeUuidType, PlatformConfig.DbUuid dbUuid) { if (nativeUuidType && dbUuid.useNativeType()) { // native UUID already set by default } else if (dbUuid.useBinary()) { diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index 39727c7b2..75591f2ad 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -4,7 +4,7 @@ import io.ebean.BackgroundExecutor; import io.ebean.Query; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; -import io.ebean.config.ServerConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.config.dbplatform.DbType; @@ -82,7 +82,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform { } @Override - public void configure(ServerConfig config) { + public void configure(PlatformConfig config) { super.configure(config); if (dbIdentity.getIdType() == IdType.SEQUENCE) { this.persistBatchOnCascade = PersistBatch.ALL; diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index c548bbc64..fe698ffba 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -5,6 +5,7 @@ import io.ebean.EbeanServer; import io.ebean.annotation.Platform; import io.ebean.config.DbConstraintNaming; import io.ebean.config.DbMigrationConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.db2.DB2Platform; @@ -227,15 +228,17 @@ public class DefaultDbMigration implements DbMigration { if (!online) { DbOffline.setGenerateMigration(); if (databasePlatform == null && !platforms.isEmpty()) { - // for multiple platform generation set the general platform - // to H2 so that it runs offline without DB connection + // for multiple platform generation the first platform + // is used to generate the "logical" model diff setPlatform(platforms.get(0).platform); } } setDefaults(); + if (!platforms.isEmpty()) { + configurePlatforms(); + } try { Request request = createRequest(); - if (platforms.isEmpty()) { generateExtraDdl(request.migrationDir, databasePlatform); } @@ -254,6 +257,16 @@ public class DefaultDbMigration implements DbMigration { } } + /** + * Load the configuration for each of the target platforms. + */ + private void configurePlatforms() { + for (Pair pair : platforms) { + PlatformConfig config = serverConfig.newPlatformConfig("dbmigration.platform", pair.prefix); + pair.platform.configure(config); + } + } + /** * Generate "repeatable" migration scripts. *

diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java index 63536ee51..7f4d94422 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java @@ -267,7 +267,7 @@ public class DefaultContainer implements SpiContainer { config.setDatabasePlatform(platform); } logger.info("DatabasePlatform name:{} platform:{}", config.getName(), platform.getName()); - platform.configure(config); + platform.configure(config.getPlatformConfig()); } /** diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index dc835fb6c..e9b423ece 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -304,7 +304,7 @@ public class InternalConfiguration { } public RelationalQueryEngine createRelationalQueryEngine() { - return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue(), serverConfig.getDbTypeConfig().getDbUuid().useBinaryOptimized()); + return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue(), serverConfig.getPlatformConfig().getDbUuid().useBinaryOptimized()); } public OrmQueryEngine createOrmQueryEngine() { diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index ef11a43c5..e474ac482 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -8,6 +8,7 @@ import io.ebean.annotation.DbEnumValue; import io.ebean.annotation.EnumValue; import io.ebean.annotation.Platform; import io.ebean.config.JsonConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.ScalarTypeConverter; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; @@ -944,7 +945,7 @@ public final class DefaultTypeManager implements TypeManager { nativeMap.put(Types.BIT, booleanType); } - ServerConfig.DbUuid dbUuid = config.getDbTypeConfig().getDbUuid(); + PlatformConfig.DbUuid dbUuid = config.getPlatformConfig().getDbUuid(); if (offlineMigrationGeneration || (databasePlatform.isNativeUuidType() && dbUuid.useNativeType())) { addType(UUID.class, new ScalarTypeUUIDNative()); diff --git a/src/test/java/io/ebean/config/DbMigrationConfigTest.java b/src/test/java/io/ebean/config/DbMigrationConfigTest.java index 0bc2ab692..95464ec72 100644 --- a/src/test/java/io/ebean/config/DbMigrationConfigTest.java +++ b/src/test/java/io/ebean/config/DbMigrationConfigTest.java @@ -32,7 +32,7 @@ public class DbMigrationConfigTest { properties.setProperty("ebean.migration.patchInsertOn", "1.3,my_views"); properties.setProperty("ebean.migration.patchResetChecksumOn", "foo"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties, null); DbMigrationConfig migrationConfig = new DbMigrationConfig(); migrationConfig.loadSettings(wrapper, "db"); @@ -50,7 +50,7 @@ public class DbMigrationConfigTest { properties.setProperty("datasource.db.username", "banana"); properties.setProperty("datasource.db.password", "apple"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties, null); DbMigrationConfig migrationConfig = new DbMigrationConfig(); migrationConfig.loadSettings(wrapper, "db"); @@ -67,7 +67,7 @@ public class DbMigrationConfigTest { properties.setProperty("datasource.db.adminusername", "banana"); properties.setProperty("datasource.db.adminpassword", "apple"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "db", properties, null); DbMigrationConfig migrationConfig = new DbMigrationConfig(); migrationConfig.loadSettings(wrapper, "db"); diff --git a/src/test/java/io/ebean/config/DocStoreConfigTest.java b/src/test/java/io/ebean/config/DocStoreConfigTest.java index 295d6948d..8919fab4a 100644 --- a/src/test/java/io/ebean/config/DocStoreConfigTest.java +++ b/src/test/java/io/ebean/config/DocStoreConfigTest.java @@ -5,7 +5,9 @@ import org.junit.Test; import java.util.Properties; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class DocStoreConfigTest { @@ -23,7 +25,7 @@ public class DocStoreConfigTest { properties.setProperty("ebean.docstore.username", "fred"); properties.setProperty("ebean.docstore.password", "rock"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties, null); config.loadSettings(wrapper); @@ -47,7 +49,7 @@ public class DocStoreConfigTest { properties.setProperty("ebean.docstore.generateMapping", "true"); properties.setProperty("ebean.docstore.dropCreate", "true"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties, null); config.loadSettings(wrapper); assertTrue(config.isGenerateMapping()); @@ -64,7 +66,7 @@ public class DocStoreConfigTest { properties.setProperty("ebean.docstore.generateMapping", "true"); properties.setProperty("ebean.docstore.create", "true"); - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", null, properties, null); config.loadSettings(wrapper); assertTrue(config.isGenerateMapping()); diff --git a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java index 677b572e7..9cd9317b7 100644 --- a/src/test/java/io/ebean/config/MatchingNamingConventionTest.java +++ b/src/test/java/io/ebean/config/MatchingNamingConventionTest.java @@ -20,7 +20,7 @@ public class MatchingNamingConventionTest { SqlServer17Platform platform = new SqlServer17Platform(); - ServerConfig config = new ServerConfig(); + PlatformConfig config = new PlatformConfig(); config.setAllQuotedIdentifiers(true); platform.configure(config); diff --git a/src/test/java/io/ebean/config/PropertiesWrapperTest.java b/src/test/java/io/ebean/config/PropertiesWrapperTest.java index 016af03c6..180156040 100644 --- a/src/test/java/io/ebean/config/PropertiesWrapperTest.java +++ b/src/test/java/io/ebean/config/PropertiesWrapperTest.java @@ -15,7 +15,7 @@ public class PropertiesWrapperTest { @Test public void testGetServerName() { - PropertiesWrapper pw = new PropertiesWrapper(null, "myserver", new Properties()); + PropertiesWrapper pw = new PropertiesWrapper(null, "myserver", new Properties(), null); assertEquals("myserver", pw.getServerName()); } @@ -25,7 +25,7 @@ public class PropertiesWrapperTest { Properties properties = new Properties(); properties.put("platform", "postgres"); - PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", properties); + PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", properties, null); assertEquals(Platform.POSTGRES, pw.getEnum(Platform.class, "platform", Platform.H2)); assertEquals(Platform.H2, pw.getEnum(Platform.class, "junk", Platform.H2)); assertNull(pw.getEnum(Platform.class, "junk", null)); @@ -40,7 +40,7 @@ public class PropertiesWrapperTest { properties.put("noTrimReqr", "jim"); properties.put("includeSpaces", " jim bob "); - PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", properties); + PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", properties, null); assertEquals(" hello ", pw.get("someBasic")); assertEquals(42, pw.getInt("someInt", 1)); assertNull(pw.get("doesNotExist", null)); @@ -62,14 +62,14 @@ public class PropertiesWrapperTest { properties.put("someSystemProp", "/aaa/${java.io.tmpdir}/bbb"); Properties evalCopy = PropertiesLoader.eval(properties); - PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", evalCopy); + PropertiesWrapper pw = new PropertiesWrapper("pref", "myserver", evalCopy, null); assertEquals(42, pw.getInt("someInt", 99)); assertEquals(Double.valueOf(5.5D), (Double.valueOf(pw.getDouble("someDouble", 99.9D)))); assertEquals(home + "/hello", pw.get("somePath", null)); assertEquals(tmpDir, "/aaa/" + tmpDir + "/bbb", pw.get("someSystemProp")); - pw = new PropertiesWrapper(evalCopy); + pw = new PropertiesWrapper(evalCopy, null); assertEquals(42, pw.getInt("someInt", 99)); assertEquals(Double.valueOf(5.5D), (Double.valueOf(pw.getDouble("someDouble", 99.9D)))); diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index 8ee588ad3..6aa9f64c9 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -75,7 +75,7 @@ public class ServerConfigTest { assertEquals(IdType.SEQUENCE, serverConfig.getIdType()); assertEquals(PersistBatch.INSERT, serverConfig.getPersistBatch()); assertEquals(PersistBatch.INSERT, serverConfig.getPersistBatchOnCascade()); - assertEquals(ServerConfig.DbUuid.BINARY, serverConfig.getDbTypeConfig().getDbUuid()); + assertEquals(PlatformConfig.DbUuid.BINARY, serverConfig.getPlatformConfig().getDbUuid()); assertEquals(JsonConfig.DateTime.ISO8601, serverConfig.getJsonDateTime()); assertEquals(42, serverConfig.getJdbcFetchSizeFindEach()); diff --git a/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java b/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java index a1e9de455..ddfd991a9 100644 --- a/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/DatabasePlatformTest.java @@ -1,8 +1,8 @@ package io.ebean.config.dbplatform; import io.ebean.annotation.Platform; -import io.ebean.config.DbTypeConfig; import io.ebean.config.MatchingNamingConvention; +import io.ebean.config.PlatformConfig; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; @@ -21,7 +21,7 @@ public class DatabasePlatformTest { config.setNamingConvention(new MatchingNamingConvention()); DatabasePlatform dbPlatform = new SqlServer17Platform(); - dbPlatform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); + dbPlatform.configure(config.getPlatformConfig(), config.isAllQuotedIdentifiers()); assertEquals(dbPlatform.convertQuotedIdentifiers("order"),"[order]"); assertEquals(dbPlatform.convertQuotedIdentifiers("`order`"),"[order]"); @@ -34,7 +34,7 @@ public class DatabasePlatformTest { ServerConfig config = new ServerConfig(); DatabasePlatform dbPlatform = new SqlServer17Platform(); - dbPlatform.configure(config.getDbTypeConfig(), config.isAllQuotedIdentifiers()); + dbPlatform.configure(config.getPlatformConfig(), config.isAllQuotedIdentifiers()); assertEquals(dbPlatform.convertQuotedIdentifiers("order"),"order"); assertEquals(dbPlatform.convertQuotedIdentifiers("`order`"),"[order]"); @@ -56,7 +56,7 @@ public class DatabasePlatformTest { @Test public void configure_customType() throws Exception { - DbTypeConfig config = new DbTypeConfig(); + PlatformConfig config = new PlatformConfig(); config.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES); config.addCustomMapping(DbType.DECIMAL, "decimal(24,4)"); diff --git a/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java b/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java index ed0fc2bf9..ca0eff20a 100644 --- a/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/MySqlPlatformTest.java @@ -1,7 +1,6 @@ package io.ebean.config.dbplatform; -import io.ebean.config.DbTypeConfig; -import io.ebean.config.ServerConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl; import io.ebeaninternal.server.core.PlatformDdlBuilder; @@ -28,7 +27,7 @@ public class MySqlPlatformTest { public void uuid_default() { MySqlPlatform platform = new MySqlPlatform(); - platform.configure(new DbTypeConfig(), false); + platform.configure(new PlatformConfig(), false); DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); assertThat(dbType.renderType(0, 0)).isEqualTo("varchar(40)"); @@ -39,8 +38,8 @@ public class MySqlPlatformTest { public void uuid_as_binary() { MySqlPlatform platform = new MySqlPlatform(); - DbTypeConfig config = new DbTypeConfig(); - config.setDbUuid(ServerConfig.DbUuid.AUTO_BINARY); + PlatformConfig config = new PlatformConfig(); + config.setDbUuid(PlatformConfig.DbUuid.AUTO_BINARY); platform.configure(config, false); DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); diff --git a/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java b/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java index 11da787e2..119d58ff1 100644 --- a/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/OraclePlatformTest.java @@ -1,7 +1,6 @@ package io.ebean.config.dbplatform; -import io.ebean.config.DbTypeConfig; -import io.ebean.config.ServerConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl; import io.ebeaninternal.server.core.PlatformDdlBuilder; @@ -37,7 +36,7 @@ public class OraclePlatformTest { public void uuid_default() { OraclePlatform platform = new OraclePlatform(); - platform.configure(new DbTypeConfig(), false); + platform.configure(new PlatformConfig(), false); DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); assertThat(dbType.renderType(0, 0)).isEqualTo("varchar2(40)"); @@ -48,8 +47,8 @@ public class OraclePlatformTest { public void uuid_as_binary() { OraclePlatform platform = new OraclePlatform(); - DbTypeConfig config = new DbTypeConfig(); - config.setDbUuid(ServerConfig.DbUuid.AUTO_BINARY); + PlatformConfig config = new PlatformConfig(); + config.setDbUuid(PlatformConfig.DbUuid.AUTO_BINARY); platform.configure(config, false); diff --git a/src/test/java/io/ebean/config/dbplatform/PostgresPlatformTest.java b/src/test/java/io/ebean/config/dbplatform/PostgresPlatformTest.java index f23370a43..b992e2fa4 100644 --- a/src/test/java/io/ebean/config/dbplatform/PostgresPlatformTest.java +++ b/src/test/java/io/ebean/config/dbplatform/PostgresPlatformTest.java @@ -1,6 +1,6 @@ package io.ebean.config.dbplatform; -import io.ebean.config.DbTypeConfig; +import io.ebean.config.PlatformConfig; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl; import io.ebeaninternal.server.core.PlatformDdlBuilder; @@ -37,7 +37,7 @@ public class PostgresPlatformTest { public void testUuidType() { PostgresPlatform platform = new PostgresPlatform(); - platform.configure(new DbTypeConfig(), false); + platform.configure(new PlatformConfig(), false); DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); String columnDefn = dbType.renderType(0, 0); From d0b24dc3404fb917b85f60b6da0cc09dbe399142 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Mar 2018 00:44:04 +1300 Subject: [PATCH 0176/1036] #1343 - Update the #1283 ENH: Support simplified test configuration (with docker setup typically via application-test.yml) --- src/main/java/io/ebean/config/AutoConfigure.java | 11 +++++++---- src/main/java/io/ebean/config/ServerConfig.java | 15 ++++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/ebean/config/AutoConfigure.java b/src/main/java/io/ebean/config/AutoConfigure.java index 5c0ef18af..879338ce5 100644 --- a/src/main/java/io/ebean/config/AutoConfigure.java +++ b/src/main/java/io/ebean/config/AutoConfigure.java @@ -6,10 +6,13 @@ package io.ebean.config; public interface AutoConfigure { /** - * Provide some configuration the ServerConfig prior to server creation. - *

- * Return true if the autoConfiguration applies to this ServerConfig. + * Perform configuration for the ServerConfig prior to properties load. */ - void configure(ServerConfig serverConfig); + void preConfigure(ServerConfig serverConfig); + + /** + * Provide some configuration the ServerConfig prior to server creation but after properties have been applied. + */ + void postConfigure(ServerConfig serverConfig); } diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index f4b59039c..28728cd22 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -2650,19 +2650,24 @@ public class ServerConfig { * Load the settings from the given properties */ private void configureFromProperties() { - autoConfiguration(); - PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties, classLoadConfig); - loadSettings(p); + List autoConfigures = autoConfiguration(); + loadSettings(new PropertiesWrapper("ebean", name, properties, classLoadConfig)); + for (AutoConfigure autoConfigure : autoConfigures) { + autoConfigure.postConfigure(this); + } } /** * Use a 'plugin' to provide automatic configuration. Intended for automatic testing * configuration with Docker containers via ebean-test-config. */ - private void autoConfiguration() { + private List autoConfiguration() { + List list = new ArrayList<>(); for (AutoConfigure autoConfigure : serviceLoad(AutoConfigure.class)) { - autoConfigure.configure(this); + autoConfigure.preConfigure(this); + list.add(autoConfigure); } + return list; } /** From 6c8cf0c5b78c2402ed796c8aafb9cb0100449bf7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Mar 2018 10:34:25 +1300 Subject: [PATCH 0177/1036] #1343 - Update for ... #1283 ENH: Support simplified test configuration (with docker setup typically via application-test.yml) DefaultContainer with config.loadFromProperties(PropertiesLoader.load()); effectively runs eval twice on properties which is unnecessary. Additionally add ServerConfig.setRunMigration() because I think it makes more sense / easier to find. Remote PropertiesLoader.setProperty() as it is no longer required for the ebean-test-config plugin. --- src/main/java/io/ebean/config/ServerConfig.java | 10 ++++++++++ .../io/ebean/config/properties/PropertiesLoader.java | 11 ----------- .../ebeaninternal/server/core/DefaultContainer.java | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 28728cd22..51221e96f 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -1956,6 +1956,16 @@ public class ServerConfig { this.durationWithNanos = durationWithNanos; } + /** + * Set to true to run DB migrations on server start. + *

+ * This is the same as serverConfig.getMigrationConfig().setRunMigration(). We have added this method here + * as it is often the only thing we need to configure for migrations. + */ + public void setRunMigration(boolean runMigration){ + migrationConfig.setRunMigration(runMigration); + } + /** * Set to true to generate the "create all" DDL on startup. *

diff --git a/src/main/java/io/ebean/config/properties/PropertiesLoader.java b/src/main/java/io/ebean/config/properties/PropertiesLoader.java index 560d255e5..3df479919 100644 --- a/src/main/java/io/ebean/config/properties/PropertiesLoader.java +++ b/src/main/java/io/ebean/config/properties/PropertiesLoader.java @@ -56,17 +56,6 @@ public class PropertiesLoader { return properties; } - /** - * Set (override) a configuration property. - * - * This is expected to be only called by test configuration logic - * (ala automatic test configuration via ebean-test-config). - */ - public static synchronized void setProperty(String key, String value) { - load(); - properties.setProperty(key, value); - } - /** * Return a copy of the properties with 'eval' run on all the values. * This resolves expressions like ${HOME} etc. diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java index 7f4d94422..e1e923dea 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java @@ -83,7 +83,7 @@ public class DefaultContainer implements SpiContainer { ServerConfig config = new ServerConfig(); config.setName(name); - config.loadFromProperties(PropertiesLoader.load()); + config.loadFromProperties(); return createServer(config); } From 8ac1b745df1cb27d2f5dec6be9bdd373628156c7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Mar 2018 16:54:38 +1300 Subject: [PATCH 0178/1036] #1344 - ENH: Add initial Cockroach DB support ... need to review JSON and DB ARRAY support --- pom.xml | 2 +- .../config/dbplatform/DatabasePlatform.java | 7 +++ .../cockroach/CockroachPlatform.java | 28 +++++++++ .../dbmigration/DdlGenerator.java | 5 ++ .../ddlgeneration/platform/CockroachDdl.java | 57 +++++++++++++++++++ .../server/core/DatabasePlatformFactory.java | 48 +++++++++++++--- .../server/core/PlatformDdlBuilder.java | 3 + 7 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 src/main/java/io/ebean/config/dbplatform/cockroach/CockroachPlatform.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java diff --git a/pom.xml b/pom.xml index f5e65dff5..bfc7d5897 100644 --- a/pom.xml +++ b/pom.xml @@ -130,7 +130,7 @@ io.ebean ebean-migration - 11.3.1 + 11.5.1 diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index c1a014095..b1ddadc2c 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -517,6 +517,13 @@ public class DatabasePlatform { this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate; } + /** + * Normally not needed - overridden in CockroachPlatform. + */ + public boolean isDdlCommitOnCreateIndex() { + return false; + } + /** * Return the DB identity/sequence features for this platform. * diff --git a/src/main/java/io/ebean/config/dbplatform/cockroach/CockroachPlatform.java b/src/main/java/io/ebean/config/dbplatform/cockroach/CockroachPlatform.java new file mode 100644 index 000000000..502e33cf6 --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/cockroach/CockroachPlatform.java @@ -0,0 +1,28 @@ +package io.ebean.config.dbplatform.cockroach; + +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.postgres.PostgresPlatform; + +/** + * CockroachDB based platform. + */ +public class CockroachPlatform extends PostgresPlatform { + + public CockroachPlatform() { + super(); + this.platform = Platform.COCKROACH; + // no like escape clause supported + this.likeSpecialCharacters = new char[]{'%', '_'}; + this.likeClauseRaw = "like ?"; + this.likeClauseEscaped = "like ?"; + } + + /** + * Needs a commit after create index such that alter table add foreign key ... succeeds. + */ + @Override + public boolean isDdlCommitOnCreateIndex() { + return true; + } + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java index ae1ef4d08..68455dd89 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java @@ -37,6 +37,7 @@ public class DdlGenerator { private final boolean runDdl; private final boolean createOnly; private final boolean jaxbPresent; + private final boolean ddlCommitOnCreateIndex; private CurrentModel currentModel; private String dropAllContent; @@ -50,8 +51,10 @@ public class DdlGenerator { if (!serverConfig.getTenantMode().isDdlEnabled() && serverConfig.isDdlRun()) { log.warn("DDL can't be run on startup with TenantMode " + serverConfig.getTenantMode()); this.runDdl = false; + this.ddlCommitOnCreateIndex = false; } else { this.runDdl = serverConfig.isDdlRun(); + this.ddlCommitOnCreateIndex = server.getDatabasePlatform().isDdlCommitOnCreateIndex(); } } @@ -109,6 +112,8 @@ public class DdlGenerator { try { if (expectErrors) { connection.setAutoCommit(true); + } else if (ddlCommitOnCreateIndex) { + runner.setCommitOnCreateIndex(); } int count = runner.runAll(content, connection); if (expectErrors) { diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java new file mode 100644 index 000000000..303c887bd --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java @@ -0,0 +1,57 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; + +/** + * CockroachDB specific DDL handling. + */ +public class CockroachDdl extends PlatformDdl { + + public CockroachDdl(DatabasePlatform platform) { + super(platform); + this.historyDdl = new PostgresHistoryDdl(); + this.dropTableCascade = " cascade"; + this.columnSetType = "type "; + this.alterTableIfExists = "if exists "; + this.columnSetNull = "drop not null"; + } + +// @Override +// protected String convertArrayType(String logicalArrayType) { +// TODO: Need to look at DB Array support ... +// } + + /** + * Map bigint, integer and smallint all into serial. + */ + @Override + public String asIdentityColumn(String columnDefn) { + + if ("bigint".equalsIgnoreCase(columnDefn)) { + return "serial"; + } + if ("integer".equalsIgnoreCase(columnDefn)) { + return "serial"; + } + if ("smallint".equalsIgnoreCase(columnDefn)) { + return "serial"; + } + return columnDefn; + } + + @Override + public void addTableComment(DdlBuffer apply, String tableName, String tableComment) { + // do nothing + } + + @Override + public void addColumnComment(DdlBuffer apply, String table, String column, String comment) { + // do nothing + } + + @Override + public boolean isInlineComments() { + return false; + } +} diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index 3f98a1c6d..75db54f34 100644 --- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.core; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.cockroach.CockroachPlatform; import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform; @@ -13,6 +14,7 @@ import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform; import io.ebean.config.dbplatform.sqlite.SQLitePlatform; import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; +import io.ebean.migration.util.JdbcClose; import io.ebeaninternal.dbmigration.DbOffline; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,6 +23,8 @@ 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; /** @@ -111,20 +115,20 @@ public class DatabasePlatformFactory { */ private DatabasePlatform byDataSource(DataSource dataSource) { - Connection conn = null; + Connection connection = null; try { - conn = dataSource.getConnection(); - DatabaseMetaData metaData = conn.getMetaData(); + connection = dataSource.getConnection(); + DatabaseMetaData metaData = connection.getMetaData(); - return byDatabaseMeta(metaData); + return byDatabaseMeta(metaData, connection); } catch (SQLException ex) { throw new PersistenceException(ex); } finally { try { - if (conn != null) { - conn.close(); + if (connection != null) { + connection.close(); } } catch (SQLException ex) { logger.error(null, ex); @@ -135,7 +139,7 @@ public class DatabasePlatformFactory { /** * Find the platform by the metaData.getDatabaseProductName(). */ - private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData) throws SQLException { + private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData, Connection connection) throws SQLException { String dbProductName = metaData.getDatabaseProductName(); dbProductName = dbProductName.toLowerCase(); @@ -151,7 +155,7 @@ public class DatabasePlatformFactory { } else if (dbProductName.contains("hsql database engine")) { return new HsqldbPlatform(); } else if (dbProductName.contains("postgres")) { - return new PostgresPlatform(); + return readPostgres(connection); } else if (dbProductName.contains("sqlite")) { return new SQLitePlatform(); } else if (dbProductName.contains("db2")) { @@ -163,4 +167,32 @@ public class DatabasePlatformFactory { // use the standard one return new DatabasePlatform(); } + + /** + * Use a select version() query as it could be Postgres or CockroachDB. + */ + private static PostgresPlatform readPostgres(Connection connection) { + // Postgres driver uses a hardcoded product name so use version() query + PreparedStatement statement = null; + ResultSet resultSet = null; + try { + statement = connection.prepareStatement("SELECT version() AS \"version\""); + resultSet = statement.executeQuery(); + if (resultSet.next()) { + String productVersion = resultSet.getString("version").toLowerCase(); + if (productVersion.contains("cockroach")) { + return new CockroachPlatform(); + } + } + } catch (SQLException e) { + logger.warn("Error running detection query on Postgres", e); + + } finally { + JdbcClose.close(resultSet); + JdbcClose.close(statement); + } + + // Real Postgres + return new PostgresPlatform(); + } } diff --git a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java index efd69538e..bf901ed50 100644 --- a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java +++ b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.core; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebeaninternal.dbmigration.ddlgeneration.platform.CockroachDdl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.DB2Ddl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.HsqldbDdl; @@ -38,6 +39,8 @@ public class PlatformDdlBuilder { return new PlatformDdl(platform); case POSTGRES: return new PostgresDdl(platform); + case COCKROACH: + return new CockroachDdl(platform); case SQLANYWHERE: return new PlatformDdl(platform); case SQLSERVER16: From eda6350d8960bfb8f741c309ce89751d63a237cc Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 9 Mar 2018 17:40:34 +1300 Subject: [PATCH 0179/1036] #1344 - ENH: Add initial Cockroach DB support ... need to review JSON Adds in the DB ARRAY support (exactly the same as Postgres) --- .../config/dbplatform/DatabasePlatform.java | 7 +++++++ .../dbplatform/postgres/PostgresPlatform.java | 8 +++++++ .../ddlgeneration/platform/CockroachDdl.java | 8 +++---- .../ddlgeneration/platform/NativeDbArray.java | 20 ++++++++++++++++++ .../ddlgeneration/platform/PostgresDdl.java | 8 +------ .../server/type/DefaultTypeManager.java | 12 +++++------ .../platform/NativeDbArrayTest.java | 21 +++++++++++++++++++ src/test/resources/ebean.properties | 2 +- 8 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArray.java create mode 100644 src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArrayTest.java diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index b1ddadc2c..ced70893c 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -381,6 +381,13 @@ public class DatabasePlatform { this.historySupport = historySupport; } + /** + * So no except for Postgres and CockroachDB. + */ + public boolean isNativeArrayType() { + return false; + } + /** * Return true if the DB supports native UUID. */ diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java index 9a9b584fd..75a395568 100644 --- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java @@ -88,6 +88,14 @@ public class PostgresPlatform extends DatabasePlatform { return new DbPlatformType("geometry(" + type + "," + srid + ")"); } + /** + * So we can generate varchar[], int[], uuid[] column definitions and use the associated scalar types. + */ + @Override + public boolean isNativeArrayType() { + return true; + } + /** * Create a Postgres specific sequence IdGenerator. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java index 303c887bd..f1fa243ef 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/CockroachDdl.java @@ -17,10 +17,10 @@ public class CockroachDdl extends PlatformDdl { this.columnSetNull = "drop not null"; } -// @Override -// protected String convertArrayType(String logicalArrayType) { -// TODO: Need to look at DB Array support ... -// } + @Override + protected String convertArrayType(String logicalArrayType) { + return NativeDbArray.logicalToNative(logicalArrayType); + } /** * Map bigint, integer and smallint all into serial. diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArray.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArray.java new file mode 100644 index 000000000..8b6723e29 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArray.java @@ -0,0 +1,20 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +/** + * Helper for logical type conversion. + */ +class NativeDbArray { + + /** + * Covert the 'logical' array type to a native one (for Postgres and Cockroach). + */ + static String logicalToNative(String logicalArrayType) { + int colonPos = logicalArrayType.lastIndexOf(']'); + if (colonPos == -1) { + return logicalArrayType; + } else { + // trim of the fallback varchar length + return logicalArrayType.substring(0, colonPos + 1); + } + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java index 774ce97d3..709e6f026 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PostgresDdl.java @@ -18,13 +18,7 @@ public class PostgresDdl extends PlatformDdl { @Override protected String convertArrayType(String logicalArrayType) { - int colonPos = logicalArrayType.lastIndexOf(']'); - if (colonPos == -1) { - return logicalArrayType; - } else { - // trim of the fallback varchar length - return logicalArrayType.substring(0, colonPos + 1); - } + return NativeDbArray.logicalToNative(logicalArrayType); } /** diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index e474ac482..ddd4c31f4 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -189,8 +189,8 @@ public final class DefaultTypeManager implements TypeManager { this.extraTypeFactory = new DefaultTypeFactory(config); this.postgres = isPostgres(config.getDatabasePlatform()); - this.arrayTypeListFactory = arrayTypeListFactory(postgres, config.getDatabasePlatform()); - this.arrayTypeSetFactory = arrayTypeSetFactory(postgres, config.getDatabasePlatform()); + this.arrayTypeListFactory = arrayTypeListFactory(config.getDatabasePlatform()); + this.arrayTypeSetFactory = arrayTypeSetFactory(config.getDatabasePlatform()); this.offlineMigrationGeneration = DbOffline.isGenerateMigration(); @@ -211,8 +211,8 @@ public final class DefaultTypeManager implements TypeManager { /** * Return the factory to use to support DB ARRAY types. */ - private PlatformArrayTypeFactory arrayTypeListFactory(boolean postgres, DatabasePlatform databasePlatform) { - if (postgres) { + private PlatformArrayTypeFactory arrayTypeListFactory(DatabasePlatform databasePlatform) { + if (databasePlatform.isNativeArrayType()) { return ScalarTypeArrayList.factory(); } else if (databasePlatform.isPlatform(Platform.H2)) { return ScalarTypeArrayListH2.factory(); @@ -224,8 +224,8 @@ public final class DefaultTypeManager implements TypeManager { /** * Return the factory to use to support DB ARRAY types. */ - private PlatformArrayTypeFactory arrayTypeSetFactory(boolean postgres, DatabasePlatform databasePlatform) { - if (postgres) { + private PlatformArrayTypeFactory arrayTypeSetFactory(DatabasePlatform databasePlatform) { + if (databasePlatform.isNativeArrayType()) { return ScalarTypeArraySet.factory(); } else if (databasePlatform.isPlatform(Platform.H2)) { return ScalarTypeArraySetH2.factory(); diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArrayTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArrayTest.java new file mode 100644 index 000000000..7d37363e4 --- /dev/null +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/NativeDbArrayTest.java @@ -0,0 +1,21 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NativeDbArrayTest { + + @Test + public void logicalToNative() { + + assertThat(NativeDbArray.logicalToNative("uuid[]")).isEqualTo("uuid[]"); + assertThat(NativeDbArray.logicalToNative("varchar[]")).isEqualTo("varchar[]"); + } + + @Test + public void logicalToNative_withFallbackDefined() { + + assertThat(NativeDbArray.logicalToNative("uuid[]:(1000)")).isEqualTo("uuid[]"); + } +} diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 3b048c4c2..b33a6e823 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -19,7 +19,7 @@ ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests -datasource.default=h2 +datasource.default=pg ebean.autoReadOnlyDataSource=true From 85bfe3d03e856367a018bc6a718b011a4340df90 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sat, 10 Mar 2018 02:51:51 +1300 Subject: [PATCH 0180/1036] #1345 - Refactor io.ebean.meta.MetaInfoManager API (query execution metrics). Breaking change for people collecting query execution metrics. --- src/main/java/io/ebean/ExpressionList.java | 5 + src/main/java/io/ebean/Query.java | 9 ++ src/main/java/io/ebean/SqlQuery.java | 5 + src/main/java/io/ebean/Update.java | 5 + .../io/ebean/meta/AbstractMetricVisitor.java | 43 ++++++ .../io/ebean/meta/BasicMetricVisitor.java | 64 ++++++++ .../java/io/ebean/meta/MetaInfoManager.java | 19 +-- .../io/ebean/meta/MetaOrmQueryMetric.java | 42 ++++++ ...phNodeStats.java => MetaOrmQueryNode.java} | 4 +- ...iginCount.java => MetaOrmQueryOrigin.java} | 5 +- .../io/ebean/meta/MetaQueryPlanStatistic.java | 98 ------------- .../java/io/ebean/meta/MetaTimedMetric.java | 5 + src/main/java/io/ebean/meta/MetricType.java | 30 ++++ .../java/io/ebean/meta/MetricVisitor.java | 48 ++++++ .../io/ebeaninternal/api/SpiEbeanServer.java | 6 + .../java/io/ebeaninternal/api/SpiQuery.java | 5 + .../io/ebeaninternal/api/SpiSqlBinding.java | 5 + .../java/io/ebeaninternal/api/SpiUpdate.java | 5 + .../ebeaninternal/metric/MetricFactory.java | 12 +- .../ebeaninternal/metric/QueryPlanMetric.java | 6 +- .../io/ebeaninternal/metric/TimedMetric.java | 15 +- .../ebeaninternal/metric/TimedMetricMap.java | 13 +- .../server/core/AbstractSqlQueryRequest.java | 2 +- .../core/CObjectGraphNodeStatistics.java | 6 +- .../server/core/DefaultMetaInfoManager.java | 57 +++++--- .../server/core/DefaultServer.java | 29 ++-- .../server/core/PersistRequest.java | 25 +++- .../core/PersistRequestCallableSql.java | 9 +- .../server/core/PersistRequestOrmUpdate.java | 6 +- .../server/core/PersistRequestUpdateSql.java | 6 +- .../ebeaninternal/server/core/Persister.java | 5 + .../server/core/RelationalQueryEngine.java | 10 ++ .../server/core/RelationalQueryRequest.java | 6 +- .../server/deploy/BeanDescriptor.java | 9 +- .../server/deploy/BeanDescriptorManager.java | 7 + .../server/dto/DtoBeanDescriptor.java | 6 +- .../server/dto/DtoBeanManager.java | 13 +- .../server/dto/DtoMappingRequest.java | 3 +- .../server/dto/DtoQueryPlan.java | 6 +- .../server/dto/DtoQueryPlanBase.java | 7 +- .../expression/DefaultExpressionList.java | 5 + .../server/expression/JunctionExpression.java | 5 + .../server/persist/DefaultPersistExecute.java | 39 ++++- .../server/persist/DefaultPersister.java | 6 + .../server/persist/ExeCallableSql.java | 1 + .../server/persist/ExeOrmUpdate.java | 1 + .../server/persist/ExeUpdateSql.java | 1 + .../server/persist/PersistExecute.java | 20 +++ .../server/profile/DMetricFactory.java | 18 +-- .../profile/DProfileLocationFactory.java | 3 +- .../server/profile/DQueryPlanMetric.java | 18 ++- .../server/profile/DTimeMetricStats.java | 11 +- .../server/profile/DTimedMetric.java | 43 +++--- .../server/profile/DTimedMetricMap.java | 20 ++- .../server/profile/DTimedProfileLocation.java | 12 +- .../server/profile/TimedProfileLocation.java | 8 +- .../server/query/CQueryPlan.java | 50 +++++-- .../server/query/CQueryPlanStats.java | 137 ++++++++---------- .../query/CQueryPlanStatsCollector.java | 32 ---- .../query/DefaultRelationalQueryEngine.java | 17 +++ .../server/querydefn/DefaultDtoQuery.java | 3 +- .../server/querydefn/DefaultOrmQuery.java | 13 ++ .../server/querydefn/DefaultOrmUpdate.java | 14 ++ .../querydefn/DefaultRelationalQuery.java | 13 ++ .../transaction/TransactionManager.java | 30 ++-- src/test/java/io/ebean/BaseTestCase.java | 25 ++++ .../java/io/ebean/DtoQueryFromOrmTest.java | 44 ++++-- src/test/java/io/ebean/DtoQueryTest.java | 14 +- src/test/java/io/ebean/UpdateQueryTest.java | 13 +- .../ebeaninternal/api/TDSpiEbeanServer.java | 6 + .../profile/BasicProfileLocationTest.java | 3 +- .../batchinsert/TestBatchInsertFlush.java | 8 +- .../org/tests/m2m/TestM2mDeleteObject.java | 15 +- .../query/finder/TestCustomerFinder.java | 16 +- .../TestObjectGraphNodeStatsCollection.java | 23 +-- .../tests/query/sqlquery/SqlQueryTests.java | 24 ++- .../transaction/TestNestedMandatory.java | 8 +- .../org/tests/update/TestSqlUpdateInTxn.java | 12 +- src/test/resources/ebean.properties | 2 +- 79 files changed, 928 insertions(+), 466 deletions(-) create mode 100644 src/main/java/io/ebean/meta/AbstractMetricVisitor.java create mode 100644 src/main/java/io/ebean/meta/BasicMetricVisitor.java create mode 100644 src/main/java/io/ebean/meta/MetaOrmQueryMetric.java rename src/main/java/io/ebean/meta/{MetaObjectGraphNodeStats.java => MetaOrmQueryNode.java} (88%) rename src/main/java/io/ebean/meta/{MetaQueryPlanOriginCount.java => MetaOrmQueryOrigin.java} (83%) delete mode 100644 src/main/java/io/ebean/meta/MetaQueryPlanStatistic.java create mode 100644 src/main/java/io/ebean/meta/MetricType.java create mode 100644 src/main/java/io/ebean/meta/MetricVisitor.java delete mode 100644 src/main/java/io/ebeaninternal/server/query/CQueryPlanStatsCollector.java diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java index 588a6f7c0..4723ab212 100644 --- a/src/main/java/io/ebean/ExpressionList.java +++ b/src/main/java/io/ebean/ExpressionList.java @@ -545,6 +545,11 @@ public interface ExpressionList { */ Query setDisableReadAuditing(); + /** + * Set a label on the query (to help identify query execution statistics). + */ + Query setLabel(String label); + /** * Add expressions to the having clause. *

diff --git a/src/main/java/io/ebean/Query.java b/src/main/java/io/ebean/Query.java index c5a5f425e..4d18a580d 100644 --- a/src/main/java/io/ebean/Query.java +++ b/src/main/java/io/ebean/Query.java @@ -1419,6 +1419,15 @@ public interface Query { */ Query setProfileLocation(ProfileLocation profileLocation); + /** + * Set a label on the query. + *

+ * This label can be used to help identify query performance metrics but we can also use + * profile location enhancement on Finders so for some that would be a better option. + *

+ */ + Query setLabel(String label); + /** * Set to true if this query should execute against the doc store. *

diff --git a/src/main/java/io/ebean/SqlQuery.java b/src/main/java/io/ebean/SqlQuery.java index a83aa9319..6c1bcf00b 100644 --- a/src/main/java/io/ebean/SqlQuery.java +++ b/src/main/java/io/ebean/SqlQuery.java @@ -115,6 +115,11 @@ public interface SqlQuery extends Serializable { */ SqlQuery setTimeout(int secs); + /** + * Set a label that can be put on performance metrics that are collected. + */ + SqlQuery setLabel(String label); + /** * A hint which for JDBC translates to the Statement.fetchSize(). *

diff --git a/src/main/java/io/ebean/Update.java b/src/main/java/io/ebean/Update.java index 637fb2c8c..70c225ce3 100644 --- a/src/main/java/io/ebean/Update.java +++ b/src/main/java/io/ebean/Update.java @@ -152,6 +152,11 @@ public interface Update { */ Update setNullParameter(String name, int jdbcType); + /** + * Set a label meaning performance metrics will be collected for the execution of this update. + */ + Update setLabel(String label); + /** * Return the sql that is actually executed. */ diff --git a/src/main/java/io/ebean/meta/AbstractMetricVisitor.java b/src/main/java/io/ebean/meta/AbstractMetricVisitor.java new file mode 100644 index 000000000..c2eb25b99 --- /dev/null +++ b/src/main/java/io/ebean/meta/AbstractMetricVisitor.java @@ -0,0 +1,43 @@ +package io.ebean.meta; + +/** + * An abstract MetricVisitor that handles the boolean flags - reset, collectTransactionMetrics and collectQueryMetrics. + */ +public abstract class AbstractMetricVisitor implements MetricVisitor { + + private final boolean reset; + private final boolean collectTransactionMetrics; + private final boolean collectQueryMetrics; + + public AbstractMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) { + this.reset = reset; + this.collectTransactionMetrics = collectTransactionMetrics; + this.collectQueryMetrics = collectQueryMetrics; + } + + @Override + public boolean isReset() { + return reset; + } + + @Override + public boolean isCollectTransactionMetrics() { + return collectTransactionMetrics; + } + + @Override + public boolean isCollectQueryMetrics() { + return collectQueryMetrics; + } + + @Override + public void visitStart() { + // do nothing by default + } + + @Override + public void visitEnd() { + // do nothing by default + } +} + diff --git a/src/main/java/io/ebean/meta/BasicMetricVisitor.java b/src/main/java/io/ebean/meta/BasicMetricVisitor.java new file mode 100644 index 000000000..bef165ed9 --- /dev/null +++ b/src/main/java/io/ebean/meta/BasicMetricVisitor.java @@ -0,0 +1,64 @@ +package io.ebean.meta; + +import java.util.ArrayList; +import java.util.List; + +/** + * A simple MetricVisitor that can collect the desired metrics into lists. + */ +public class BasicMetricVisitor extends AbstractMetricVisitor { + + private final List timed = new ArrayList<>(); + private final List dtoQuery = new ArrayList<>(); + private final List ormQuery = new ArrayList<>(); + + /** + * Construct to reset and collect everything. + */ + public BasicMetricVisitor() { + super(true, true, true); + } + + /** + * Construct specifying reset and what to collect. + */ + public BasicMetricVisitor(boolean reset, boolean collectTransactionMetrics, boolean collectQueryMetrics) { + super(reset, collectTransactionMetrics, collectQueryMetrics); + } + + /** + * Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate. + */ + public List getTimedMetrics() { + return timed; + } + + /** + * Return the DTO query metrics. + */ + public List getDtoQueryMetrics() { + return dtoQuery; + } + + /** + * Return the ORM query metrics. + */ + public List getOrmQueryMetrics() { + return ormQuery; + } + + @Override + public void visitTimed(MetaTimedMetric metric) { + timed.add(metric); + } + + @Override + public void visitQuery(MetaQueryMetric metric) { + dtoQuery.add(metric); + } + + @Override + public void visitOrmQuery(MetaOrmQueryMetric metric) { + ormQuery.add(metric); + } +} diff --git a/src/main/java/io/ebean/meta/MetaInfoManager.java b/src/main/java/io/ebean/meta/MetaInfoManager.java index c8d88cf83..9535de536 100644 --- a/src/main/java/io/ebean/meta/MetaInfoManager.java +++ b/src/main/java/io/ebean/meta/MetaInfoManager.java @@ -8,23 +8,20 @@ import java.util.List; public interface MetaInfoManager { /** - * Collect and return the transaction execution metrics. + * Visit the metrics resetting and collecting/reporting as desired. */ - List collectTransactionStatistics(boolean reset); + void visitMetrics(MetricVisitor visitor); /** - * Collect query plan statistics (new, will migrate ORM query stats over to this). + * Run a visit collecting all the metrics and returning BasicMetricVisitor + * which holds all the metrics in simple lists. */ - List collectQueryStatistics(boolean reset); + BasicMetricVisitor visitBasic(); /** - * Collect and return the non-empty query plan statistics for all the beans. - *

- * Note that this excludes the query plan statistics where there has been no - * executions (since the last collection with reset). - *

+ * Just reset all the metrics. Maybe only useful for testing purposes. */ - List collectQueryPlanStatistics(boolean reset); + void resetAllMetrics(); /** * Collect and return the ObjectGraphNode statistics. @@ -36,6 +33,6 @@ public interface MetaInfoManager { * * @param reset Set to true to reset the underlying statistics after collection. */ - List collectNodeStatistics(boolean reset); + List collectNodeStatistics(boolean reset); } diff --git a/src/main/java/io/ebean/meta/MetaOrmQueryMetric.java b/src/main/java/io/ebean/meta/MetaOrmQueryMetric.java new file mode 100644 index 000000000..7a74409f2 --- /dev/null +++ b/src/main/java/io/ebean/meta/MetaOrmQueryMetric.java @@ -0,0 +1,42 @@ +package io.ebean.meta; + +import io.ebean.ProfileLocation; + +import java.util.List; + +/** + * Query execution statistics for Orm queries. + */ +public interface MetaOrmQueryMetric extends MetaQueryMetric { + + /** + * Return the profile location. + */ + ProfileLocation getProfileLocation(); + + /** + * Return true if this query plan was tuned by AutoTune. + */ + boolean isAutoTuned(); + + /** + * Return a string representation of the query plan hash. + */ + String getQueryPlanHash(); + + /** + * Return the time of the last query executed using this plan. + */ + long getLastQueryTime(); + + /** + * Return the 'origin' points and paths that resulted in the query being + * executed and the associated number of times the query was executed via that + * path. + *

+ * This includes direct and lazy loading paths. + *

+ */ + List getOrigins(); + +} diff --git a/src/main/java/io/ebean/meta/MetaObjectGraphNodeStats.java b/src/main/java/io/ebean/meta/MetaOrmQueryNode.java similarity index 88% rename from src/main/java/io/ebean/meta/MetaObjectGraphNodeStats.java rename to src/main/java/io/ebean/meta/MetaOrmQueryNode.java index 81421978b..0f1d6bd24 100644 --- a/src/main/java/io/ebean/meta/MetaObjectGraphNodeStats.java +++ b/src/main/java/io/ebean/meta/MetaOrmQueryNode.java @@ -8,10 +8,8 @@ import io.ebean.bean.ObjectGraphNode; * These statistics can be used to identify origin queries that result in lots * of lazy loading. *

- * - * @see MetaInfoManager#collectNodeStatistics(boolean) */ -public interface MetaObjectGraphNodeStats { +public interface MetaOrmQueryNode { /** * Return the ObjectGraphNode which has the origin point and relative path. diff --git a/src/main/java/io/ebean/meta/MetaQueryPlanOriginCount.java b/src/main/java/io/ebean/meta/MetaOrmQueryOrigin.java similarity index 83% rename from src/main/java/io/ebean/meta/MetaQueryPlanOriginCount.java rename to src/main/java/io/ebean/meta/MetaOrmQueryOrigin.java index 6ca5b3827..9f4d2f096 100644 --- a/src/main/java/io/ebean/meta/MetaQueryPlanOriginCount.java +++ b/src/main/java/io/ebean/meta/MetaOrmQueryOrigin.java @@ -9,11 +9,8 @@ import io.ebean.bean.ObjectGraphNode; * This basically points to the bit of original code and query that results in * this query directly or via lazy loading. *

- * - * @see MetaQueryPlanStatistic - * @see MetaInfoManager#collectQueryPlanStatistics(boolean) */ -public interface MetaQueryPlanOriginCount { +public interface MetaOrmQueryOrigin { /** * The 'origin' and path which this query belongs to. diff --git a/src/main/java/io/ebean/meta/MetaQueryPlanStatistic.java b/src/main/java/io/ebean/meta/MetaQueryPlanStatistic.java deleted file mode 100644 index fc01a0e7e..000000000 --- a/src/main/java/io/ebean/meta/MetaQueryPlanStatistic.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.ebean.meta; - -import io.ebean.ProfileLocation; - -import java.util.List; - -/** - * Query execution statistics Meta data. - * - * @see MetaInfoManager#collectQueryPlanStatistics(boolean) - */ -public interface MetaQueryPlanStatistic { - - /** - * Return the bean type this query plan is for. - */ - Class getBeanType(); - - /** - * Return the profile location. - */ - ProfileLocation getProfileLocation(); - - /** - * Return true if this query plan was tuned by AutoTune. - */ - boolean isAutoTuned(); - - /** - * Return a string representation of the query plan hash. - */ - String getQueryPlanHash(); - - /** - * Return the sql executed. - */ - String getSql(); - - /** - * Return the total number of queries executed. - */ - long getExecutionCount(); - - /** - * Return the total number of beans loaded by the queries. - *

- * This excludes background fetching. - *

- */ - long getTotalLoadedBeans(); - - /** - * Return the total time taken by executions of this query. - */ - long getTotalTimeMicros(); - - /** - * Return the max execution time for this query. - */ - long getMaxTimeMicros(); - - /** - * Return the time collection started (or was last reset). - */ - long getCollectionStart(); - - /** - * Return the time of the last query executed using this plan. - */ - long getLastQueryTime(); - - /** - * Return the average query execution time in microseconds. - *

- * This excludes background fetching. - *

- */ - long getAvgTimeMicros(); - - /** - * Return the average number of bean loaded per query. - *

- * This excludes background fetching. - *

- */ - long getAvgLoadedBeans(); - - /** - * Return the 'origin' points and paths that resulted in the query being - * executed and the associated number of times the query was executed via that - * path. - *

- * This includes direct and lazy loading paths. - *

- */ - List getOrigins(); - -} diff --git a/src/main/java/io/ebean/meta/MetaTimedMetric.java b/src/main/java/io/ebean/meta/MetaTimedMetric.java index ada73a66f..53f67109d 100644 --- a/src/main/java/io/ebean/meta/MetaTimedMetric.java +++ b/src/main/java/io/ebean/meta/MetaTimedMetric.java @@ -6,6 +6,11 @@ package io.ebean.meta; */ public interface MetaTimedMetric { + /** + * Return the metric type. + */ + MetricType getMetricType(); + /** * Return the metric name. */ diff --git a/src/main/java/io/ebean/meta/MetricType.java b/src/main/java/io/ebean/meta/MetricType.java new file mode 100644 index 000000000..6b39cbc47 --- /dev/null +++ b/src/main/java/io/ebean/meta/MetricType.java @@ -0,0 +1,30 @@ +package io.ebean.meta; + +/** + * The type of Metric. + */ +public enum MetricType { + + /** + * Transactions. + */ + TXN, + + /** + * ORM queries. + */ + ORM, + + /** + * DTO queries. + */ + DTO, + + /** + * SQL queries with a label will have metrics collected. + *

+ * SqlQuery and SqlUpdate without a label have no metrics collected. + */ + SQL + +} diff --git a/src/main/java/io/ebean/meta/MetricVisitor.java b/src/main/java/io/ebean/meta/MetricVisitor.java new file mode 100644 index 000000000..8b39e6499 --- /dev/null +++ b/src/main/java/io/ebean/meta/MetricVisitor.java @@ -0,0 +1,48 @@ +package io.ebean.meta; + +/** + * Defines visitor to read and report the transaction and query metrics. + */ +public interface MetricVisitor { + + /** + * Return true if the metrics should be reset. + */ + boolean isReset(); + + /** + * Return true if we should visit the transaction metrics. + */ + boolean isCollectTransactionMetrics(); + + /** + * Return true if we should visit the ORM and SQL query metrics. + */ + boolean isCollectQueryMetrics(); + + /** + * Visit has started. + */ + void visitStart(); + + /** + * Visit transaction metrics (and L2 cache metrics in future). + */ + void visitTimed(MetaTimedMetric metric); + + /** + * Visit DTO and SQL query metrics. + */ + void visitQuery(MetaQueryMetric metric); + + /** + * Visit ORM query metrics. + */ + void visitOrmQuery(MetaOrmQueryMetric metric); + + /** + * Visit has completed. + */ + void visitEnd(); + +} diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java index 305672805..eb449157f 100644 --- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java @@ -14,6 +14,7 @@ import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditPrepare; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.core.timezone.DataTimeZone; @@ -257,4 +258,9 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL * Execute the underlying ORM query returning as a JDBC ResultSet to map to DTO beans. */ SpiResultSet findResultSet(SpiQuery ormQuery, SpiTransaction transaction); + + /** + * Visit all the metrics (typically reporting them). + */ + void visitMetrics(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index adaa9f422..4f7184830 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -179,6 +179,11 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { */ ProfileLocation getProfileLocation(); + /** + * Return the label set on the query. + */ + String getLabel(); + /** * Return true if this is a "find by id" query. This includes a check for a single "equal to" expression for the Id. */ diff --git a/src/main/java/io/ebeaninternal/api/SpiSqlBinding.java b/src/main/java/io/ebeaninternal/api/SpiSqlBinding.java index 6da641dea..849ad0cb0 100644 --- a/src/main/java/io/ebeaninternal/api/SpiSqlBinding.java +++ b/src/main/java/io/ebeaninternal/api/SpiSqlBinding.java @@ -15,6 +15,11 @@ public interface SpiSqlBinding { */ String getQuery(); + /** + * Return the label (to collect metrics on when set). + */ + String getLabel(); + /** * Return the first row to fetch. */ diff --git a/src/main/java/io/ebeaninternal/api/SpiUpdate.java b/src/main/java/io/ebeaninternal/api/SpiUpdate.java index ebe8e5ab8..2e2ed8531 100644 --- a/src/main/java/io/ebeaninternal/api/SpiUpdate.java +++ b/src/main/java/io/ebeaninternal/api/SpiUpdate.java @@ -43,6 +43,11 @@ public interface SpiUpdate extends Update { */ Class getBeanType(); + /** + * Return the label (for metrics collection). + */ + String getLabel(); + /** * Return the type of this - insert, update or delete. */ diff --git a/src/main/java/io/ebeaninternal/metric/MetricFactory.java b/src/main/java/io/ebeaninternal/metric/MetricFactory.java index 6f83c3e89..72ccbb3ad 100644 --- a/src/main/java/io/ebeaninternal/metric/MetricFactory.java +++ b/src/main/java/io/ebeaninternal/metric/MetricFactory.java @@ -1,5 +1,7 @@ package io.ebeaninternal.metric; +import io.ebean.meta.MetricType; + /** * Factory to create timed metric counters. */ @@ -15,20 +17,16 @@ public interface MetricFactory { /** * Create a timed metric group. */ - TimedMetricMap createTimedMetricMap(String name); + TimedMetricMap createTimedMetricMap(MetricType metricType, String name); /** * Create a Timed metric. */ - TimedMetric createTimedMetric(String name); + TimedMetric createTimedMetric(MetricType metricType, String name); /** * Create a Timed metric. */ - QueryPlanMetric createQueryPlanMetric(Class type, String label, String sql); + QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class type, String label, String sql); - /** - * Return a instance used to collect Query plan metrics. - */ - QueryPlanCollector createCollector(boolean reset); } diff --git a/src/main/java/io/ebeaninternal/metric/QueryPlanMetric.java b/src/main/java/io/ebeaninternal/metric/QueryPlanMetric.java index 893a97593..f0d5e31db 100644 --- a/src/main/java/io/ebeaninternal/metric/QueryPlanMetric.java +++ b/src/main/java/io/ebeaninternal/metric/QueryPlanMetric.java @@ -1,5 +1,7 @@ package io.ebeaninternal.metric; +import io.ebean.meta.MetricVisitor; + /** * Internal Query plan metric holder. */ @@ -11,7 +13,7 @@ public interface QueryPlanMetric { TimedMetric getMetric(); /** - * Collect the non-empty query plan metrics. + * Visit the underlying metric. */ - void collect(QueryPlanCollector collector); + void visit(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/metric/TimedMetric.java b/src/main/java/io/ebeaninternal/metric/TimedMetric.java index a2a29e030..1bba42bb0 100644 --- a/src/main/java/io/ebeaninternal/metric/TimedMetric.java +++ b/src/main/java/io/ebeaninternal/metric/TimedMetric.java @@ -1,8 +1,6 @@ package io.ebeaninternal.metric; -import io.ebean.meta.MetaTimedMetric; - -import java.util.List; +import io.ebean.meta.MetricVisitor; /** * Metric for timed events like transaction execution times. @@ -25,12 +23,17 @@ public interface TimedMetric { boolean isEmpty(); /** - * Collect the timed metric statistics. + * Reset the statistics. + */ + void reset(); + + /** + * Collect and return a snapshot of the metrics. */ TimedMetricStats collect(boolean reset); /** - * Add non empty metrics to the result. + * Visit non empty metrics. */ - void collect(boolean reset, List result); + void visit(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/metric/TimedMetricMap.java b/src/main/java/io/ebeaninternal/metric/TimedMetricMap.java index 3976b5121..801bc74c1 100644 --- a/src/main/java/io/ebeaninternal/metric/TimedMetricMap.java +++ b/src/main/java/io/ebeaninternal/metric/TimedMetricMap.java @@ -1,8 +1,6 @@ package io.ebeaninternal.metric; -import io.ebean.meta.MetaTimedMetric; - -import java.util.List; +import io.ebean.meta.MetricVisitor; /** * A map of timed metrics keyed by a string. @@ -15,7 +13,12 @@ public interface TimedMetricMap { void add(String key, long exeMicros); /** - * Add non empty metrics to the given result. + * Add an execution for the given key including row/bean count. */ - void collect(boolean reset, List result); + void add(String key, long exeMicros, int rows); + + /** + * Visit the metric. + */ + void visit(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java index 03feedaf4..41371c912 100644 --- a/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/AbstractSqlQueryRequest.java @@ -24,7 +24,7 @@ import java.sql.SQLException; */ public abstract class AbstractSqlQueryRequest { - private final SpiSqlBinding query; + protected final SpiSqlBinding query; protected final SpiEbeanServer server; diff --git a/src/main/java/io/ebeaninternal/server/core/CObjectGraphNodeStatistics.java b/src/main/java/io/ebeaninternal/server/core/CObjectGraphNodeStatistics.java index 754c0a990..8b53a86aa 100644 --- a/src/main/java/io/ebeaninternal/server/core/CObjectGraphNodeStatistics.java +++ b/src/main/java/io/ebeaninternal/server/core/CObjectGraphNodeStatistics.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.core; import io.ebean.bean.ObjectGraphNode; -import io.ebean.meta.MetaObjectGraphNodeStats; +import io.ebean.meta.MetaOrmQueryNode; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; @@ -35,7 +35,7 @@ public class CObjectGraphNodeStatistics { totalBeans.add(beanCount); } - public MetaObjectGraphNodeStats get(boolean reset) { + public MetaOrmQueryNode get(boolean reset) { if (reset) { return new Snapshot(node, startTime.getAndSet(System.currentTimeMillis()), count.sumThenReset(), totalTime.sumThenReset(), totalBeans.sumThenReset()); @@ -44,7 +44,7 @@ public class CObjectGraphNodeStatistics { } } - private static class Snapshot implements MetaObjectGraphNodeStats { + private static class Snapshot implements MetaOrmQueryNode { private final ObjectGraphNode node; private final long startTime; diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java index b52c66390..6ebc4152d 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultMetaInfoManager.java @@ -1,12 +1,13 @@ package io.ebeaninternal.server.core; +import io.ebean.meta.AbstractMetricVisitor; +import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaInfoManager; -import io.ebean.meta.MetaObjectGraphNodeStats; +import io.ebean.meta.MetaOrmQueryMetric; +import io.ebean.meta.MetaOrmQueryNode; import io.ebean.meta.MetaQueryMetric; -import io.ebean.meta.MetaQueryPlanStatistic; import io.ebean.meta.MetaTimedMetric; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.query.CQueryPlanStatsCollector; +import io.ebean.meta.MetricVisitor; import java.util.ArrayList; import java.util.List; @@ -23,29 +24,26 @@ public class DefaultMetaInfoManager implements MetaInfoManager { } @Override - public List collectTransactionStatistics(boolean reset) { - return server.collectTransactionStatistics(reset); + public void visitMetrics(MetricVisitor visitor) { + server.visitMetrics(visitor); } @Override - public List collectQueryStatistics(boolean reset) { - return server.collectQueryStatistics(reset); + public BasicMetricVisitor visitBasic() { + BasicMetricVisitor basic = new BasicMetricVisitor(); + visitMetrics(basic); + return basic; } @Override - public List collectQueryPlanStatistics(boolean reset) { - - CQueryPlanStatsCollector collector = new CQueryPlanStatsCollector(reset); - for (BeanDescriptor desc : server.getBeanDescriptors()) { - desc.collectQueryPlanStatistics(collector); - } - return collector.getList(); + public void resetAllMetrics() { + server.visitMetrics(new ResetVisitor()); } @Override - public List collectNodeStatistics(boolean reset) { + public List collectNodeStatistics(boolean reset) { - List list = new ArrayList<>(); + List list = new ArrayList<>(); for (CObjectGraphNodeStatistics nodeStatistics : server.objectGraphStats.values()) { if (!nodeStatistics.isEmpty()) { list.add(nodeStatistics.get(reset)); @@ -54,4 +52,29 @@ public class DefaultMetaInfoManager implements MetaInfoManager { return list; } + /** + * Visitor that resets the statistics but doesn't collect them. + */ + private static class ResetVisitor extends AbstractMetricVisitor { + + ResetVisitor() { + super(true, true, true); + } + + @Override + public void visitTimed(MetaTimedMetric metric) { + // ignore + } + + @Override + public void visitQuery(MetaQueryMetric metric) { + // ignore + } + + @Override + public void visitOrmQuery(MetaOrmQueryMetric metric) { + // ignore + } + } + } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 6629aee54..700f10439 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -48,8 +48,7 @@ import io.ebean.event.BeanPersistController; import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebean.meta.MetaInfoManager; -import io.ebean.meta.MetaQueryMetric; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricVisitor; import io.ebean.plugin.BeanType; import io.ebean.plugin.Plugin; import io.ebean.plugin.Property; @@ -2192,10 +2191,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } - public List collectTransactionStatistics(boolean reset) { - return transactionManager.collectTransactionStatistics(reset); - } - @Override public Set checkUniqueness(Object bean) { return checkUniqueness(bean, null); @@ -2237,8 +2232,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { /** - * Returns a set of properties if saving the bean will violate the unique constraints - * (definded by given properties). + * Returns a set of properties if saving the bean will violate the unique constraints (defined by given properties). */ private Set checkUniqueness(EntityBean entityBean, BeanDescriptor beanDesc, BeanProperty[] props, Transaction transaction) { @@ -2261,15 +2255,24 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { if (findCount(query, transaction) > 0) { Set ret = new LinkedHashSet<>(); - for (Property prop : props) { - ret.add(prop); - } + Collections.addAll(ret, props); return ret; } return null; } - public List collectQueryStatistics(boolean reset) { - return dtoBeanManager.collectStats(reset); + @Override + public void visitMetrics(MetricVisitor visitor) { + visitor.visitStart(); + if (visitor.isCollectTransactionMetrics()) { + transactionManager.visitMetrics(visitor); + } + if (visitor.isCollectQueryMetrics()) { + beanDescriptorManager.visitMetrics(visitor); + dtoBeanManager.visitMetrics(visitor); + relationalQueryEngine.visitMetrics(visitor); + persister.visitMetrics(visitor); + } + visitor.visitEnd(); } } diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequest.java b/src/main/java/io/ebeaninternal/server/core/PersistRequest.java index c74515a7c..46e7aa605 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequest.java @@ -22,6 +22,7 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe UPDATESQL(EVT_UPDATESQL), CALLABLESQL(EVT_CALLABLESQL); String profileEventId; + Type(String profileEventId) { this.profileEventId = profileEventId; } @@ -36,12 +37,30 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe final PersistExecute persistExecute; + protected String label; + + protected long startNanos; + + PersistRequest(SpiEbeanServer server, SpiTransaction t, PersistExecute persistExecute) { + super(server, t); + this.persistExecute = persistExecute; + } + /** * Used by CallableSqlRequest and UpdateSqlRequest. */ - public PersistRequest(SpiEbeanServer server, SpiTransaction t, PersistExecute persistExecute) { - super(server, t); - this.persistExecute = persistExecute; + PersistRequest(SpiEbeanServer server, SpiTransaction t, PersistExecute persistExecute, String label) { + this(server, t, persistExecute); + this.label = label; + } + + /** + * Effectively set start nanos if we are collecting metrics on a label. + */ + public void startBind(boolean batchThisRequest) { + if (!batchThisRequest && label != null) { + startNanos = System.nanoTime(); + } } /** diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestCallableSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestCallableSql.java index 7f203678e..432a4eb49 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestCallableSql.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestCallableSql.java @@ -31,10 +31,9 @@ public final class PersistRequestCallableSql extends PersistRequest { /** * Create. */ - public PersistRequestCallableSql(SpiEbeanServer server, - CallableSql cs, SpiTransaction t, PersistExecute persistExecute) { + public PersistRequestCallableSql(SpiEbeanServer server, CallableSql cs, SpiTransaction t, PersistExecute persistExecute) { - super(server, t, persistExecute); + super(server, t, persistExecute, cs.getLabel()); this.type = PersistRequest.Type.CALLABLESQL; this.callableSql = (SpiCallableSql) cs; } @@ -88,7 +87,9 @@ public final class PersistRequestCallableSql extends PersistRequest { */ @Override public void postExecute() { - + if (startNanos > 0) { + persistExecute.collectSqlCall(label, startNanos, rowCount); + } if (transaction.isLogSummary()) { String m = "CallableSql label[" + callableSql.getLabel() + "]" + " rows[" + rowCount + "]" + " bind[" + bindLog + "]"; transaction.logSummary(m); diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestOrmUpdate.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestOrmUpdate.java index 4a55f9db6..aa2f3092e 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestOrmUpdate.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestOrmUpdate.java @@ -27,7 +27,7 @@ public final class PersistRequestOrmUpdate extends PersistRequest { public PersistRequestOrmUpdate(SpiEbeanServer server, BeanManager mgr, SpiUpdate ormUpdate, SpiTransaction t, PersistExecute persistExecute) { - super(server, t, persistExecute); + super(server, t, persistExecute, ormUpdate.getLabel()); this.beanDescriptor = mgr.getBeanDescriptor(); this.ormUpdate = ormUpdate; } @@ -86,7 +86,9 @@ public final class PersistRequestOrmUpdate extends PersistRequest { */ @Override public void postExecute() { - + if (startNanos > 0) { + persistExecute.collectOrmUpdate(label, startNanos, rowCount); + } OrmUpdateType ormUpdateType = ormUpdate.getOrmUpdateType(); String tableName = ormUpdate.getBaseTable(); diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java index 05fd26cd6..5261de3f9 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java @@ -33,7 +33,7 @@ public final class PersistRequestUpdateSql extends PersistRequest { public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate updateSql, SpiTransaction t, PersistExecute persistExecute) { - super(server, t, persistExecute); + super(server, t, persistExecute, updateSql.getLabel()); this.type = Type.UPDATESQL; this.updateSql = (SpiSqlUpdate) updateSql; } @@ -102,7 +102,9 @@ public final class PersistRequestUpdateSql extends PersistRequest { */ @Override public void postExecute() { - + if (startNanos > 0) { + persistExecute.collectSqlUpdate(label, startNanos, rowCount); + } if (transaction.isLogSummary()) { String m = description + " table[" + tableName + "] rows[" + rowCount + "] bind[" + bindLog + "]"; transaction.logSummary(m); diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java index f6044d040..981032053 100644 --- a/src/main/java/io/ebeaninternal/server/core/Persister.java +++ b/src/main/java/io/ebeaninternal/server/core/Persister.java @@ -6,6 +6,7 @@ import io.ebean.SqlUpdate; import io.ebean.Transaction; import io.ebean.Update; import io.ebean.bean.EntityBean; +import io.ebean.meta.MetricVisitor; import java.util.Collection; import java.util.List; @@ -78,4 +79,8 @@ public interface Persister { */ List draftRestore(Query query, Transaction transaction); + /** + * Visit the metrics. + */ + void visitMetrics(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/core/RelationalQueryEngine.java b/src/main/java/io/ebeaninternal/server/core/RelationalQueryEngine.java index ae4dde8f1..fa2a13b93 100644 --- a/src/main/java/io/ebeaninternal/server/core/RelationalQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/core/RelationalQueryEngine.java @@ -2,6 +2,7 @@ package io.ebeaninternal.server.core; import io.ebean.SqlRow; +import io.ebean.meta.MetricVisitor; import java.util.List; import java.util.function.Consumer; @@ -29,4 +30,13 @@ public interface RelationalQueryEngine { */ void findEach(RelationalQueryRequest request, Predicate consumer); + /** + * Collect SQL query execution statistics. + */ + void collect(String label, long exeMicros, int rows); + + /** + * Visit the metrics. + */ + void visitMetrics(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java index dace84109..24278ea11 100644 --- a/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/RelationalQueryRequest.java @@ -46,7 +46,11 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest { @Override protected void requestComplete() { - + String label = query.getLabel(); + if (label != null) { + long exeMicros = (System.nanoTime() - startNano) / 1000L; + queryEngine.collect(label, exeMicros, rows); + } } public void findEach(Consumer consumer) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 06810d7e0..8ba1b5ae6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -27,6 +27,7 @@ import io.ebean.event.changelog.ChangeType; import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebean.event.readaudit.ReadEvent; +import io.ebean.meta.MetricVisitor; import io.ebean.plugin.BeanDocType; import io.ebean.plugin.BeanType; import io.ebean.plugin.ExpressionPath; @@ -61,7 +62,6 @@ import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.DmlUtil; import io.ebeaninternal.server.query.CQueryPlan; -import io.ebeaninternal.server.query.CQueryPlanStatsCollector; import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.rawsql.SpiRawSql; @@ -1598,10 +1598,13 @@ public class BeanDescriptor implements BeanType { return new DeployUpdateParser(this).parse(ormUpdateStatement); } - public void collectQueryPlanStatistics(CQueryPlanStatsCollector collector) { + /** + * Visit all the ORM query plan metrics (includes UpdateQuery with updates and deletes). + */ + public void visitMetrics(MetricVisitor visitor) { for (CQueryPlan queryPlan : queryPlanCache.values()) { if (!queryPlan.isEmptyStats()) { - collector.add(queryPlan.getSnapshot(collector.isReset())); + visitor.visitOrmQuery(queryPlan.getSnapshot(visitor.isReset())); } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index b0044d91a..d1d449120 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -19,6 +19,7 @@ import io.ebean.event.changelog.ChangeLogFilter; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeLogRegister; +import io.ebean.meta.MetricVisitor; import io.ebean.plugin.BeanType; import io.ebean.util.AnnotationUtil; import io.ebeaninternal.api.ConcurrencyMode; @@ -1632,6 +1633,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap { target.setPrimaryKeyJoin(inverseJoin); } + public void visitMetrics(MetricVisitor visitor) { + for (BeanDescriptor desc : immutableDescriptorList) { + desc.visitMetrics(visitor); + } + } + /** * Comparator to sort the BeanDescriptors by name. */ diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java index 81920e858..04060e8a4 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java @@ -1,6 +1,6 @@ package io.ebeaninternal.server.dto; -import io.ebeaninternal.metric.QueryPlanCollector; +import io.ebean.meta.MetricVisitor; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -37,9 +37,9 @@ public class DtoBeanDescriptor { plans.put(planKey, plan); } - public void collectStats(QueryPlanCollector collector) { + public void visit(MetricVisitor visitor) { for (DtoQueryPlan plan : plans.values()) { - plan.collectStats(collector); + plan.visit(visitor); } } } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java index 87e58a453..7cbd9488d 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java @@ -1,11 +1,8 @@ package io.ebeaninternal.server.dto; -import io.ebean.meta.MetaQueryMetric; -import io.ebeaninternal.metric.MetricFactory; -import io.ebeaninternal.metric.QueryPlanCollector; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.server.type.TypeManager; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -41,13 +38,9 @@ public class DtoBeanManager { } } - public List collectStats(boolean reset) { - - QueryPlanCollector collector = MetricFactory.get().createCollector(reset); - + public void visitMetrics(MetricVisitor visitor) { for (DtoBeanDescriptor value : descriptorMap.values()) { - value.collectStats(collector); + value.visit(visitor); } - return collector.complete(); } } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoMappingRequest.java b/src/main/java/io/ebeaninternal/server/dto/DtoMappingRequest.java index d781e35c0..c7ab221ef 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoMappingRequest.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoMappingRequest.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.dto; +import io.ebean.meta.MetricType; import io.ebeaninternal.api.SpiDtoQuery; import io.ebeaninternal.metric.MetricFactory; import io.ebeaninternal.metric.QueryPlanMetric; @@ -44,6 +45,6 @@ public class DtoMappingRequest { } public QueryPlanMetric createMetric() { - return MetricFactory.get().createQueryPlanMetric(type, label, sql); + return MetricFactory.get().createQueryPlanMetric(MetricType.DTO, type, label, sql); } } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlan.java b/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlan.java index 36d49c351..897e8cc5e 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlan.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlan.java @@ -1,6 +1,6 @@ package io.ebeaninternal.server.dto; -import io.ebeaninternal.metric.QueryPlanCollector; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.server.type.DataReader; import java.sql.SQLException; @@ -21,7 +21,7 @@ public interface DtoQueryPlan { void collect(long exeMicros, int rows); /** - * Collect the query plan statistics. + * Visit the metric (if not empty). */ - void collectStats(QueryPlanCollector collector); + void visit(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlanBase.java b/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlanBase.java index b4a867a50..b6218cbcd 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlanBase.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoQueryPlanBase.java @@ -1,6 +1,6 @@ package io.ebeaninternal.server.dto; -import io.ebeaninternal.metric.QueryPlanCollector; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.QueryPlanMetric; import io.ebeaninternal.metric.TimedMetric; @@ -21,8 +21,7 @@ abstract class DtoQueryPlanBase implements DtoQueryPlan { } @Override - public void collectStats(QueryPlanCollector collector) { - planMetric.collect(collector); + public void visit(MetricVisitor visitor) { + planMetric.visit(visitor); } - } diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index ec0e9b738..29747b439 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -513,6 +513,11 @@ public class DefaultExpressionList implements SpiExpressionList { return query.setDisableReadAuditing(); } + @Override + public Query setLabel(String label) { + return query.setLabel(label); + } + @Override public ExpressionList having() { return query.having(); diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index 6b54867ff..4d4c3a53c 100644 --- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -798,6 +798,11 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.setCountDistinct(orderBy); } + @Override + public Query setLabel(String label) { + return exprList.setLabel(label); + } + @Override public ExpressionList startsWith(String propertyName, String value) { return exprList.startsWith(propertyName, value); diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersistExecute.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersistExecute.java index edaee965d..621f8338a 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersistExecute.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersistExecute.java @@ -1,6 +1,10 @@ package io.ebeaninternal.server.persist; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.metric.MetricFactory; +import io.ebeaninternal.metric.TimedMetricMap; import io.ebeaninternal.server.core.PersistRequestCallableSql; import io.ebeaninternal.server.core.PersistRequestOrmUpdate; import io.ebeaninternal.server.core.PersistRequestUpdateSql; @@ -24,15 +28,48 @@ final class DefaultPersistExecute implements PersistExecute { */ private final int defaultBatchSize; + private final TimedMetricMap ormUpdateMetric; + + private final TimedMetricMap sqlUpdateMetric; + + private final TimedMetricMap sqlCallMetric; + /** * Construct this DmlPersistExecute. */ DefaultPersistExecute(Binder binder, int defaultBatchSize) { - this.exeOrmUpdate = new ExeOrmUpdate(binder); this.exeUpdateSql = new ExeUpdateSql(binder); this.exeCallableSql = new ExeCallableSql(binder); this.defaultBatchSize = defaultBatchSize; + this.ormUpdateMetric = MetricFactory.get().createTimedMetricMap(MetricType.SQL, "orm.update."); + this.sqlUpdateMetric = MetricFactory.get().createTimedMetricMap(MetricType.SQL, "sql.update."); + this.sqlCallMetric = MetricFactory.get().createTimedMetricMap(MetricType.SQL, "sql.call."); + } + + @Override + public void visitMetrics(MetricVisitor visitor) { + ormUpdateMetric.visit(visitor); + sqlUpdateMetric.visit(visitor); + sqlCallMetric.visit(visitor); + } + + @Override + public void collectOrmUpdate(String label, long startNanos, int rowCount) { + long exeMicros = (System.nanoTime() - startNanos) / 1000L; + ormUpdateMetric.add(label, exeMicros, rowCount); + } + + @Override + public void collectSqlUpdate(String label, long startNanos, int rowCount) { + long exeMicros = (System.nanoTime() - startNanos) / 1000L; + sqlUpdateMetric.add(label, exeMicros, rowCount); + } + + @Override + public void collectSqlCall(String label, long startNanos, int rowCount) { + long exeMicros = (System.nanoTime() - startNanos) / 1000L; + sqlCallMetric.add(label, exeMicros, rowCount); } @Override diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index a825c1653..0be2f64ae 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -10,6 +10,7 @@ import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; import io.ebean.event.BeanPersistController; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.api.SpiUpdate; @@ -79,6 +80,11 @@ public final class DefaultPersister implements Persister { this.persistExecute = new DefaultPersistExecute(binder, server.getServerConfig().getPersistBatchSize()); } + @Override + public void visitMetrics(MetricVisitor visitor) { + persistExecute.visitMetrics(visitor); + } + /** * Execute the CallableSql. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java index a1e8daa4e..3bc2dc3d2 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java @@ -60,6 +60,7 @@ class ExeCallableSql { private CallableStatement bindStmt(PersistRequestCallableSql request, boolean batchThisRequest) throws SQLException { + request.startBind(batchThisRequest); SpiCallableSql callableSql = request.getCallableSql(); SpiTransaction t = request.getTransaction(); diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java index 32faa0924..42cc54a98 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeOrmUpdate.java @@ -75,6 +75,7 @@ class ExeOrmUpdate { private PreparedStatement bindStmt(PersistRequestOrmUpdate request, boolean batchThisRequest) throws SQLException { + request.startBind(batchThisRequest); SpiUpdate ormUpdate = request.getOrmUpdate(); SpiTransaction t = request.getTransaction(); diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java index fd1f0c7d4..88879458d 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java @@ -83,6 +83,7 @@ class ExeUpdateSql { private PreparedStatement bindStmt(PersistRequestUpdateSql request, boolean batchThisRequest) throws SQLException { + request.startBind(batchThisRequest); SpiSqlUpdate updateSql = request.getUpdateSql(); SpiTransaction t = request.getTransaction(); diff --git a/src/main/java/io/ebeaninternal/server/persist/PersistExecute.java b/src/main/java/io/ebeaninternal/server/persist/PersistExecute.java index 04ce2db7c..283923fa8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/PersistExecute.java +++ b/src/main/java/io/ebeaninternal/server/persist/PersistExecute.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.persist; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.PersistRequestCallableSql; import io.ebeaninternal.server.core.PersistRequestOrmUpdate; @@ -34,4 +35,23 @@ public interface PersistExecute { */ int executeSqlUpdate(PersistRequestUpdateSql request); + /** + * Collect execution metrics for sql update. + */ + void collectOrmUpdate(String label, long startNanos, int rowCount); + + /** + * Collect execution metrics for sql update. + */ + void collectSqlUpdate(String label, long startNanos, int rowCount); + + /** + * Collect execution metrics for sql callable. + */ + void collectSqlCall(String label, long startNanos, int rowCount); + + /** + * Visit the metrics. + */ + void visitMetrics(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/profile/DMetricFactory.java b/src/main/java/io/ebeaninternal/server/profile/DMetricFactory.java index 8eae9626c..40cd2b36a 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DMetricFactory.java +++ b/src/main/java/io/ebeaninternal/server/profile/DMetricFactory.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.profile; +import io.ebean.meta.MetricType; import io.ebeaninternal.metric.MetricFactory; -import io.ebeaninternal.metric.QueryPlanCollector; import io.ebeaninternal.metric.QueryPlanMetric; import io.ebeaninternal.metric.TimedMetric; import io.ebeaninternal.metric.TimedMetricMap; @@ -12,22 +12,18 @@ import io.ebeaninternal.metric.TimedMetricMap; public class DMetricFactory implements MetricFactory { @Override - public TimedMetricMap createTimedMetricMap(String name) { - return new DTimedMetricMap(name); + public TimedMetricMap createTimedMetricMap(MetricType metricType, String name) { + return new DTimedMetricMap(metricType, name); } @Override - public TimedMetric createTimedMetric(String name) { - return new DTimedMetric(name); + public TimedMetric createTimedMetric(MetricType metricType, String name) { + return new DTimedMetric(metricType, name); } @Override - public QueryPlanMetric createQueryPlanMetric(Class type, String label, String sql) { - return new DQueryPlanMetric(new DQueryPlanMeta(type, label, sql), createTimedMetric(label)); + public QueryPlanMetric createQueryPlanMetric(MetricType metricType, Class type, String label, String sql) { + return new DQueryPlanMetric(new DQueryPlanMeta(type, label, sql), new DTimedMetric(metricType, label)); } - @Override - public QueryPlanCollector createCollector(boolean reset) { - return new DQueryPlanCollector(reset); - } } diff --git a/src/main/java/io/ebeaninternal/server/profile/DProfileLocationFactory.java b/src/main/java/io/ebeaninternal/server/profile/DProfileLocationFactory.java index 241c2a0ac..950e10740 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DProfileLocationFactory.java +++ b/src/main/java/io/ebeaninternal/server/profile/DProfileLocationFactory.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.profile; import io.ebean.ProfileLocation; +import io.ebean.meta.MetricType; import io.ebean.service.SpiProfileLocationFactory; import io.ebeaninternal.metric.MetricFactory; import io.ebeaninternal.metric.TimedMetric; @@ -18,7 +19,7 @@ public class DProfileLocationFactory implements SpiProfileLocationFactory { @Override public ProfileLocation create(int lineNumber, String label) { - TimedMetric timedMetric = MetricFactory.get().createTimedMetric("txn.named." + label); + TimedMetric timedMetric = MetricFactory.get().createTimedMetric(MetricType.TXN, "txn.named." + label); DTimedProfileLocation loc = new DTimedProfileLocation(lineNumber, label, timedMetric); TimedProfileLocationRegistry.register(loc); diff --git a/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java b/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java index b358a5584..1d7dff3e9 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java +++ b/src/main/java/io/ebeaninternal/server/profile/DQueryPlanMetric.java @@ -1,7 +1,8 @@ package io.ebeaninternal.server.profile; import io.ebean.meta.MetaQueryMetric; -import io.ebeaninternal.metric.QueryPlanCollector; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.QueryPlanMetric; import io.ebeaninternal.metric.TimedMetric; import io.ebeaninternal.metric.TimedMetricStats; @@ -9,18 +10,18 @@ import io.ebeaninternal.metric.TimedMetricStats; class DQueryPlanMetric implements QueryPlanMetric { private final DQueryPlanMeta meta; - private final TimedMetric metric; + private final DTimedMetric metric; - DQueryPlanMetric(DQueryPlanMeta meta, TimedMetric metric) { + DQueryPlanMetric(DQueryPlanMeta meta, DTimedMetric metric) { this.meta = meta; this.metric = metric; } @Override - public void collect(QueryPlanCollector collector) { - TimedMetricStats stats = metric.collect(collector.isReset()); + public void visit(MetricVisitor visitor) { + TimedMetricStats stats = metric.collect(visitor.isReset()); if (stats != null) { - collector.add(new Stats(meta, stats)); + visitor.visitQuery(new Stats(meta, stats)); } } @@ -44,6 +45,11 @@ class DQueryPlanMetric implements QueryPlanMetric { return meta + " " + stats + " sql:" + getSql(); } + @Override + public MetricType getMetricType() { + return stats.getMetricType(); + } + @Override public Class getType() { return meta.getType(); diff --git a/src/main/java/io/ebeaninternal/server/profile/DTimeMetricStats.java b/src/main/java/io/ebeaninternal/server/profile/DTimeMetricStats.java index 1a9d61f8f..dc446b4a6 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DTimeMetricStats.java +++ b/src/main/java/io/ebeaninternal/server/profile/DTimeMetricStats.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.profile; +import io.ebean.meta.MetricType; import io.ebeaninternal.metric.TimedMetricStats; /** @@ -7,6 +8,8 @@ import io.ebeaninternal.metric.TimedMetricStats; */ class DTimeMetricStats implements TimedMetricStats { + private final MetricType metricType; + private final String name; private String location; @@ -21,7 +24,8 @@ class DTimeMetricStats implements TimedMetricStats { private final long beanCount; - DTimeMetricStats(String name, long collectionStart, long count, long total, long max, long beanCount) { + DTimeMetricStats(MetricType metricType, String name, long collectionStart, long count, long total, long max, long beanCount) { + this.metricType = metricType; this.name = name; this.startTime = collectionStart; this.count = count; @@ -53,6 +57,11 @@ class DTimeMetricStats implements TimedMetricStats { this.location = location; } + @Override + public MetricType getMetricType() { + return metricType; + } + @Override public String getName() { return name; diff --git a/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java b/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java index 42a7f682c..bb7ee0b6f 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java +++ b/src/main/java/io/ebeaninternal/server/profile/DTimedMetric.java @@ -1,9 +1,9 @@ package io.ebeaninternal.server.profile; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.TimedMetric; -import java.util.List; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAccumulator; import java.util.concurrent.atomic.LongAdder; @@ -16,6 +16,8 @@ import java.util.concurrent.atomic.LongAdder; */ class DTimedMetric implements TimedMetric { + private final MetricType metricType; + private final String name; private final LongAdder beanCount = new LongAdder(); @@ -28,7 +30,8 @@ class DTimedMetric implements TimedMetric { private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis()); - DTimedMetric(String name) { + DTimedMetric(MetricType metricType, String name) { + this.metricType = metricType; this.name = name; } @@ -54,11 +57,23 @@ class DTimedMetric implements TimedMetric { return count.sum() == 0; } + /** + * Reset all the internal counters and start time. + */ @Override - public void collect(boolean reset, List result) { - DTimeMetricStats metric = collect(reset); + public void reset() { + startTime.set(System.currentTimeMillis()); + max.reset(); + count.reset(); + total.reset(); + beanCount.reset(); + } + + @Override + public void visit(MetricVisitor visitor) { + DTimeMetricStats metric = collect(visitor.isReset()); if (metric != null) { - result.add(metric); + visitor.visitTimed(metric); } } @@ -78,7 +93,7 @@ class DTimedMetric implements TimedMetric { /** * Return the current statistics resetting the internal values if reset is true. */ - public DTimeMetricStats getStatistics(boolean reset) { + private DTimeMetricStats getStatistics(boolean reset) { if (reset) { // Note these values are not guaranteed to be consistent wrt each other @@ -88,21 +103,11 @@ class DTimedMetric implements TimedMetric { final long totalVal = total.sumThenReset(); final long countVal = count.sumThenReset(); final long startTimeVal = startTime.getAndSet(System.currentTimeMillis()); - return new DTimeMetricStats(name, startTimeVal, countVal, totalVal, maxVal, beans); + return new DTimeMetricStats(metricType, name, startTimeVal, countVal, totalVal, maxVal, beans); } else { - return new DTimeMetricStats(name, startTime.get(), count.sum(), total.sum(), max.get(), beanCount.sum()); + return new DTimeMetricStats(metricType, name, startTime.get(), count.sum(), total.sum(), max.get(), beanCount.sum()); } } - /** - * Reset all the internal counters and start time. - */ - public void reset() { - startTime.set(System.currentTimeMillis()); - max.reset(); - count.reset(); - total.reset(); - } - } diff --git a/src/main/java/io/ebeaninternal/server/profile/DTimedMetricMap.java b/src/main/java/io/ebeaninternal/server/profile/DTimedMetricMap.java index d077e7aea..37f1b7632 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DTimedMetricMap.java +++ b/src/main/java/io/ebeaninternal/server/profile/DTimedMetricMap.java @@ -1,30 +1,38 @@ package io.ebeaninternal.server.profile; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.TimedMetricMap; -import java.util.List; import java.util.concurrent.ConcurrentHashMap; class DTimedMetricMap implements TimedMetricMap { + private final MetricType metricType; + private final String name; private final ConcurrentHashMap map = new ConcurrentHashMap<>(); - DTimedMetricMap(String name) { + DTimedMetricMap(MetricType metricType, String name) { + this.metricType = metricType; this.name = name; } @Override public void add(String key, long exeMicros) { - map.computeIfAbsent(key, (k)-> new DTimedMetric(name + key)).add(exeMicros); + map.computeIfAbsent(key, (k) -> new DTimedMetric(metricType, name + key)).add(exeMicros); } @Override - public void collect(boolean reset, List list) { + public void add(String key, long exeMicros, int rows) { + map.computeIfAbsent(key, (k) -> new DTimedMetric(metricType, name + key)).add(exeMicros, rows); + } + + @Override + public void visit(MetricVisitor visitor) { for (DTimedMetric value : map.values()) { - value.collect(reset, list); + value.visit(visitor); } } } diff --git a/src/main/java/io/ebeaninternal/server/profile/DTimedProfileLocation.java b/src/main/java/io/ebeaninternal/server/profile/DTimedProfileLocation.java index ea62a335b..5479bc686 100644 --- a/src/main/java/io/ebeaninternal/server/profile/DTimedProfileLocation.java +++ b/src/main/java/io/ebeaninternal/server/profile/DTimedProfileLocation.java @@ -1,11 +1,9 @@ package io.ebeaninternal.server.profile; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.TimedMetric; import io.ebeaninternal.metric.TimedMetricStats; -import java.util.List; - /** * Default profile location that uses stack trace. */ @@ -37,13 +35,11 @@ class DTimedProfileLocation extends DProfileLocation implements TimedProfileLoca } @Override - public void collect(boolean reset, List list) { - - TimedMetricStats collect = timedMetric.collect(reset); + public void visit(MetricVisitor visitor) { + TimedMetricStats collect = timedMetric.collect(visitor.isReset()); if (collect != null) { collect.setLocation(obtain()); - list.add(collect); + visitor.visitTimed(collect); } } - } diff --git a/src/main/java/io/ebeaninternal/server/profile/TimedProfileLocation.java b/src/main/java/io/ebeaninternal/server/profile/TimedProfileLocation.java index 36f702ecd..6402993ce 100644 --- a/src/main/java/io/ebeaninternal/server/profile/TimedProfileLocation.java +++ b/src/main/java/io/ebeaninternal/server/profile/TimedProfileLocation.java @@ -1,11 +1,9 @@ package io.ebeaninternal.server.profile; import io.ebean.ProfileLocation; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.metric.TimedMetric; -import java.util.List; - /** * ProfileLocation that collects timing metrics. */ @@ -22,7 +20,7 @@ public interface TimedProfileLocation extends ProfileLocation { TimedMetric getMetric(); /** - * Collect the metrics adding to the given list if the metrics are non empty. + * Visit the non empty metrics. */ - void collect(boolean reset, List list); + void visit(MetricVisitor visitor); } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java index 670098f5b..a9f7921cd 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java @@ -3,8 +3,12 @@ package io.ebeaninternal.server.query; import io.ebean.ProfileLocation; import io.ebean.bean.ObjectGraphNode; import io.ebean.config.dbplatform.SqlLimitResponse; +import io.ebean.meta.MetricType; import io.ebeaninternal.api.CQueryPlanKey; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.metric.MetricFactory; +import io.ebeaninternal.metric.TimedMetric; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.deploy.BeanProperty; @@ -51,6 +55,10 @@ public class CQueryPlan { private final ProfileLocation profileLocation; + private final String location; + + private final String label; + private final CQueryPlanKey planKey; private final boolean rawSql; @@ -90,9 +98,12 @@ public class CQueryPlan { this.dataTimeZone = server.getDataTimeZone(); this.beanType = request.getBeanDescriptor().getBeanType(); this.planKey = request.getQueryPlanKey(); - this.profileLocation = request.getQuery().getProfileLocation(); - this.autoTuned = request.getQuery().isAutoTuned(); - this.asOfTableCount = request.getQuery().getAsOfTableCount(); + SpiQuery query = request.getQuery(); + this.profileLocation = query.getProfileLocation(); + this.label = query.getLabel(); + this.location = location(); + this.autoTuned = query.isAutoTuned(); + this.asOfTableCount = query.getAsOfTableCount(); this.sql = sqlRes.getSql(); this.rowNumberIncluded = sqlRes.isIncludesRowNumberColumn(); this.sqlTree = sqlTree; @@ -105,13 +116,15 @@ public class CQueryPlan { /** * Create a query plan for a raw sql query. */ - CQueryPlan(OrmQueryRequest request, String sql, SqlTree sqlTree, - boolean rawSql, boolean rowNumberIncluded, String logWhereSql) { + CQueryPlan(OrmQueryRequest request, String sql, SqlTree sqlTree, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) { this.server = request.getServer(); this.dataTimeZone = server.getDataTimeZone(); this.beanType = request.getBeanDescriptor().getBeanType(); - this.profileLocation = request.getQuery().getProfileLocation(); + SpiQuery query = request.getQuery(); + this.profileLocation = query.getProfileLocation(); + this.label = query.getLabel(); + this.location = location(); this.planKey = buildPlanKey(sql, rawSql, rowNumberIncluded, logWhereSql); this.autoTuned = false; this.asOfTableCount = 0; @@ -124,6 +137,9 @@ public class CQueryPlan { this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins()); } + private String location() { + return (profileLocation == null) ? "" : profileLocation.shortDescription(); + } private CQueryPlanKey buildPlanKey(String sql, boolean rawSql, boolean rowNumberIncluded, String logWhereSql) { @@ -143,6 +159,14 @@ public class CQueryPlan { return profileLocation; } + public String getLabel() { + return label; + } + + public String getLocation() { + return location; + } + public DataReader createDataReader(ResultSet rset) { return new RsetDataReader(dataTimeZone, rset); } @@ -240,17 +264,13 @@ public class CQueryPlan { } } + /** + * Return a copy of the current query statistics. + */ public Snapshot getSnapshot(boolean reset) { return stats.getSnapshot(reset); } - /** - * Return the current query statistics. - */ - public CQueryPlanStats getQueryStats() { - return stats; - } - /** * Return the time this query plan was last used. */ @@ -268,4 +288,8 @@ public class CQueryPlan { public boolean isEmptyStats() { return stats.isEmpty(); } + + public TimedMetric createTimedMetric() { + return MetricFactory.get().createTimedMetric(MetricType.ORM, label); + } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPlanStats.java b/src/main/java/io/ebeaninternal/server/query/CQueryPlanStats.java index 371801037..83defb38a 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPlanStats.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryPlanStats.java @@ -2,16 +2,17 @@ package io.ebeaninternal.server.query; import io.ebean.ProfileLocation; import io.ebean.bean.ObjectGraphNode; -import io.ebean.meta.MetaQueryPlanOriginCount; -import io.ebean.meta.MetaQueryPlanStatistic; +import io.ebean.meta.MetaOrmQueryMetric; +import io.ebean.meta.MetaOrmQueryOrigin; +import io.ebean.meta.MetricType; +import io.ebeaninternal.metric.TimedMetric; +import io.ebeaninternal.metric.TimedMetricStats; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.LongAccumulator; import java.util.concurrent.atomic.LongAdder; /** @@ -21,15 +22,7 @@ public final class CQueryPlanStats { private final CQueryPlan queryPlan; - private final LongAdder count = new LongAdder(); - - private final LongAdder totalTime = new LongAdder(); - - private final LongAdder totalBeans = new LongAdder(); - - private final LongAccumulator maxTime = new LongAccumulator(Math::max, Long.MIN_VALUE); - - private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis()); + private final TimedMetric timedMetric; private long lastQueryTime; @@ -39,16 +32,16 @@ public final class CQueryPlanStats { * Construct for a given query plan. */ CQueryPlanStats(CQueryPlan queryPlan, boolean collectQueryOrigins) { - this.queryPlan = queryPlan; this.origins = !collectQueryOrigins ? null : new ConcurrentHashMap<>(); + this.timedMetric = queryPlan.createTimedMetric(); } /** * Return true if there are no statistics collected since the last reset. */ public boolean isEmpty() { - return count.sum() == 0; + return timedMetric.isEmpty(); } /** @@ -56,10 +49,7 @@ public final class CQueryPlanStats { */ public void add(long loadedBeanCount, long timeMicros, ObjectGraphNode objectGraphNode) { - count.increment(); - totalBeans.add(loadedBeanCount); - totalTime.add(timeMicros); - maxTime.accumulate(timeMicros); + timedMetric.add(timeMicros, loadedBeanCount); // not safe but should be atomic lastQueryTime = System.currentTimeMillis(); @@ -82,14 +72,7 @@ public final class CQueryPlanStats { * Reset the internal statistics counters. */ public void reset() { - - // Racey but near enough for our purposes as we don't want locks - count.reset(); - totalBeans.reset(); - totalTime.reset(); - maxTime.reset(); - startTime.set(System.currentTimeMillis()); - + timedMetric.reset(); if (origins != null) { for (LongAdder counter : origins.values()) { counter.reset(); @@ -109,25 +92,20 @@ public final class CQueryPlanStats { */ Snapshot getSnapshot(boolean reset) { - List origins = getOrigins(reset); - - // not guaranteed to be consistent due to time gaps between getting each value out of LongAdders but can live with that - // relative to the cost of making sure count and totalTime etc are all guaranteed to be consistent - if (reset) { - return new Snapshot(queryPlan, count.sumThenReset(), totalTime.sumThenReset(), totalBeans.sumThenReset(), maxTime.getThenReset(), startTime.getAndSet(System.currentTimeMillis()), lastQueryTime, origins); - } - return new Snapshot(queryPlan, count.sum(), totalTime.sum(), totalBeans.sum(), maxTime.get(), startTime.get(), lastQueryTime, origins); + TimedMetricStats collect = timedMetric.collect(reset); + List origins = getOrigins(reset); + return new Snapshot(queryPlan, collect, lastQueryTime, origins); } /** * Return the list/snapshot of the origins and their counter value. */ - private List getOrigins(boolean reset) { + private List getOrigins(boolean reset) { if (origins == null) { return Collections.emptyList(); } - List list = new ArrayList<>(origins.size()); + List list = new ArrayList<>(origins.size()); for (Entry entry : origins.entrySet()) { if (reset) { @@ -142,7 +120,7 @@ public final class CQueryPlanStats { /** * Snapshot of the origin ObjectGraphNode and counter value. */ - private static class OriginSnapshot implements MetaQueryPlanOriginCount { + private static class OriginSnapshot implements MetaOrmQueryOrigin { private final ObjectGraphNode objectGraphNode; private final long count; @@ -170,70 +148,83 @@ public final class CQueryPlanStats { /** * A snapshot of the current statistics for a query plan. */ - public static class Snapshot implements MetaQueryPlanStatistic { + static class Snapshot implements MetaOrmQueryMetric { private final CQueryPlan queryPlan; - private final long count; - private final long totalTime; - private final long totalBeans; - private final long maxTime; - private final long startTime; + private final TimedMetricStats metrics; private final long lastQueryTime; - private final List origins; - - Snapshot(CQueryPlan queryPlan, long count, long totalTime, long totalBeans, long maxTime, long startTime, long lastQueryTime, - List origins) { + private final List origins; + Snapshot(CQueryPlan queryPlan, TimedMetricStats metrics, long lastQueryTime, List origins) { this.queryPlan = queryPlan; - this.count = count; - this.totalTime = totalTime; - this.totalBeans = totalBeans; - this.maxTime = maxTime; - this.startTime = startTime; + this.metrics = metrics; this.lastQueryTime = lastQueryTime; this.origins = origins; } @Override public String toString() { - ProfileLocation profileLocation = queryPlan.getProfileLocation(); - String loc = (profileLocation == null) ? "" : profileLocation.shortDescription(); - return "location:" + loc + " count:" + count + " time:" + totalTime + " maxTime:" + maxTime + " beans:" + totalBeans + " sql:" + getSql(); + return "location:" + getLocation() + " metrics:" + metrics + " sql:" + getSql(); } @Override - public Class getBeanType() { + public MetricType getMetricType() { + return MetricType.ORM; + } + + @Override + public Class getType() { return queryPlan.getBeanType(); } + @Override + public String getLabel() { + return queryPlan.getLabel(); + } + + @Override + public String getName() { + return queryPlan.getLabel(); + } + + @Override + public String getLocation() { + return queryPlan.getLocation(); + } + @Override public ProfileLocation getProfileLocation() { return queryPlan.getProfileLocation(); } @Override - public long getExecutionCount() { - return count; + public long getBeanCount() { + return metrics.getBeanCount(); } @Override - public long getTotalTimeMicros() { - return totalTime; + public long getCount() { + return metrics.getCount(); } @Override - public long getTotalLoadedBeans() { - return totalBeans; + public long getTotal() { + return metrics.getTotal(); } @Override - public long getMaxTimeMicros() { - return maxTime; + public long getMax() { + return metrics.getMax(); } @Override - public long getCollectionStart() { - return startTime; + public long getMean() { + return metrics.getMean(); + } + + @Override + public long getStartTime() { + return metrics.getStartTime(); } @Override @@ -257,17 +248,7 @@ public final class CQueryPlanStats { } @Override - public long getAvgTimeMicros() { - return count < 1 ? 0 : totalTime / count; - } - - @Override - public long getAvgLoadedBeans() { - return count < 1 ? 0 : totalBeans / count; - } - - @Override - public List getOrigins() { + public List getOrigins() { return origins; } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPlanStatsCollector.java b/src/main/java/io/ebeaninternal/server/query/CQueryPlanStatsCollector.java deleted file mode 100644 index cb458e3c9..000000000 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPlanStatsCollector.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.ebeaninternal.server.query; - -import io.ebean.meta.MetaQueryPlanStatistic; - -import java.util.ArrayList; -import java.util.List; - -/** - * Helper to collect query plan execution statistics. - */ -public class CQueryPlanStatsCollector { - - private final boolean reset; - - List list = new ArrayList<>(); - - public CQueryPlanStatsCollector(boolean reset) { - this.reset = reset; - } - - public boolean isReset() { - return reset; - } - - public void add(MetaQueryPlanStatistic planStatistic) { - list.add(planStatistic); - } - - public List getList() { - return list; - } -} diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java index 4be7bec7b..f1282f9d2 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultRelationalQueryEngine.java @@ -1,7 +1,11 @@ package io.ebeaninternal.server.query; import io.ebean.SqlRow; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.metric.MetricFactory; +import io.ebeaninternal.metric.TimedMetricMap; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.core.RelationalQueryEngine; import io.ebeaninternal.server.core.RelationalQueryRequest; @@ -25,10 +29,23 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine { private final boolean binaryOptimizedUUID; + private final TimedMetricMap timedMetricMap; + public DefaultRelationalQueryEngine(Binder binder, String dbTrueValue, boolean binaryOptimizedUUID) { this.binder = binder; this.dbTrueValue = dbTrueValue == null ? "true" : dbTrueValue; this.binaryOptimizedUUID = binaryOptimizedUUID; + this.timedMetricMap = MetricFactory.get().createTimedMetricMap(MetricType.SQL, "sql.query."); + } + + @Override + public void collect(String label, long exeMicros, int rows) { + timedMetricMap.add(label, exeMicros, rows); + } + + @Override + public void visitMetrics(MetricVisitor visitor) { + timedMetricMap.visit(visitor); } @Override diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java index cf3158974..3c7049fe2 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java @@ -51,6 +51,7 @@ public class DefaultDtoQuery implements SpiDtoQuery { this.server = server; this.descriptor = descriptor; this.ormQuery = ormQuery; + this.label = ormQuery.getLabel(); } /** @@ -65,7 +66,7 @@ public class DefaultDtoQuery implements SpiDtoQuery { @Override public String planKey() { - return sql+":first"+firstRow+":max"+maxRows; + return sql + ":first" + firstRow + ":max" + maxRows; } @Override diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 7a908b410..0359e97c2 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -96,6 +96,8 @@ public class DefaultOrmQuery implements SpiQuery { private Type type; + private String label; + private Mode mode = Mode.NORMAL; private Object tenantId; @@ -340,6 +342,17 @@ public class DefaultOrmQuery implements SpiQuery { return this; } + @Override + public String getLabel() { + return label; + } + + @Override + public Query setLabel(String label) { + this.label = label; + return this; + } + @Override public boolean isAutoTunable() { return nativeSql == null && beanDescriptor.isAutoTunable(); diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java index 0e232909f..0381df322 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmUpdate.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.querydefn; import io.ebean.EbeanServer; +import io.ebean.Update; import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.SpiUpdate; @@ -23,6 +24,8 @@ public final class DefaultOrmUpdate implements SpiUpdate, Serializable { */ private final String name; + private String label; + /** * The parameters used to bind to the sql. */ @@ -137,6 +140,17 @@ public final class DefaultOrmUpdate implements SpiUpdate, Serializable { return name; } + @Override + public Update setLabel(String label) { + this.label = label; + return this; + } + + @Override + public String getLabel() { + return label; + } + @Override public String getUpdateStatement() { return updateStatement; diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java index d2c9dfa6b..eb344b003 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultRelationalQuery.java @@ -19,6 +19,8 @@ public class DefaultRelationalQuery implements SpiSqlQuery { private final transient EbeanServer server; + private String label; + private String query; private int firstRow; @@ -122,6 +124,17 @@ public class DefaultRelationalQuery implements SpiSqlQuery { return this; } + @Override + public String getLabel() { + return label; + } + + @Override + public DefaultRelationalQuery setLabel(String label) { + this.label = label; + return this; + } + @Override public BindParams getBindParams() { return bindParams; diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 2a8bf37cc..c76358829 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -11,7 +11,8 @@ import io.ebean.config.dbplatform.DatabasePlatform.OnQueryOnly; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeSet; -import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricType; +import io.ebean.meta.MetricVisitor; import io.ebeaninternal.api.ScopeTrans; import io.ebeaninternal.api.ScopedTransaction; import io.ebeaninternal.api.SpiProfileHandler; @@ -37,7 +38,6 @@ import javax.persistence.PersistenceException; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -170,9 +170,9 @@ public class TransactionManager implements SpiTransactionManager { this.transactionFactory = TransactionFactoryBuilder.build(this, dataSourceSupplier, tenantProvider); MetricFactory metricFactory = MetricFactory.get(); - this.txnMain = metricFactory.createTimedMetric("txn.main"); - this.txnReadOnly = metricFactory.createTimedMetric("txn.readonly"); - this.txnNamed = metricFactory.createTimedMetricMap("txn.named."); + this.txnMain = metricFactory.createTimedMetric(MetricType.TXN, "txn.main"); + this.txnReadOnly = metricFactory.createTimedMetric(MetricType.TXN, "txn.readonly"); + this.txnNamed = metricFactory.createTimedMetricMap(MetricType.TXN, "txn.named."); scopeManager.register(this); } @@ -528,21 +528,13 @@ public class TransactionManager implements SpiTransactionManager { txnNamed.add(label, exeMicros); } - /** - * Collect the transaction execution statistics since the last reset. - */ - public List collectTransactionStatistics(boolean reset) { - - List list = new ArrayList<>(); - - txnMain.collect(reset, list); - txnReadOnly.collect(reset, list); + public void visitMetrics(MetricVisitor visitor) { + txnMain.visit(visitor); + txnReadOnly.visit(visitor); + txnNamed.visit(visitor); for (TimedProfileLocation timedLocation : TimedProfileLocationRegistry.registered()) { - timedLocation.collect(reset, list); + timedLocation.visit(visitor); } - txnNamed.collect(reset, list); - - return list; } /** @@ -562,7 +554,7 @@ public class TransactionManager implements SpiTransactionManager { if (st instanceof ScopedTransaction) { // can be null for Supports as that can start as a 'No Transaction' and then // effectively be replaced by transactions inside the scope - ((ScopedTransaction)st).complete(returnOrThrowable, opCode); + ((ScopedTransaction) st).complete(returnOrThrowable, opCode); } } diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index 16e4ef45d..cee47bcaf 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -1,6 +1,9 @@ package io.ebean; import io.ebean.annotation.Platform; +import io.ebean.meta.BasicMetricVisitor; +import io.ebean.meta.MetaTimedMetric; +import io.ebean.meta.MetricType; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiQuery; @@ -14,6 +17,8 @@ import org.slf4j.LoggerFactory; import org.tests.model.basic.Country; import java.sql.Types; +import java.util.List; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; @@ -52,6 +57,26 @@ public abstract class BaseTestCase { } } + protected void resetAllMetrics() { + server().getMetaInfoManager().resetAllMetrics(); + } + + protected BasicMetricVisitor visitMetricsBasic() { + return server().getMetaInfoManager().visitBasic(); + } + + protected List visitTimedMetrics() { + return visitMetricsBasic().getTimedMetrics(); + } + + protected List sqlMetrics() { + List timedMetrics = visitTimedMetrics(); + + return timedMetrics.stream() + .filter((it) -> it.getMetricType() == MetricType.SQL) + .collect(Collectors.toList()); + } + /** * Return the generated sql trimming column alias if required. */ diff --git a/src/test/java/io/ebean/DtoQueryFromOrmTest.java b/src/test/java/io/ebean/DtoQueryFromOrmTest.java index c72cfa330..0278a51c8 100644 --- a/src/test/java/io/ebean/DtoQueryFromOrmTest.java +++ b/src/test/java/io/ebean/DtoQueryFromOrmTest.java @@ -1,7 +1,11 @@ package io.ebean; +import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; +import io.ebean.meta.MetaTimedMetric; import org.ebeantest.LoggedSqlCollector; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.tests.model.basic.Contact; @@ -13,18 +17,23 @@ import static org.assertj.core.api.Assertions.assertThat; public class DtoQueryFromOrmTest extends BaseTestCase { -// @BeforeClass -// public static void resetStats() { -// Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); -// } -// -// @AfterClass -// public static void reportStats() { -// List stats = Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(false); -// for (MetaQueryMetric stat : stats) { -// System.out.println(stat); -// } -// } + @BeforeClass + public static void resetStats() { + Ebean.getDefaultServer().getMetaInfoManager().resetAllMetrics(); + } + + @AfterClass + public static void reportStats() { + BasicMetricVisitor basic = Ebean.getDefaultServer().getMetaInfoManager().visitBasic(); + for (MetaQueryMetric metric : basic.getDtoQueryMetrics()) { + System.out.println(metric); + } + + System.out.println("-- transaction metrics --"); + for (MetaTimedMetric metric : basic.getTimedMetrics()) { + System.out.println(metric); + } + } @Ignore @Test @@ -32,9 +41,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { ResetBasicData.reset(); - Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); + resetAllMetrics(); - String[] prefix = {"Bl", "B", "Red"}; + String[] prefix = {"Bl", "B", "Red", "jim"}; for (String val : prefix) { List list = Ebean.find(Contact.class) @@ -43,12 +52,15 @@ public class DtoQueryFromOrmTest extends BaseTestCase { .orderBy().asc("lastName") .setMaxRows(10) .asDto(ContactDto.class) + .setLabel("prefixLoop") .findList(); System.out.println("List:" + list); } - List stats = Ebean.getDefaultServer().getMetaInfoManager().collectQueryStatistics(true); + BasicMetricVisitor basic = visitMetricsBasic(); + + List stats = basic.getDtoQueryMetrics(); for (MetaQueryMetric stat : stats) { System.out.println(stat); } @@ -72,6 +84,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { .where().isNotNull("email").isNotNull("lastName") .orderBy().asc("lastName") .asDto(ContactDto.class) + .setLabel("explicitId") .setRelaxedMode(); List dtos = query.findList(); @@ -126,6 +139,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List contactDtos = Ebean.find(Contact.class) + .setLabel("emailFullName") .select("email, concat(lastName,', ',firstName) as fullName") .where().isNotNull("email").isNotNull("lastName") .orderBy().asc("lastName") diff --git a/src/test/java/io/ebean/DtoQueryTest.java b/src/test/java/io/ebean/DtoQueryTest.java index 53bf02730..7957559dc 100644 --- a/src/test/java/io/ebean/DtoQueryTest.java +++ b/src/test/java/io/ebean/DtoQueryTest.java @@ -1,5 +1,6 @@ package io.ebean; +import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -102,7 +103,7 @@ public class DtoQueryTest extends BaseTestCase { ResetBasicData.reset(); - server().getMetaInfoManager().collectQueryStatistics(true); + resetAllMetrics(); String[] names = {"Rob", "Fiona", "Shrek"}; @@ -116,14 +117,17 @@ public class DtoQueryTest extends BaseTestCase { log.info("Found " + custs); } - List stats = server().getMetaInfoManager().collectQueryStatistics(false); + // collect without reset + BasicMetricVisitor basic = new BasicMetricVisitor(false, true, true); + server().getMetaInfoManager().visitMetrics(basic); + List stats = basic.getDtoQueryMetrics(); assertThat(stats).hasSize(1); MetaQueryMetric queryMetric = stats.get(0); - assertThat(queryMetric.getLabel()).isEqualTo("basic"); assertThat(queryMetric.getCount()).isEqualTo(3); + assertThat(queryMetric.getName()).isEqualTo("basic"); server().findDto(DCust.class, "select c4.id, c4.name from o_customer c4 where lower(c4.name) = :name") @@ -131,7 +135,9 @@ public class DtoQueryTest extends BaseTestCase { .setParameter("name", "rob") .findList(); - stats = server().getMetaInfoManager().collectQueryStatistics(true); + BasicMetricVisitor metric2 = server().getMetaInfoManager().visitBasic(); + + stats = metric2.getDtoQueryMetrics(); assertThat(stats).hasSize(2); log.info("stats " + stats); diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index 0a8e81fbc..00498227d 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -2,11 +2,14 @@ package io.ebean; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; +import io.ebean.meta.BasicMetricVisitor; +import io.ebean.meta.MetaOrmQueryMetric; import org.junit.Test; import org.tests.model.basic.Country; import org.tests.model.basic.Customer; import java.sql.Timestamp; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -16,6 +19,8 @@ public class UpdateQueryTest extends BaseTestCase { @Test public void basic() { + resetAllMetrics(); + EbeanServer server = server(); UpdateQuery update = server.update(Customer.class); Query query = update @@ -24,11 +29,17 @@ public class UpdateQueryTest extends BaseTestCase { .where() .eq("status", Customer.Status.NEW) .gt("id", 1000) - .query(); + .setLabel("updateActive"); query.update(); assertThat(query.getGeneratedSql()).contains("update o_customer set status=?, updtime=? where status = ? and id > ?"); + + BasicMetricVisitor basic = visitMetricsBasic(); + List ormQueryMetrics = basic.getOrmQueryMetrics(); + assertThat(ormQueryMetrics).hasSize(1); + assertThat(ormQueryMetrics.get(0).getType()).isEqualTo(Customer.class); + assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateActive"); } @Test diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index 349767266..62265c0fb 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -36,6 +36,7 @@ import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebean.meta.MetaInfoManager; +import io.ebean.meta.MetricVisitor; import io.ebean.plugin.Property; import io.ebean.plugin.SpiServer; import io.ebean.text.csv.CsvReader; @@ -275,6 +276,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { } + @Override + public void visitMetrics(MetricVisitor visitor) { + + } + @Override public void loadMany(BeanCollection collection, boolean onlyIds) { diff --git a/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java b/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java index a6295b842..457bfad89 100644 --- a/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java +++ b/src/test/java/io/ebeaninternal/server/profile/BasicProfileLocationTest.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.profile; +import io.ebean.meta.MetricType; import io.ebeaninternal.metric.MetricFactory; import org.junit.Test; @@ -10,7 +11,7 @@ public class BasicProfileLocationTest { @Test public void obtain() { - DProfileLocation loc = new DTimedProfileLocation(12, "foo", MetricFactory.get().createTimedMetric("junk")); + DProfileLocation loc = new DTimedProfileLocation(12, "foo", MetricFactory.get().createTimedMetric(MetricType.TXN, "junk")); assertThat(loc.obtain()).endsWith(":12)"); assertThat(loc.shortDescription()).isEqualTo("NativeMethodAccessorImpl.invoke0(Native Method:12)"); diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java index 7046d8c64..37998bfdc 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java @@ -6,7 +6,7 @@ import io.ebean.EbeanServer; import io.ebean.Transaction; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Transactional; -import io.ebean.meta.MetaInfoManager; +import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaTimedMetric; import io.ebeaninternal.api.SpiTransaction; import org.ebeantest.LoggedSqlCollector; @@ -29,8 +29,7 @@ public class TestBatchInsertFlush extends BaseTestCase { EbeanServer server = Ebean.getDefaultServer(); - MetaInfoManager metaInfoManager = server.getMetaInfoManager(); - metaInfoManager.collectTransactionStatistics(true); + resetAllMetrics(); Transaction transaction = server.beginTransaction(); try { @@ -76,7 +75,8 @@ public class TestBatchInsertFlush extends BaseTestCase { transaction.end(); } - List txnStats = metaInfoManager.collectTransactionStatistics(true); + BasicMetricVisitor basic = visitMetricsBasic(); + List txnStats = basic.getTimedMetrics(); for (MetaTimedMetric txnMetric : txnStats) { System.out.println(txnMetric); } diff --git a/src/test/java/org/tests/m2m/TestM2mDeleteObject.java b/src/test/java/org/tests/m2m/TestM2mDeleteObject.java index 9fed238ca..3ba05ee68 100644 --- a/src/test/java/org/tests/m2m/TestM2mDeleteObject.java +++ b/src/test/java/org/tests/m2m/TestM2mDeleteObject.java @@ -2,25 +2,34 @@ package org.tests.m2m; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.meta.MetaTimedMetric; +import org.junit.Assert; +import org.junit.Test; import org.tests.model.m2m.Permission; import org.tests.model.m2m.Role; import org.tests.model.m2m.Tenant; -import org.junit.Assert; -import org.junit.Test; import java.util.HashSet; import java.util.List; import java.util.Set; +import static org.assertj.core.api.Assertions.assertThat; + public class TestM2mDeleteObject extends BaseTestCase { @Test public void test() { - Ebean.createUpdate(Permission.class, "delete from Permission").execute(); + resetAllMetrics(); + + Ebean.createUpdate(Permission.class, "delete from Permission").setLabel("deleteAllPermissions").execute(); Ebean.createUpdate(Tenant.class, "delete from Tenant").execute(); Ebean.createUpdate(Role.class, "delete from Role").execute(); + List sqlMetrics = sqlMetrics(); + assertThat(sqlMetrics).hasSize(1); + assertThat(sqlMetrics.get(0).getName()).isEqualTo("orm.update.deleteAllPermissions"); + Tenant t = new Tenant("tenant"); Ebean.save(t); diff --git a/src/test/java/org/tests/query/finder/TestCustomerFinder.java b/src/test/java/org/tests/query/finder/TestCustomerFinder.java index bfd51e476..63e41a954 100644 --- a/src/test/java/org/tests/query/finder/TestCustomerFinder.java +++ b/src/test/java/org/tests/query/finder/TestCustomerFinder.java @@ -3,8 +3,8 @@ package org.tests.query.finder; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; -import io.ebean.meta.MetaInfoManager; -import io.ebean.meta.MetaQueryPlanStatistic; +import io.ebean.meta.BasicMetricVisitor; +import io.ebean.meta.MetaOrmQueryMetric; import io.ebean.meta.MetaTimedMetric; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -136,9 +136,7 @@ public class TestCustomerFinder extends BaseTestCase { ResetBasicData.reset(); - MetaInfoManager metaInfoManager = Ebean.getDefaultServer().getMetaInfoManager(); - metaInfoManager.collectQueryPlanStatistics(true); - metaInfoManager.collectTransactionStatistics(true); + resetAllMetrics(); List customers = Customer.find.all(); assertThat(customers).isNotEmpty(); @@ -153,14 +151,16 @@ public class TestCustomerFinder extends BaseTestCase { Customer.find.updateNames("Junk", 2000); Customer.find.byId(3); - List planStats = metaInfoManager.collectQueryPlanStatistics(true); + BasicMetricVisitor basic = server().getMetaInfoManager().visitBasic(); + + List planStats = basic.getOrmQueryMetrics(); assertThat(planStats.size()).isGreaterThan(4); - for (MetaQueryPlanStatistic planStat : planStats) { + for (MetaOrmQueryMetric planStat : planStats) { System.out.println(planStat); } - for (MetaTimedMetric txnTimed : metaInfoManager.collectTransactionStatistics(true)) { + for (MetaTimedMetric txnTimed : basic.getTimedMetrics()) { System.out.println(txnTimed); } } diff --git a/src/test/java/org/tests/query/other/TestObjectGraphNodeStatsCollection.java b/src/test/java/org/tests/query/other/TestObjectGraphNodeStatsCollection.java index 228568a8e..a7c26b691 100644 --- a/src/test/java/org/tests/query/other/TestObjectGraphNodeStatsCollection.java +++ b/src/test/java/org/tests/query/other/TestObjectGraphNodeStatsCollection.java @@ -3,16 +3,17 @@ package org.tests.query.other; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; +import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaInfoManager; -import io.ebean.meta.MetaObjectGraphNodeStats; -import io.ebean.meta.MetaQueryPlanStatistic; +import io.ebean.meta.MetaOrmQueryMetric; +import io.ebean.meta.MetaOrmQueryNode; +import org.junit.Assert; +import org.junit.Test; import org.tests.model.basic.Address; import org.tests.model.basic.Customer; import org.tests.model.basic.Order; import org.tests.model.basic.OrderDetail; import org.tests.model.basic.ResetBasicData; -import org.junit.Assert; -import org.junit.Test; import java.util.List; @@ -30,19 +31,19 @@ public class TestObjectGraphNodeStatsCollection extends BaseTestCase { server.find(Order.class).findCount(); infoManager.collectNodeStatistics(true); - infoManager.collectQueryPlanStatistics(true); + infoManager.resetAllMetrics(); runFindOrderQuery(server); runFindCustomerQuery(server); - List nodeStatistics = infoManager.collectNodeStatistics(true); - for (MetaObjectGraphNodeStats stat : nodeStatistics) { - stat.toString(); + List nodeStatistics = infoManager.collectNodeStatistics(true); + for (MetaOrmQueryNode stat : nodeStatistics) { + System.out.println(stat); } - List planStatistics = infoManager.collectQueryPlanStatistics(true); - for (MetaQueryPlanStatistic planStatistic : planStatistics) { - planStatistic.getSql(); + BasicMetricVisitor basic = infoManager.visitBasic(); + for (MetaOrmQueryMetric queryMetric : basic.getOrmQueryMetrics()) { + System.out.println(queryMetric); } } diff --git a/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java b/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java index 39d71a2d3..1e0a5e830 100644 --- a/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java +++ b/src/test/java/org/tests/query/sqlquery/SqlQueryTests.java @@ -4,6 +4,7 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.SqlQuery; import io.ebean.SqlRow; +import io.ebean.meta.MetaTimedMetric; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.Order; @@ -114,9 +115,13 @@ public class SqlQueryTests extends BaseTestCase { ResetBasicData.reset(); - SqlQuery sqlQuery = Ebean.createSqlQuery("select * from o_order where o_order.id > :id order by id"); - sqlQuery.setParameter("id", 3); - sqlQuery.setMaxRows(10); + resetAllMetrics(); + + SqlQuery sqlQuery = Ebean.createSqlQuery("select * from o_order where o_order.id > :id order by id") + .setParameter("id", 3) + .setMaxRows(10) + .setLabel("findList-3-10"); + LoggedSqlCollector.start(); sqlQuery.findList(); @@ -129,6 +134,8 @@ public class SqlQueryTests extends BaseTestCase { } else { assertThat(sql.get(0)).contains("select * from o_order where o_order.id > ? order by id limit 10;"); } + + assertThat(sqlMetrics()).isNotEmpty(); } @Test @@ -136,8 +143,11 @@ public class SqlQueryTests extends BaseTestCase { ResetBasicData.reset(); - SqlQuery sqlQuery = Ebean.createSqlQuery("Select * from o_order"); - sqlQuery.setMaxRows(10); + resetAllMetrics(); + + SqlQuery sqlQuery = Ebean.createSqlQuery("Select * from o_order") + .setMaxRows(10) + .setLabel("findEach-Max10Rows"); LoggedSqlCollector.start(); sqlQuery.findEach(bean -> bean.get("id")); @@ -150,6 +160,10 @@ public class SqlQueryTests extends BaseTestCase { } else { assertThat(sql.get(0)).contains("limit 10"); } + + List sqlMetrics = sqlMetrics(); + assertThat(sqlMetrics).hasSize(1); + assertThat(sqlMetrics.get(0).getName()).isEqualTo("sql.query.findEach-Max10Rows"); } @Test diff --git a/src/test/java/org/tests/transaction/TestNestedMandatory.java b/src/test/java/org/tests/transaction/TestNestedMandatory.java index 97578d46b..91eb4e14f 100644 --- a/src/test/java/org/tests/transaction/TestNestedMandatory.java +++ b/src/test/java/org/tests/transaction/TestNestedMandatory.java @@ -5,7 +5,6 @@ import io.ebean.Ebean; import io.ebean.Transaction; import io.ebean.annotation.Transactional; import io.ebean.annotation.TxType; -import io.ebean.meta.MetaInfoManager; import io.ebean.meta.MetaTimedMetric; import org.junit.Test; import org.slf4j.Logger; @@ -19,17 +18,16 @@ public class TestNestedMandatory extends BaseTestCase { private static final Logger log = LoggerFactory.getLogger(TestNestedMandatory.class); - static Transaction outerTxn; + private static Transaction outerTxn; @Test public void test() { - MetaInfoManager metaInfoManager = Ebean.getDefaultServer().getMetaInfoManager(); - metaInfoManager.collectTransactionStatistics(true); + resetAllMetrics(); new Outer().doOuter(); - List txnMetrics = metaInfoManager.collectTransactionStatistics(true); + List txnMetrics = visitTimedMetrics(); for (MetaTimedMetric txnTimed : txnMetrics) { System.out.println(txnTimed); } diff --git a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java index 3b167abc1..e306e477d 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java +++ b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java @@ -3,10 +3,13 @@ package org.tests.update; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.SqlUpdate; +import io.ebean.meta.MetaTimedMetric; import org.junit.Assert; import org.junit.Test; import org.tests.idkeys.db.AuditLog; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; public class TestSqlUpdateInTxn extends BaseTestCase { @@ -40,11 +43,18 @@ public class TestSqlUpdateInTxn extends BaseTestCase { String sql = " \nupdate audit_log \nset description = description \nwhere id = id"; - SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql); + resetAllMetrics(); + + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql).setLabel("auditLargeUpdate"); sqlUpdate.execute(); assertThat(sqlUpdate.getSql()).isEqualTo(sql.trim()); assertThat(sqlUpdate.getGeneratedSql()).isEqualTo(sql.trim()); + + List sqlMetrics = sqlMetrics(); + assertThat(sqlMetrics).hasSize(1); + assertThat(sqlMetrics.get(0).getName()).isEqualTo("sql.update.auditLargeUpdate"); + assertThat(sqlMetrics.get(0).getCount()).isEqualTo(1); } @Test diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index b33a6e823..3b048c4c2 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -19,7 +19,7 @@ ebean.ddl.generate=true ebean.ddl.run=true ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp} ebean.packages=org.tests -datasource.default=pg +datasource.default=h2 ebean.autoReadOnlyDataSource=true From af2b8976fa72f03e4a7325b23f58191aa371aae6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 12 Mar 2018 18:28:17 +1300 Subject: [PATCH 0181/1036] #1346 - Since ebean version 11.12.1 executing docStore query with findPagedList fails with error (due to order by id) --- .../server/deploy/BeanPropertyAssocMany.java | 12 + .../server/querydefn/DefaultOrmQuery.java | 91 ++++- .../server/querydefn/OrmQueryPlanKey.java | 85 +---- .../deploy/BeanPropertyAssocManyTest.java | 26 +- .../server/querydefn/OrmQueryPlanKeyTest.java | 353 +++++++++--------- 5 files changed, 288 insertions(+), 279 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index c58c658db..9f52a6a33 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -335,6 +335,18 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return false; } + /** + * Add the loaded current bean to its associated parent. + * + * Helper method used by Elastic integration when loading with a persistence context. + */ + public void lazyLoadMany(EntityBean current) { + EntityBean parentBean = childMasterProperty.getValueAsEntityBean(current); + if (parentBean != null) { + addBeanToCollectionWithCreate(parentBean, current, true); + } + } + public void addWhereParentIdIn(SpiQuery query, List parentIds, boolean useDocStore) { if (useDocStore) { // assumes the ManyToOne property is included diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 0359e97c2..50683c1dc 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -359,7 +359,7 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public Query setUseDocStore(boolean useDocStore) { + public DefaultOrmQuery setUseDocStore(boolean useDocStore) { this.useDocStore = useDocStore; return this; } @@ -428,7 +428,7 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public Query setIncludeSoftDeletes() { + public DefaultOrmQuery setIncludeSoftDeletes() { this.temporalMode = TemporalMode.SOFT_DELETED; return this; } @@ -1050,14 +1050,87 @@ public class DefaultOrmQuery implements SpiQuery { if (isNativeSql()) { queryPlanKey = new NativeSqlQueryPlanKey(nativeSql + "-" + firstRow + "-" + maxRows); } else { - queryPlanKey = new OrmQueryPlanKey(beanDescriptor.getDiscValue(), m2mIncludeJoin, type, detail, maxRows, firstRow, - disableLazyLoading, manualId, orderBy, - distinct, sqlDistinct, mapKey, id, bindParams, whereExpressions, havingExpressions, - temporalMode, forUpdate, rootTableAlias, rawSql, updateProperties, countDistinctOrder); + queryPlanKey = new OrmQueryPlanKey(planDescription(), maxRows, firstRow, rawSql); } return queryPlanKey; } + private String planDescription() { + + StringBuilder sb = new StringBuilder(300); + if (type != null) { + sb.append("t:").append(type.ordinal()); + } + if (useDocStore) { + sb.append(",ds:"); + } + if (beanDescriptor.getDiscValue() != null) { + sb.append(",disc:").append(beanDescriptor.getDiscValue()); + } + if (temporalMode != SpiQuery.TemporalMode.CURRENT) { + sb.append(",temp:").append(temporalMode.ordinal()); + } + if (forUpdate != null) { + sb.append(",forUpd:").append(forUpdate.ordinal()); + } + if (id != null) { + sb.append(",id:"); + } + if (manualId) { + sb.append(",manId:"); + } + if (distinct) { + sb.append(",dist:"); + } + if (sqlDistinct) { + sb.append(",sqlD:"); + } + if (disableLazyLoading) { + sb.append(",disLazy:"); + } + if (rootTableAlias != null) { + sb.append(",root:").append(rootTableAlias); + } + if (orderBy != null) { + sb.append(",orderBy:").append(orderBy.toStringFormat()); + } + if (m2mIncludeJoin != null) { + sb.append(",m2m:").append(m2mIncludeJoin.getTable()); + } + if (mapKey != null) { + sb.append(",mapKey:").append(mapKey); + } + if (countDistinctOrder != null) { + sb.append(",countDistOrd:").append(countDistinctOrder.name()); + } + if (detail != null) { + sb.append(" detail["); + detail.queryPlanHash(sb); + sb.append("]"); + } + if (bindParams != null) { + sb.append(" bindParams["); + bindParams.buildQueryPlanHash(sb); + sb.append("]"); + } + if (whereExpressions != null) { + sb.append(" where["); + whereExpressions.queryPlanHash(sb); + sb.append("]"); + } + if (havingExpressions != null) { + sb.append(" having["); + havingExpressions.queryPlanHash(sb); + sb.append("]"); + } + if (updateProperties != null) { + sb.append(" update["); + updateProperties.buildQueryPlanHash(sb); + sb.append("]"); + } + return sb.toString(); + } + @Override public boolean isNativeSql() { return nativeSql != null; @@ -1449,7 +1522,7 @@ public class DefaultOrmQuery implements SpiQuery { @Override public boolean checkPagingOrderBy() { - return (maxRows > 1 || firstRow > 0) && !distinct && (orderByIsEmpty() || isOrderById()); + return !useDocStore && (maxRows > 1 || firstRow > 0) && !distinct && (orderByIsEmpty() || isOrderById()); } @Override @@ -1585,7 +1658,7 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public Query setDisableLazyLoading(boolean disableLazyLoading) { + public DefaultOrmQuery setDisableLazyLoading(boolean disableLazyLoading) { this.disableLazyLoading = disableLazyLoading; return this; } @@ -1793,7 +1866,7 @@ public class DefaultOrmQuery implements SpiQuery { } @Override - public Query alias(String alias) { + public DefaultOrmQuery alias(String alias) { this.rootTableAlias = alias; return this; } diff --git a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java index da91f6ea2..2286f3ae2 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKey.java @@ -1,13 +1,6 @@ package io.ebeaninternal.server.querydefn; -import io.ebean.CountDistinctOrder; -import io.ebean.OrderBy; -import io.ebean.Query; -import io.ebeaninternal.api.BindParams; import io.ebeaninternal.api.CQueryPlanKey; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.rawsql.SpiRawSql; /** @@ -21,85 +14,11 @@ class OrmQueryPlanKey implements CQueryPlanKey { private final int planHash; private final String description; - OrmQueryPlanKey(String discValue, TableJoin m2mIncludeTable, SpiQuery.Type type, OrmQueryDetail detail, int maxRows, int firstRow, boolean disableLazyLoading, - boolean manualId, OrderBy orderBy, boolean distinct, boolean sqlDistinct, String mapKey, Object id, BindParams bindParams, - SpiExpression whereExpressions, SpiExpression havingExpressions, SpiQuery.TemporalMode temporalMode, - Query.ForUpdate forUpdate, String rootTableAlias, SpiRawSql rawSql, OrmUpdateProperties updateProperties, CountDistinctOrder countDistinctOrder) { - - StringBuilder sb = new StringBuilder(300); - if (type != null) { - sb.append("t:").append(type.ordinal()); - } - if (discValue != null) { - sb.append("disc:").append(discValue); - } - if (temporalMode != SpiQuery.TemporalMode.CURRENT) { - sb.append(",temp:").append(temporalMode.ordinal()); - } - if (forUpdate != null) { - sb.append(",forUpd:").append(forUpdate.ordinal()); - } - if (id != null) { - sb.append(",id:"); - } - if (manualId) { - sb.append(",manId:"); - } - if (distinct) { - sb.append(",dist:"); - } - if (sqlDistinct) { - sb.append(",sqlD:"); - } - if (disableLazyLoading) { - sb.append(",disLazy:"); - } - if (rootTableAlias != null) { - sb.append(",root:").append(rootTableAlias); - } - if (orderBy != null) { - sb.append(",orderBy:").append(orderBy.toStringFormat()); - } - if (m2mIncludeTable != null) { - sb.append(",m2m:").append(m2mIncludeTable.getTable()); - } - if (mapKey != null) { - sb.append(",mapKey:").append(mapKey); - } - if (countDistinctOrder != null) { - sb.append(",countdistinctoder:").append(countDistinctOrder.name()); - } + OrmQueryPlanKey(String description, int maxRows, int firstRow, SpiRawSql rawSql) { + this.description = description; this.maxRows = maxRows; this.firstRow = firstRow; this.rawSqlKey = (rawSql == null) ? null : rawSql.getKey(); - - if (detail != null) { - sb.append(" detail["); - detail.queryPlanHash(sb); - sb.append("]"); - } - if (bindParams != null) { - sb.append(" bindParams["); - bindParams.buildQueryPlanHash(sb); - sb.append("]"); - } - if (whereExpressions != null) { - sb.append(" where["); - whereExpressions.queryPlanHash(sb); - sb.append("]"); - } - if (havingExpressions != null) { - sb.append(" having["); - havingExpressions.queryPlanHash(sb); - sb.append("]"); - } - if (updateProperties != null) { - sb.append(" update["); - updateProperties.buildQueryPlanHash(sb); - sb.append("]"); - } - - this.description = sb.toString(); int hc = description.hashCode(); hc = hc * 92821 + (maxRows); hc = hc * 92821 + (firstRow); diff --git a/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java b/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java index 881614304..162832e76 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java @@ -3,23 +3,27 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; +import io.ebean.common.BeanList; +import org.junit.Test; +import org.tests.model.basic.Contact; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; -import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.*; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class BeanPropertyAssocManyTest extends BaseTestCase { - BeanDescriptor customerDesc = spiEbeanServer().getBeanDescriptor(Customer.class); + private BeanDescriptor customerDesc = spiEbeanServer().getBeanDescriptor(Customer.class); @SuppressWarnings("unchecked") - BeanPropertyAssocMany contacts() { + private BeanPropertyAssocMany contacts() { return (BeanPropertyAssocMany) customerDesc.getBeanProperty("contacts"); } @@ -44,6 +48,20 @@ public class BeanPropertyAssocManyTest extends BaseTestCase { assertTrue(ref.isReference()); } + @Test + public void lazyLoadMany_addsToParentCollection() { + + Customer customer = new Customer(); + customer.setContacts(new BeanList<>()); + + Contact contact = new Contact(); + contact.setCustomer(customer); + + contacts().lazyLoadMany((EntityBean) contact); + + assertThat(customer.getContacts()).hasSize(1); + assertThat(customer.getContacts().get(0)).isSameAs(contact); + } @Test public void findIdsByParentId() { diff --git a/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java b/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java index 7df67e9a7..043ecf6f0 100644 --- a/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java +++ b/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java @@ -1,10 +1,9 @@ package io.ebeaninternal.server.querydefn; -import io.ebean.OrderBy; +import io.ebean.ExpressionList; import io.ebean.Query; -import io.ebeaninternal.api.SpiExpression; -import io.ebeaninternal.api.SpiExpressionList; +import io.ebeaninternal.api.CQueryPlanKey; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; @@ -13,63 +12,55 @@ import io.ebeaninternal.server.expression.BaseExpressionTest; import org.junit.Test; import org.tests.model.basic.Customer; +import java.sql.Timestamp; + import static org.assertj.core.api.Assertions.assertThat; public class OrmQueryPlanKeyTest extends BaseExpressionTest { - @Test - public void equals_when_defaults() { - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - - assertSame(key1, key2); + @SuppressWarnings("unchecked") + private DefaultOrmQuery query() { + return (DefaultOrmQuery) server().find(Customer.class); } @Test - public void equals_when_diffDiscValue() { + public void equals_when_defaults() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey("A", null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key3 = new OrmQueryPlanKey("B", null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - assertDifferent(key2, key3); + assertSame(query().createQueryPlanKey(), query().createQueryPlanKey()); } @Test public void equals_when_diffTableJoinNull() { - TableJoin tableJoin = tableJoin("table", "id", "customer_id"); + DefaultOrmQuery q1 = query(); + q1.setM2MIncludeJoin(tableJoin("table", "id", "customer_id")); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - - assertDifferent(key1, key2); + assertDifferent(q1, query()); } @Test public void equals_when_diffTableJoin() { - TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); - TableJoin tableJoin2 = tableJoin("two", "id", "customer_id"); + DefaultOrmQuery q1 = query(); + q1.setM2MIncludeJoin(tableJoin("one", "cid", "customer_id")); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + DefaultOrmQuery q2 = query(); + q2.setM2MIncludeJoin(tableJoin("two", "cid", "customer_id")); - assertDifferent(key1, key2); + assertDifferent(q1, q2); } @Test public void equals_when_sameTableJoin() { - TableJoin tableJoin1 = tableJoin("one", "id", "customer_id"); - TableJoin tableJoin2 = tableJoin("one", "id", "customer_id"); + DefaultOrmQuery q1 = query(); + q1.setM2MIncludeJoin(tableJoin("one", "id", "cust_id")); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, tableJoin1, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, tableJoin2, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + DefaultOrmQuery q2 = query(); + q2.setM2MIncludeJoin(tableJoin("one", "id", "cust_id")); - assertSame(key1, key2); + assertSame(q1, q2); } private TableJoin tableJoin(String table, String col1, String col2) { @@ -82,297 +73,293 @@ public class OrmQueryPlanKeyTest extends BaseExpressionTest { @Test public void equals_when_diffQueryType() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.LIST, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + DefaultOrmQuery q1 = query(); + q1.setType(SpiQuery.Type.BEAN); - assertDifferent(key1, key2); + DefaultOrmQuery q2 = query(); + q2.setType(SpiQuery.Type.LIST); + + assertDifferent(q1, q2); } @Test public void equals_when_firstRowsDifferent() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 10, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + CQueryPlanKey key1 = query().setFirstRow(10).createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); + assertDifferent(key1, key2); + key1 = query().setFirstRow(10).createQueryPlanKey(); + key2 = query().setFirstRow(9).createQueryPlanKey(); + assertDifferent(key1, key2); + + key1 = query().createQueryPlanKey(); + key2 = query().setFirstRow(9).createQueryPlanKey(); assertDifferent(key1, key2); } @Test public void equals_when_maxRowsDifferent() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - + CQueryPlanKey key1 = query().setMaxRows(10).createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); + + key1 = query().setMaxRows(10).createQueryPlanKey(); + key2 = query().setMaxRows(9).createQueryPlanKey(); + assertDifferent(key1, key2); + + key1 = query().createQueryPlanKey(); + key2 = query().setMaxRows(9).createQueryPlanKey(); + assertDifferent(key1, key2); + } @Test public void equals_when_firstRowsMaxRowsSame() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 10, 20, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - + CQueryPlanKey key1 = query().setMaxRows(10).setFirstRow(20).createQueryPlanKey(); + CQueryPlanKey key2 = query().setFirstRow(20).setMaxRows(10).createQueryPlanKey(); assertSame(key1, key2); } @Test public void equals_when_diffDisableLazyLoading() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, true, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - - assertDifferent(key1, key2); + assertDifferent(query().setDisableLazyLoading(true), query()); } @Test public void equals_when_diffOrderByNull() { - OrderBy o1 = new OrderBy<>("id"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + CQueryPlanKey key1 = query().order("id").createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); + assertDifferent(key1, key2); + key1 = ((DefaultOrmQuery) query().order().asc("id")).createQueryPlanKey(); + key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); } @Test public void equals_when_orderBySame() { - OrderBy o1 = new OrderBy<>("id, name"); - OrderBy o2 = new OrderBy<>("id, name"); - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o1, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, o2, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - + CQueryPlanKey key1 = query().order("id, name").createQueryPlanKey(); + CQueryPlanKey key2 = query().order("id, name").createQueryPlanKey(); assertSame(key1, key2); } @Test public void equals_when_diffDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + + CQueryPlanKey key1 = query().setDistinct(true).createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); } @Test public void equals_when_sameDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, true, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + + CQueryPlanKey key1 = query().setDistinct(true).createQueryPlanKey(); + CQueryPlanKey key2 = query().setDistinct(true).createQueryPlanKey(); assertSame(key1, key2); } @Test public void equals_when_diffSqlDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + DefaultOrmQuery q1 = query(); + q1.setSqlDistinct(true); + CQueryPlanKey key1 = q1.createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); + assertDifferent(key1, key2); } @Test public void equals_when_sameSqlDistinct() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, true, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertSame(key1, key2); + + DefaultOrmQuery q1 = query(); + q1.setSqlDistinct(true); + + DefaultOrmQuery q2 = query(); + q2.setSqlDistinct(true); + + assertSame(q1, q2); } @Test - public void equals_when_diffMapKeyNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + public void equals_when_useDocStore() { + CQueryPlanKey key1 = query().setUseDocStore(true).createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); + assertDifferent(key1, key2); } @Test public void equals_when_diffMapKey() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "diff", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - } - @Test - public void equals_when_sameMapKey() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, "mapKey", null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertSame(key1, key2); + CQueryPlanKey key1 = query().setMapKey("name").createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); + assertDifferent(key1, key2); + + CQueryPlanKey key3 = query().setMapKey("email").createQueryPlanKey(); + assertDifferent(key1, key3); + + CQueryPlanKey key4 = query().setMapKey("name").createQueryPlanKey(); + assertSame(key1, key4); } @Test public void equals_when_diffIdNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + + CQueryPlanKey key1 = query().setId(42).createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); } @Test public void equals_when_idBothGiven() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 42, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, 23, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + + CQueryPlanKey key1 = query().setId(42).createQueryPlanKey(); + CQueryPlanKey key2 = query().setId(23).createQueryPlanKey(); assertSame(key1, key2); } @Test public void equals_when_diffTemporalMode() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); + + CQueryPlanKey key1 = query().createQueryPlanKey(); + CQueryPlanKey key2 = query().asDraft().createQueryPlanKey(); assertDifferent(key1, key2); + + CQueryPlanKey key3 = query().asOf(new Timestamp(System.currentTimeMillis())).createQueryPlanKey(); + assertDifferent(key1, key3); + + CQueryPlanKey key4 = query().setIncludeSoftDeletes().createQueryPlanKey(); + assertDifferent(key1, key4); } @Test public void equals_when_diffForUpdate() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - } - @Test - public void equals_when_diffForUpdate_NoWait() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.NOWAIT, null, null, null, null); + CQueryPlanKey key1 = query().forUpdate().createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); - } - @Test - public void equals_when_diffForUpdate_SkipLocked() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.BASE, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, Query.ForUpdate.SKIPLOCKED, null, null, null, null); - assertDifferent(key1, key2); + CQueryPlanKey key3 = query().forUpdateNoWait().createQueryPlanKey(); + assertDifferent(key1, key3); + + CQueryPlanKey key4 = query().forUpdateSkipLocked().createQueryPlanKey(); + assertDifferent(key1, key4); + + CQueryPlanKey key5 = query().forUpdate().createQueryPlanKey(); + assertSame(key1, key5); } @Test public void equals_when_diffRootAliasNull() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + + CQueryPlanKey key1 = query().alias("alias").createQueryPlanKey(); + CQueryPlanKey key2 = query().createQueryPlanKey(); assertDifferent(key1, key2); + + CQueryPlanKey key3 = query().alias("diff").createQueryPlanKey(); + assertDifferent(key1, key3); + + CQueryPlanKey key4 = query().alias("alias").createQueryPlanKey(); + assertSame(key1, key4); } - @Test - public void equals_when_diffRootAlias() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "diff", null, null, null); - assertDifferent(key1, key2); + + private DefaultOrmQuery list_id_eq_42() { + return (DefaultOrmQuery) server().find(Customer.class) + .where().eq("id", 42).query(); } - @Test - public void equals_when_sameRootAlias() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, "rootAlias", null, null, null); - assertSame(key1, key2); + private DefaultOrmQuery list_id_eq_43() { + return (DefaultOrmQuery) server().find(Customer.class) + .where().eq("id", 43).query(); } - SpiExpressionList list_id_eq_42() { - return (SpiExpressionList) server().find(Customer.class) - .where().eq("id", 42); - } - - SpiExpressionList list_id_eq_43() { - return (SpiExpressionList) server().find(Customer.class) - .where().eq("id", 43); - } - - SpiExpressionList list_id_eq_42_and_name_eq_rob() { - return (SpiExpressionList) server().find(Customer.class) - .where().eq("id", 43).eq("name", "rob"); + private DefaultOrmQuery list_id_eq_42_and_name_eq_rob() { + return (DefaultOrmQuery) server().find(Customer.class) + .where().eq("id", 43).eq("name", "rob").query(); } @Test public void equals_when_sameWhere() { - - SpiExpressionList list1 = list_id_eq_42(); - SpiExpressionList list2 = list_id_eq_43(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list2, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertSame(key1, key2); + assertSame(list_id_eq_42(), list_id_eq_43()); } @Test public void equals_when_diffWhere() { - SpiExpressionList where1 = list_id_eq_42(); - SpiExpressionList where2 = list_id_eq_42_and_name_eq_rob(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, where1, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, where2, null, SpiQuery.TemporalMode.DRAFT, null, null, null, null, null); - assertDifferent(key1, key2); + assertDifferent(list_id_eq_42(), list_id_eq_42_and_name_eq_rob()); } @Test public void equals_when_diffWhereNullLast() { - SpiExpressionList list1 = list_id_eq_42(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - } - - @Test - public void equals_when_diffWhereNullFirst() { - - SpiExpressionList list1 = list_id_eq_42(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, list1, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); + assertDifferent(list_id_eq_42(), query()); } @Test public void equals_when_diffHaving() { - SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - SpiExpression having2 = list_id_eq_42_and_name_eq_rob().copyForPlanKey(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + CQueryPlanKey key1 = planKey(query().having().eq("id", 42)); + CQueryPlanKey key2 = planKey(query().having().eq("id", 42).eq("name", "Rob")); assertDifferent(key1, key2); + + CQueryPlanKey key3 = planKey(query().where().eq("id", 42)); + assertDifferent(key1, key3); + + CQueryPlanKey key4 = planKey(query().having().eq("name", "Rob")); + assertDifferent(key1, key4); } + @Test public void equals_when_sameHaving() { - SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - SpiExpression having2 = list_id_eq_42().copyForPlanKey(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having2, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); + CQueryPlanKey key1 = planKey(query().having().eq("id", 42)); + CQueryPlanKey key2 = planKey(query().having().eq("id", 43)); assertSame(key1, key2); } - @Test - public void equals_when_havingNullLast() { - - SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - } - - @Test - public void equals_when_havingNullFirst() { - - SpiExpression having1 = list_id_eq_42().copyForPlanKey(); - - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, having1, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); - } - @Test public void equals_when_manualId() { - OrmQueryPlanKey key1 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, false, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - OrmQueryPlanKey key2 = new OrmQueryPlanKey(null, null, SpiQuery.Type.BEAN, null, 0, 0, false, true, null, false, false, null, null, null, null, null, SpiQuery.TemporalMode.CURRENT, null, null, null, null, null); - assertDifferent(key1, key2); + DefaultOrmQuery q1 = query(); + q1.setManualId(true); + + assertDifferent(q1, query()); } - private void assertDifferent(OrmQueryPlanKey key1, OrmQueryPlanKey key2) { + private CQueryPlanKey planKey(ExpressionList id) { + return planKey(id.query()); + } + + private CQueryPlanKey planKey(Query query) { + return ((DefaultOrmQuery) query).createQueryPlanKey(); + } + + private void assertDifferent(DefaultOrmQuery q1, DefaultOrmQuery q2) { + assertDifferent(q1.createQueryPlanKey(), q2.createQueryPlanKey()); + } + + private void assertSame(DefaultOrmQuery q1, DefaultOrmQuery q2) { + assertSame(q1.createQueryPlanKey(), q2.createQueryPlanKey()); + } + + private void assertDifferent(CQueryPlanKey key1, CQueryPlanKey key2) { assertThat(key1).isNotEqualTo(key2); assertThat(key1.hashCode()).isNotEqualTo(key2.hashCode()); } - private void assertSame(OrmQueryPlanKey key1, OrmQueryPlanKey key2) { + private void assertSame(CQueryPlanKey key1, CQueryPlanKey key2) { assertThat(key1).isEqualTo(key2); assertThat(key1.hashCode()).isEqualTo(key2.hashCode()); } From 607cf3156c472a294799d4ea8496277d55bc23d8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 13 Mar 2018 00:15:42 +1300 Subject: [PATCH 0182/1036] #1347 - Improve cleanup of inactive transactions from threadLocal when no end() used --- .../ebeaninternal/api/ScopedTransaction.java | 60 ++++++-- .../TestDuplicateKeyException.java | 4 +- .../transaction/TestExecuteComplete.java | 132 ++++++++++++++++++ 3 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/tests/transaction/TestExecuteComplete.java diff --git a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java index 833a3d7b6..a8d38b03f 100644 --- a/src/main/java/io/ebeaninternal/api/ScopedTransaction.java +++ b/src/main/java/io/ebeaninternal/api/ScopedTransaction.java @@ -21,6 +21,11 @@ public class ScopedTransaction extends SpiTransactionProxy { private ScopeTrans current; + /** + * Flag set when we clear the thread scope (on commit/rollback or end). + */ + private boolean scopeCleared; + public ScopedTransaction(TransactionScopeManager manager) { this.manager = manager; } @@ -47,30 +52,51 @@ public class ScopedTransaction extends SpiTransactionProxy { */ public void complete(Object returnOrThrowable, int opCode) { current.complete(returnOrThrowable, opCode); + // no finally here for pop() as we come in here twice if an + // error is thrown on commit (due to enhancement finally block) pop(); } /** - * Programmatic complete - finally block, try to commit. + * Internal programmatic complete - finally block, try to commit. */ public void complete() { - current.complete(); - pop(); + try { + current.complete(); + } finally { + pop(); + } + } + + private void clearScopeOnce() { + if (!scopeCleared) { + manager.set(null); + scopeCleared = true; + } + } + + private boolean clearScope() { + if (stack.isEmpty()) { + clearScopeOnce(); + return true; + } + return false; } private void pop() { - if (!stack.isEmpty()) { + if (!clearScope()) { current = stack.pop(); transaction = current.getTransaction(); - } else { - manager.set(null); } } @Override public void end() throws PersistenceException { - current.end(); - pop(); + try { + current.end(); + } finally { + pop(); + } } @Override @@ -80,17 +106,29 @@ public class ScopedTransaction extends SpiTransactionProxy { @Override public void commit() { - current.commitTransaction(); + try { + current.commitTransaction(); + } finally { + clearScope(); + } } @Override public void rollback() throws PersistenceException { - current.rollback(null); + try { + current.rollback(null); + } finally { + clearScope(); + } } @Override public void rollback(Throwable e) throws PersistenceException { - current.rollback(e); + try { + current.rollback(e); + } finally { + clearScope(); + } } @Override diff --git a/src/test/java/org/tests/inheritance/TestDuplicateKeyException.java b/src/test/java/org/tests/inheritance/TestDuplicateKeyException.java index 987cb5043..2b53a3d4a 100644 --- a/src/test/java/org/tests/inheritance/TestDuplicateKeyException.java +++ b/src/test/java/org/tests/inheritance/TestDuplicateKeyException.java @@ -3,11 +3,11 @@ package org.tests.inheritance; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.junit.Assert; +import org.junit.Test; import org.tests.model.basic.AttributeHolder; import org.tests.model.basic.ListAttribute; import org.tests.model.basic.ListAttributeValue; -import org.junit.Assert; -import org.junit.Test; public class TestDuplicateKeyException extends BaseTestCase { diff --git a/src/test/java/org/tests/transaction/TestExecuteComplete.java b/src/test/java/org/tests/transaction/TestExecuteComplete.java new file mode 100644 index 000000000..a8ec5f8c3 --- /dev/null +++ b/src/test/java/org/tests/transaction/TestExecuteComplete.java @@ -0,0 +1,132 @@ +package org.tests.transaction; + +import io.ebean.BaseTestCase; +import io.ebean.DataIntegrityException; +import io.ebean.Ebean; +import io.ebean.Transaction; +import io.ebean.TxScope; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; +import io.ebean.annotation.Transactional; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.server.transaction.DefaultTransactionThreadLocal; +import org.junit.Test; +import org.tests.model.basic.Customer; +import org.tests.model.basic.Order; + +import static org.assertj.core.api.StrictAssertions.assertThat; + +public class TestExecuteComplete extends BaseTestCase { + + + @ForPlatform(Platform.H2) + @Test + public void execute_when_errorOnCommit_threadLocalIsCleared() { + + try { + Ebean.execute(TxScope.required().setBatch(PersistBatch.ALL), () -> { + + Customer customer = Ebean.getReference(Customer.class, 42424242L); + Order order = new Order(); + order.setCustomer(customer); + + Ebean.save(customer); + }); + } catch (DataIntegrityException e) { + // assert the thread local has been cleaned up + SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn).isNull(); + } + } + + @ForPlatform(Platform.H2) + @Test + public void nestedExecute_when_errorOnCommit_threadLocalIsCleared() { + + try { + Ebean.execute(TxScope.required().setBatch(PersistBatch.ALL), () -> + Ebean.execute(() -> { + + Customer customer = Ebean.getReference(Customer.class, 42424242L); + Order order = new Order(); + order.setCustomer(customer); + + Ebean.save(customer); + })); + } catch (DataIntegrityException e) { + // assert the thread local has been cleaned up + SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn).isNull(); + } + } + + @ForPlatform(Platform.H2) + @Test + public void transactional_errorOnCommit_expect_threadScopeCleanup() { + + try { + errorOnCommit(); + } catch (DataIntegrityException e) { + SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn).isNull(); + } + } + + @Transactional(batchSize = 10) + private void errorOnCommit() { + Customer customer = Ebean.getReference(Customer.class, 42424242L); + Order order = new Order(); + order.setCustomer(customer); + + Ebean.save(customer); + } + + @ForPlatform(Platform.H2) + @Test + public void normal_expect_threadScopeCleanup() { + + Transaction txn1 = server().beginTransaction(); + try { + txn1.commit(); + } finally { + txn1.end(); + } + + SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn2).isNull(); + } + + @ForPlatform(Platform.H2) + @Test + public void missingEnd_expect_threadScopeCleanup() { + + Transaction txn1 = server().beginTransaction(); + try { + txn1.commit(); + } finally { + // accidentally omit end() + //txn1.end(); + } + + SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn2).isNull(); + } + + @ForPlatform(Platform.H2) + @Test + public void missingEnd_withRollbackOnly_expect_threadScopeCleanup() { + + Transaction txn1 = server().beginTransaction(); + try { + txn1.rollback(); + } finally { + // accidentally omit end() + //txn1.end(); + } + + SpiTransaction txn2 = DefaultTransactionThreadLocal.get("h2"); + assertThat(txn2).isNull(); + } + +} From afead2da41143b4cb6e6c682007c6faa1b233944 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 13 Mar 2018 23:55:47 +1300 Subject: [PATCH 0183/1036] #1221 - ENH: Add a merge(bean) and merge(bean, paths) --- src/main/java/io/ebean/Ebean.java | 10 + src/main/java/io/ebean/EbeanServer.java | 16 + src/main/java/io/ebean/MergeOptions.java | 29 ++ .../java/io/ebean/MergeOptionsBuilder.java | 80 ++++ .../io/ebean/bean/EntityBeanIntercept.java | 16 + .../io/ebeaninternal/api/SpiEbeanServer.java | 5 + .../server/core/DefaultServer.java | 24 +- .../server/core/PersistRequestBean.java | 45 ++- .../ebeaninternal/server/core/Persister.java | 8 + .../server/deploy/BaseCollectionHelp.java | 17 + .../server/deploy/BeanCollectionHelp.java | 6 + .../server/deploy/BeanListHelp.java | 2 +- .../server/deploy/BeanMapHelp.java | 2 +- .../server/deploy/BeanPropertyAssocMany.java | 7 + .../server/deploy/BeanSetHelp.java | 2 +- .../server/persist/DefaultPersister.java | 115 +++--- .../ebeaninternal/server/persist/Flags.java | 135 +++++++ .../server/persist/MergeContext.java | 56 +++ .../server/persist/MergeHandler.java | 147 +++++++ .../server/persist/MergeNode.java | 74 ++++ .../server/persist/MergeNodeAssocMany.java | 57 +++ .../server/persist/MergeNodeAssocOne.java | 60 +++ .../server/persist/MergeRequest.java | 64 +++ .../server/persist/SaveManyPropRequest.java | 12 +- .../ebeaninternal/api/TDSpiEbeanServer.java | 16 + .../server/persist/BatchedBeanHolderTest.java | 9 +- .../server/persist/FlagsTest.java | 44 ++ src/test/java/org/tests/merge/MAddress.java | 33 ++ src/test/java/org/tests/merge/MBase.java | 32 ++ src/test/java/org/tests/merge/MContact.java | 67 ++++ .../java/org/tests/merge/MContactMessage.java | 54 +++ src/test/java/org/tests/merge/MCustomer.java | 68 ++++ .../java/org/tests/merge/TestMergeBasic.java | 117 ++++++ .../org/tests/merge/TestMergeCustomer.java | 376 ++++++++++++++++++ .../java/org/tests/model/basic/UUOne.java | 28 ++ .../java/org/tests/model/basic/UUTwo.java | 29 ++ .../joins/TestDisjunctWhereOuterOnMany.java | 8 +- 37 files changed, 1804 insertions(+), 66 deletions(-) create mode 100644 src/main/java/io/ebean/MergeOptions.java create mode 100644 src/main/java/io/ebean/MergeOptionsBuilder.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/Flags.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeContext.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeHandler.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeNode.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocMany.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocOne.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/MergeRequest.java create mode 100644 src/test/java/io/ebeaninternal/server/persist/FlagsTest.java create mode 100644 src/test/java/org/tests/merge/MAddress.java create mode 100644 src/test/java/org/tests/merge/MBase.java create mode 100644 src/test/java/org/tests/merge/MContact.java create mode 100644 src/test/java/org/tests/merge/MContactMessage.java create mode 100644 src/test/java/org/tests/merge/MCustomer.java create mode 100644 src/test/java/org/tests/merge/TestMergeBasic.java create mode 100644 src/test/java/org/tests/merge/TestMergeCustomer.java diff --git a/src/main/java/io/ebean/Ebean.java b/src/main/java/io/ebean/Ebean.java index 2f0031fd1..97f895921 100644 --- a/src/main/java/io/ebean/Ebean.java +++ b/src/main/java/io/ebean/Ebean.java @@ -638,6 +638,16 @@ public final class Ebean { serverMgr.getDefaultServer().updateAll(beans); } + /** + * Merge the bean using the given merge options. + * + * @param bean The bean to merge + * @param options The options to control the merge + */ + public static void merge(Object bean, MergeOptions options) { + serverMgr.getDefaultServer().merge(bean, options); + } + /** * Save all the beans from a Collection. */ diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java index eab9ee668..f13cb86e7 100644 --- a/src/main/java/io/ebean/EbeanServer.java +++ b/src/main/java/io/ebean/EbeanServer.java @@ -1615,6 +1615,22 @@ public interface EbeanServer { */ void updateAll(Collection beans, Transaction transaction) throws OptimisticLockException; + /** + * Merge the bean using the given merge options. + * + * @param bean The bean to merge + * @param options The options to control the merge + */ + void merge(Object bean, MergeOptions options); + + /** + * Merge the bean using the given merge options and a transaction. + * + * @param bean The bean to merge + * @param options The options to control the merge + */ + void merge(Object bean, MergeOptions options, Transaction transaction); + /** * Insert the bean. *

diff --git a/src/main/java/io/ebean/MergeOptions.java b/src/main/java/io/ebean/MergeOptions.java new file mode 100644 index 000000000..0d1fae70b --- /dev/null +++ b/src/main/java/io/ebean/MergeOptions.java @@ -0,0 +1,29 @@ +package io.ebean; + +import java.util.Set; + +/** + * Options used to control a merge. Use MergeOptionsBuilder to create an instance. + *

+ * Instances of MergeOptions are thread safe and safe to share across threads. + */ +public interface MergeOptions { + + /** + * Returns true if Id values are supplied by the client. + *

+ * This would be the case when for example a mobile creates data in it's own local database + * and then sync's. In this case often the id values are UUID. + */ + boolean isClientGeneratedIds(); + + /** + * Return true if delete permanent should be used and false for 'normal' delete that allows soft deletes. + */ + boolean isDeletePermanent(); + + /** + * Return the paths included in the merge. + */ + Set paths(); +} diff --git a/src/main/java/io/ebean/MergeOptionsBuilder.java b/src/main/java/io/ebean/MergeOptionsBuilder.java new file mode 100644 index 000000000..c17b2d88d --- /dev/null +++ b/src/main/java/io/ebean/MergeOptionsBuilder.java @@ -0,0 +1,80 @@ +package io.ebean; + +import java.util.LinkedHashSet; +import java.util.Set; + +/** + * Builds a MergeOptions which is immutable and thread safe. + */ +public class MergeOptionsBuilder { + + private Set paths = new LinkedHashSet<>(); + + private boolean clientGeneratedIds; + + private boolean deletePermanent = true; + + /** + * Add a path that will included in the merge. + * + * @param path The path relative to the root type. + * @return The builder to chain another addPath() or build(). + */ + public MergeOptionsBuilder addPath(String path) { + paths.add(path); + return this; + } + + /** + * Set to true if Id values are supplied by the client. + *

+ * This would be the case when for example a mobile creates data in it's own local database + * and then sync's. In this case often the id values are UUID. + */ + public MergeOptionsBuilder setClientGeneratedIds() { + this.clientGeneratedIds = true; + return this; + } + + /** + * Set that deletions should use delete permanent (rather than default which allows soft deletes). + */ + public MergeOptionsBuilder setDeletePermanent() { + this.deletePermanent = true; + return this; + } + + /** + * Build and return the MergeOptions instance. + */ + public MOptions build() { + return new MOptions(paths, clientGeneratedIds, deletePermanent); + } + + private static class MOptions implements MergeOptions { + + private final boolean clientGeneratedIds; + private final boolean deletePermanent; + private final Set paths; + + private MOptions(Set paths, boolean clientGeneratedIds, boolean deletePermanent) { + this.paths = paths; + this.clientGeneratedIds = clientGeneratedIds; + this.deletePermanent = deletePermanent; + } + + public Set paths() { + return paths; + } + + @Override + public boolean isClientGeneratedIds() { + return clientGeneratedIds; + } + + @Override + public boolean isDeletePermanent() { + return deletePermanent; + } + } +} diff --git a/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/src/main/java/io/ebean/bean/EntityBeanIntercept.java index de6c82456..cde09876f 100644 --- a/src/main/java/io/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/io/ebean/bean/EntityBeanIntercept.java @@ -52,6 +52,8 @@ public final class EntityBeanIntercept implements Serializable { */ private int state; + private boolean forceUpdate; + private boolean readOnly; private boolean dirty; @@ -292,6 +294,20 @@ public final class EntityBeanIntercept implements Serializable { this.readOnly = readOnly; } + /** + * Set the bean to be updated when persisted (for merge). + */ + public void setForceUpdate(boolean forceUpdate) { + this.forceUpdate = forceUpdate; + } + + /** + * Return true if the entity should be updated. + */ + public boolean isUpdate() { + return forceUpdate || state == STATE_LOADED; + } + /** * Return true if the entity has been loaded. */ diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java index eb449157f..8232773fc 100644 --- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java @@ -263,4 +263,9 @@ public interface SpiEbeanServer extends EbeanServer, BeanLoader, BeanCollectionL * Visit all the metrics (typically reporting them). */ void visitMetrics(MetricVisitor visitor); + + /** + * Return true if a row for the bean type and id exists. + */ + boolean exists(Class beanType, Object beanId, Transaction transaction); } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 700f10439..7a75abd5f 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -12,6 +12,7 @@ import io.ebean.Filter; import io.ebean.FutureIds; import io.ebean.FutureList; import io.ebean.FutureRowCount; +import io.ebean.MergeOptions; import io.ebean.PagedList; import io.ebean.PersistenceContextScope; import io.ebean.ProfileLocation; @@ -915,6 +916,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return new DefaultUpdateQuery<>(createQuery(beanType)); } + @Override + public void merge(Object bean, MergeOptions options) { + merge(bean, options, null); + } + + @Override + public void merge(Object bean, MergeOptions options, Transaction transaction) { + BeanDescriptor desc = getBeanDescriptor(bean.getClass()); + if (desc == null) { + throw new PersistenceException(bean.getClass().getName() + " is NOT an Entity Bean registered with this server?"); + } + executeInTrans((txn) -> persister.merge(desc, checkEntityBean(bean), options, txn), transaction); + } + @Override public Query find(Class beanType) { return createQuery(beanType); @@ -1271,6 +1286,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } } + @Override + public boolean exists(Class beanType, Object beanId, Transaction transaction) { + List ids = findIds(find(beanType).setId(beanId), transaction); + return !ids.isEmpty(); + } + @Override public List findIds(Query query, Transaction t) { @@ -2234,8 +2255,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { /** * Returns a set of properties if saving the bean will violate the unique constraints (defined by given properties). */ - private Set checkUniqueness(EntityBean entityBean, BeanDescriptor beanDesc, BeanProperty[] props, - Transaction transaction) { + private Set checkUniqueness(EntityBean entityBean, BeanDescriptor beanDesc, BeanProperty[] props, Transaction transaction) { BeanProperty idProperty = beanDesc.getIdProperty(); Query query = new DefaultOrmQuery<>(beanDesc, this, expressionFactory); ExpressionList exprList = query.where(); diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 8c0113b1e..33f72c636 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -23,6 +23,7 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.id.ImportedId; import io.ebeaninternal.server.persist.BatchControl; import io.ebeaninternal.server.persist.BatchedSqlException; +import io.ebeaninternal.server.persist.Flags; import io.ebeaninternal.server.persist.PersistExecute; import io.ebeaninternal.server.transaction.BeanPersistIdMap; import io.ebeanservice.docstore.api.DocStoreUpdate; @@ -75,6 +76,8 @@ public final class PersistRequestBean extends PersistRequest implements BeanP private final boolean publish; + private int flags; + private DocStoreMode docStoreMode; private ConcurrencyMode concurrencyMode; @@ -152,7 +155,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP private boolean getterCallback; public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager mgr, SpiTransaction t, - PersistExecute persistExecute, PersistRequest.Type type, boolean saveRecurse, boolean publish) { + PersistExecute persistExecute, PersistRequest.Type type, int flags) { super(server, t, persistExecute); this.entityBean = (EntityBean) bean; @@ -165,7 +168,8 @@ public final class PersistRequestBean extends PersistRequest implements BeanP this.controller = beanDescriptor.getPersistController(); this.type = type; this.docStoreMode = calcDocStoreMode(transaction, type); - if (saveRecurse) { + this.flags = flags; + if (Flags.isRecurse(flags)) { this.persistCascade = t.isPersistCascade(); } @@ -179,7 +183,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP beanDescriptor.checkMutableProperties(intercept); } this.concurrencyMode = beanDescriptor.getConcurrencyMode(intercept); - this.publish = publish; + this.publish = Flags.isPublish(flags); if (isMarkDraftDirty(publish)) { beanDescriptor.setDraftDirty(entityBean, true); } @@ -231,6 +235,13 @@ public final class PersistRequestBean extends PersistRequest implements BeanP if (createImplicitTransIfRequired()) { docStoreMode = calcDocStoreMode(transaction, type); } + checkBatchEscalationOnCascade(); + } + + /** + * Check for batch escalation on cascade. + */ + public void checkBatchEscalationOnCascade() { if (transaction.checkBatchEscalationOnCascade(this)) { // we escalated to use batch mode so flush when done // but if createdTransaction then commit will flush it @@ -1076,6 +1087,13 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return requestUpdateAllLoadedProps; } + /** + * Return the flags set on this persist request. + */ + public int getFlags() { + return flags; + } + /** * Return true if this request is a 'publish' action. */ @@ -1226,4 +1244,25 @@ public final class PersistRequestBean extends PersistRequest implements BeanP public void profile() { profileBase(type.profileEventId, profileOffset, beanDescriptor.getProfileId(), 1); } + + /** + * Set the request flags indicating this is an insert. + */ + public void flagInsert() { + flags = Flags.setInsert(flags); + } + + /** + * Unset the request insert flag indicating this is an update. + */ + public void flagUpdate() { + flags = Flags.unsetInsert(flags); + } + + /** + * Return true if this request is an insert. + */ + public boolean isInsertedParent() { + return Flags.isInsert(flags); + } } diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java index 981032053..82e46b856 100644 --- a/src/main/java/io/ebeaninternal/server/core/Persister.java +++ b/src/main/java/io/ebeaninternal/server/core/Persister.java @@ -1,12 +1,15 @@ package io.ebeaninternal.server.core; import io.ebean.CallableSql; +import io.ebean.MergeOptions; import io.ebean.Query; import io.ebean.SqlUpdate; import io.ebean.Transaction; import io.ebean.Update; import io.ebean.bean.EntityBean; import io.ebean.meta.MetricVisitor; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.server.deploy.BeanDescriptor; import java.util.Collection; import java.util.List; @@ -16,6 +19,11 @@ import java.util.List; */ public interface Persister { + /** + * Merge the bean. + */ + int merge(BeanDescriptor desc, EntityBean entityBean, MergeOptions options, SpiTransaction transaction); + /** * Update the bean. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java new file mode 100644 index 000000000..5e50e9700 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java @@ -0,0 +1,17 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.BeanCollection; + +import java.util.Collection; + +abstract class BaseCollectionHelp implements BeanCollectionHelp { + + @Override + public Collection underlying(Object value) { + if (value instanceof BeanCollection) { + return ((BeanCollection)value).getActualDetails(); + } else { + return (Collection)value; + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java index 1de0e6d24..8891048bb 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java @@ -10,6 +10,7 @@ import io.ebean.bean.EntityBean; import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; +import java.util.Collection; /** * Helper functions for performing tasks on Lists Sets or Maps. @@ -21,6 +22,11 @@ public interface BeanCollectionHelp { */ void setLoader(BeanCollectionLoader loader); + /** + * Return the underlying collection of beans. + */ + Collection underlying(Object value); + /** * Return the mechanism to add beans to the underlying collection. *

diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java index 1f5bde3c8..df5429233 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java @@ -17,7 +17,7 @@ import java.util.List; /** * Helper object for dealing with Lists. */ -public final class BeanListHelp implements BeanCollectionHelp { +public final class BeanListHelp extends BaseCollectionHelp { private final BeanPropertyAssocMany many; private final BeanDescriptor targetDescriptor; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java index c91b4d22e..e3b42bea7 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java @@ -18,7 +18,7 @@ import java.util.Map.Entry; /** * Helper specifically for dealing with Maps. */ -public final class BeanMapHelp implements BeanCollectionHelp { +public final class BeanMapHelp extends BaseCollectionHelp { private final BeanPropertyAssocMany many; private final BeanDescriptor targetDescriptor; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 9f52a6a33..f193624b0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -205,6 +205,13 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { // by default not including "Many" properties in document store } + /** + * Return the underlying collection of beans. + */ + public Collection getRawCollection(EntityBean bean) { + return help.underlying(getVal(bean)); + } + /** * Copy collection value if existing is empty. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java index f191b919f..0dfdf40af 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java @@ -17,7 +17,7 @@ import java.util.Set; /** * Helper specifically for dealing with Sets. */ -public final class BeanSetHelp implements BeanCollectionHelp { +public final class BeanSetHelp extends BaseCollectionHelp { private final BeanPropertyAssocMany many; private final BeanDescriptor targetDescriptor; diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 0be2f64ae..0b3d20e1a 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.persist; import io.ebean.CallableSql; +import io.ebean.MergeOptions; import io.ebean.Query; import io.ebean.SqlUpdate; import io.ebean.Transaction; @@ -53,8 +54,6 @@ import java.util.Set; *

  • Handles cascading of save and delete
  • *
  • Handles the batching and queueing
  • *

    - * - * @see io.ebeaninternal.server.persist.DefaultPersistExecute */ public final class DefaultPersister implements Persister { @@ -161,7 +160,7 @@ public final class DefaultPersister implements Persister { draftHandler.resetDraft(draftBean); PUB.trace("draftRestore bean [{}] id[{}]", desc.getName(), draftHandler.getId()); - update(createRequest(draftBean, transaction, null, mgr, Type.UPDATE, true, false)); + update(createRequest(draftBean, transaction, null, mgr, Type.UPDATE, Flags.RECURSE)); } PUB.debug("draftRestore - complete for [{}]", desc.getName()); @@ -211,7 +210,7 @@ public final class DefaultPersister implements Persister { Type persistType = draftHandler.isInsert() ? Type.INSERT : Type.UPDATE; PUB.trace("publish bean [{}] id[{}] type[{}]", desc.getName(), draftHandler.getId(), persistType); - PersistRequestBean request = createRequest(liveBean, transaction, null, mgr, persistType, true, true); + PersistRequestBean request = createRequest(liveBean, transaction, null, mgr, persistType, Flags.PUBLISH_RECURSE); if (persistType == Type.INSERT) { insert(request); } else { @@ -281,7 +280,7 @@ public final class DefaultPersister implements Persister { // update the dirty status on the drafts that have been published PUB.debug("publish - update dirty status on [{}] drafts", draftUpdates.size()); for (T draftUpdate : draftUpdates) { - update(createRequest(draftUpdate, transaction, null, mgr, Type.UPDATE, false, false)); + update(createRequest(draftUpdate, transaction, null, mgr, Type.UPDATE, Flags.ZERO)); } } } @@ -346,6 +345,28 @@ public final class DefaultPersister implements Persister { return deleteRequest(createRequest(detailBean, t, deleteType)); } + @Override + public int merge(BeanDescriptor desc, EntityBean bean, MergeOptions options, SpiTransaction transaction) { + + MergeHandler merge = new MergeHandler(server, desc, bean, options, transaction); + List deleteBeans = merge.merge(); + if (!deleteBeans.isEmpty()) { + // all detected deletes for the merge paths + for (EntityBean deleteBean : deleteBeans) { + delete(deleteBean, transaction, options.isDeletePermanent()); + } + } + + // cascade save as normal with forceUpdate flags set + PersistRequestBean request = createRequestRecurse(bean, transaction, null, Flags.MERGE); + request.checkBatchEscalationOnCascade(); + saveRecurse(request); + request.flushBatchOnCascade(); + + // lambda expects a return + return 0; + } + /** * Update the bean. */ @@ -368,7 +389,7 @@ public final class DefaultPersister implements Persister { if (req.isReference()) { // its a reference so see if there are manys to save... if (req.isPersistCascade()) { - saveAssocMany(false, req, false); + saveAssocMany(req); } req.checkUpdatedManysOnly(); } else { @@ -389,7 +410,7 @@ public final class DefaultPersister implements Persister { */ @Override public void save(EntityBean bean, Transaction t) { - if (bean._ebean_getIntercept().isLoaded()) { + if (bean._ebean_getIntercept().isUpdate()) { // deleteMissingChildren is false when using 'save' on 'loaded' beans update(bean, t, false); } else { @@ -416,19 +437,22 @@ public final class DefaultPersister implements Persister { } } - void saveRecurse(EntityBean bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) { + void saveRecurse(EntityBean bean, Transaction t, Object parentBean, int flags) { // determine insert or update taking into account stateless updates - PersistRequestBean request = createRequestRecurse(bean, t, parentBean, insertMode, publish); + PersistRequestBean request = createRequestRecurse(bean, t, parentBean, flags); + saveRecurse(request); + } + private void saveRecurse(PersistRequestBean request) { if (request.isReference()) { // its a reference... if (request.isPersistCascade()) { // save any associated List held beans - saveAssocMany(false, request, insertMode); + request.flagUpdate(); + saveAssocMany(request); } request.checkUpdatedManysOnly(); - } else { if (request.isInsert()) { insert(request); @@ -447,11 +471,11 @@ public final class DefaultPersister implements Persister { // skip as already inserted/updated in this request (recursive cascading) return; } - + request.flagInsert(); try { if (request.isPersistCascade()) { // save associated One beans recursively first - saveAssocOne(request, true); + saveAssocOne(request); } // set the IDGenerated value if required @@ -460,7 +484,7 @@ public final class DefaultPersister implements Persister { if (request.isPersistCascade()) { // save any associated List held beans - saveAssocMany(true, request, true); + saveAssocMany(request); } } finally { request.unRegisterBean(); @@ -476,11 +500,11 @@ public final class DefaultPersister implements Persister { // skip as already inserted/updated in this request (recursive cascading) return; } - + request.flagUpdate(); try { if (request.isPersistCascade()) { // save associated One beans recursively first - saveAssocOne(request, false); + saveAssocOne(request); } if (request.isDirty()) { @@ -495,7 +519,7 @@ public final class DefaultPersister implements Persister { if (request.isPersistCascade()) { // save all the beans in assocMany's after - saveAssocMany(false, request, false); + saveAssocMany(request); } request.checkUpdatedManysOnly(); @@ -518,7 +542,7 @@ public final class DefaultPersister implements Persister { if (originalRequest.isHardDeleteDraft()) { // a hard delete of a draftable bean so first we need to delete the associated 'live' bean // due to FK constraint and then after that execute the original delete of the draft bean - return deleteRequest(createPublishRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, true), originalRequest); + return deleteRequest(createPublishRequest(originalRequest.createReference(), t, Type.DELETE_PERMANENT, Flags.PUBLISH), originalRequest); } else { // normal delete or soft delete @@ -610,7 +634,7 @@ public final class DefaultPersister implements Persister { int rowCount = deleteRecurse(bean, transaction, permanent); if (rowCount == -1) { total = -1; - } else if (total != -1){ + } else if (total != -1) { total += rowCount; } } @@ -838,7 +862,7 @@ public final class DefaultPersister implements Persister { * bean to the child beans. *

    */ - private void saveAssocMany(boolean insertedParent, PersistRequestBean request, boolean insertMode) { + private void saveAssocMany(PersistRequestBean request) { EntityBean parentBean = request.getEntityBean(); BeanDescriptor desc = request.getBeanDescriptor(); @@ -854,7 +878,7 @@ public final class DefaultPersister implements Persister { if (!prop.isSaveRecurseSkippable(detailBean)) { t.depth(+1); prop.setParentBeanToChild(parentBean, detailBean); - saveRecurse(detailBean, t, parentBean, insertMode, request.isPublish()); + saveRecurse(detailBean, t, parentBean, request.getFlags()); t.depth(-1); } } @@ -863,10 +887,11 @@ public final class DefaultPersister implements Persister { // many's with cascade save BeanPropertyAssocMany[] manys = desc.propertiesManySave(); + boolean insertedParent = request.isInsertedParent(); for (BeanPropertyAssocMany many : manys) { // check that property is loaded and collection should be cascaded to if (request.isLoadedProperty(many) && !many.isSkipSaveBeanCollection(parentBean, insertedParent)) { - saveMany(new SaveManyPropRequest(insertedParent, many, parentBean, request), insertMode); + saveMany(new SaveManyPropRequest(insertedParent, many, parentBean, request)); if (!insertedParent) { request.addUpdatedManyProperty(many); } @@ -874,7 +899,7 @@ public final class DefaultPersister implements Persister { } } - private void saveMany(SaveManyPropRequest saveMany, boolean insertMode) { + private void saveMany(SaveManyPropRequest saveMany) { if (saveMany.getMany().hasJoinTable()) { @@ -882,7 +907,7 @@ public final class DefaultPersister implements Persister { // we only allow one direction based on first traversed basis boolean saveIntersectionFromThisDirection = saveMany.isSaveIntersection(); if (saveMany.isCascade()) { - saveAssocManyDetails(saveMany, false, insertMode); + saveAssocManyDetails(saveMany, false); } // for ManyToMany save the 'relationship' via inserts/deletes // into/from the intersection table @@ -900,7 +925,7 @@ public final class DefaultPersister implements Persister { } if (saveMany.isCascade()) { // potentially deletes 'missing children' for 'stateless update' - saveAssocManyDetails(saveMany, saveMany.isDeleteMissingChildren(), insertMode); + saveAssocManyDetails(saveMany, saveMany.isDeleteMissingChildren()); } } } @@ -922,7 +947,7 @@ public final class DefaultPersister implements Persister { EntityBean eb = (EntityBean) removedBean; if (eb._ebean_getIntercept().isLoaded()) { // only delete if the bean was loaded meaning that it is known to exist in the DB - deleteRequest(createPublishRequest(removedBean, saveMany.getTransaction(), PersistRequest.Type.DELETE, saveMany.isPublish())); + deleteRequest(createPublishRequest(removedBean, saveMany.getTransaction(), PersistRequest.Type.DELETE, saveMany.getFlags())); } } } @@ -933,9 +958,9 @@ public final class DefaultPersister implements Persister { /** * Save the details from a OneToMany collection. */ - private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren, boolean insertMode) { + private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren) { - saveMany.saveDetails(this, deleteMissingChildren, insertMode); + saveMany.saveDetails(this, deleteMissingChildren); } /** @@ -1056,13 +1081,12 @@ public final class DefaultPersister implements Persister { return false; } - private int deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany many, Transaction t, boolean publish) { + private void deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany many, Transaction t, boolean publish) { // delete all intersection rows for this bean IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean, publish); SqlUpdate sqlDelete = intRow.createDeleteChildren(server); - - return executeSqlUpdate(sqlDelete, t); + executeSqlUpdate(sqlDelete, t); } /** @@ -1154,7 +1178,7 @@ public final class DefaultPersister implements Persister { *

    */ void deleteManyDetails(SpiTransaction t, BeanDescriptor desc, EntityBean parentBean, - BeanPropertyAssocMany many, List excludeDetailIds, boolean softDelete) { + BeanPropertyAssocMany many, List excludeDetailIds, boolean softDelete) { if (many.getCascadeInfo().isDelete()) { // cascade delete the beans in the collection @@ -1202,7 +1226,7 @@ public final class DefaultPersister implements Persister { /** * Save any associated one beans. */ - private void saveAssocOne(PersistRequestBean request, boolean insertMode) { + private void saveAssocOne(PersistRequestBean request) { BeanDescriptor desc = request.getBeanDescriptor(); @@ -1219,7 +1243,7 @@ public final class DefaultPersister implements Persister { && !request.isParent(detailBean)) { SpiTransaction t = request.getTransaction(); t.depth(-1); - saveRecurse(detailBean, t, null, insertMode, request.isPublish()); + saveRecurse(detailBean, t, null, request.getFlags()); t.depth(+1); } } @@ -1315,25 +1339,25 @@ public final class DefaultPersister implements Persister { * perform an insert, update or delete. */ private PersistRequestBean createRequest(T bean, Transaction t, PersistRequest.Type type) { - return createRequestInternal(bean, t, type, false, false); + return createRequestInternal(bean, t, type, Flags.ZERO); } /** * Create the Persist Request Object additionally specifying the publish status. */ - private PersistRequestBean createPublishRequest(T bean, Transaction t, PersistRequest.Type type, boolean publish) { - return createRequestInternal(bean, t, type, false, publish); + private PersistRequestBean createPublishRequest(T bean, Transaction t, PersistRequest.Type type, int flags) { + return createRequestInternal(bean, t, type, Flags.unsetRecuse(flags)); } /** * Create the Persist Request Object additionally specifying the publish status. */ - private PersistRequestBean createRequestInternal(T bean, Transaction t, PersistRequest.Type type, boolean saveRecurse, boolean publish) { + private PersistRequestBean createRequestInternal(T bean, Transaction t, PersistRequest.Type type, int flags) { BeanManager mgr = getBeanManager(bean); if (mgr == null) { throw new PersistenceException(errNotRegistered(bean.getClass())); } - return createRequest(bean, t, null, mgr, type, saveRecurse, publish); + return createRequest(bean, t, null, mgr, type, flags); } /** @@ -1341,7 +1365,7 @@ public final class DefaultPersister implements Persister { *

    * This call determines the PersistRequest.Type based on bean state and the insert flag (root persist type). */ - private PersistRequestBean createRequestRecurse(T bean, Transaction t, Object parentBean, boolean insertMode, boolean publish) { + private PersistRequestBean createRequestRecurse(T bean, Transaction t, Object parentBean, int flags) { BeanManager mgr = getBeanManager(bean); if (mgr == null) { throw new PersistenceException(errNotRegistered(bean.getClass())); @@ -1349,14 +1373,15 @@ public final class DefaultPersister implements Persister { BeanDescriptor desc = mgr.getBeanDescriptor(); EntityBean entityBean = (EntityBean) bean; PersistRequest.Type type; - if (publish) { + if (Flags.isPublishOrMerge(flags)) { // insert if it is a new bean (as publish created it) - type = entityBean._ebean_getIntercept().isNew() ? Type.INSERT : Type.UPDATE; + type = entityBean._ebean_getIntercept().isUpdate() ? Type.UPDATE : Type.INSERT; } else { // determine Insert or Update based on bean state and insert flag + boolean insertMode = Flags.isInsert(flags); type = desc.isInsertMode(entityBean._ebean_getIntercept(), insertMode) ? Type.INSERT : Type.UPDATE; } - return createRequest(bean, t, parentBean, mgr, type, true, publish); + return createRequest(bean, t, parentBean, mgr, type, Flags.setRecurse(flags)); } /** @@ -1365,7 +1390,7 @@ public final class DefaultPersister implements Persister { */ @SuppressWarnings({"unchecked", "rawtypes"}) private PersistRequestBean createRequest(T bean, Transaction t, Object parentBean, BeanManager mgr, - PersistRequest.Type type, boolean saveRecurse, boolean publish) { + PersistRequest.Type type, int flags) { if (type == Type.DELETE_PERMANENT) { type = Type.DELETE; @@ -1374,7 +1399,7 @@ public final class DefaultPersister implements Persister { type = Type.SOFT_DELETE; } - return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, saveRecurse, publish); + return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, flags); } private String errNotRegistered(Class beanClass) { diff --git a/src/main/java/io/ebeaninternal/server/persist/Flags.java b/src/main/java/io/ebeaninternal/server/persist/Flags.java new file mode 100644 index 000000000..ffde410c5 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/Flags.java @@ -0,0 +1,135 @@ +package io.ebeaninternal.server.persist; + +/** + * Flags used in persistence. + *

    + * Allows passing of flag state when recursively persisting. + */ +public class Flags { + + /** + * Indicates the bean is being inserted. + */ + public static final int INSERT = 0x00000001; + + /** + * Indicates persist cascade. + */ + public static final int RECURSE = 0x00000002; + + /** + * Indicates Publish mode. + */ + public static final int PUBLISH = 0x00000004; + + /** + * Indicates Merge mode. + */ + public static final int MERGE = 0x00000008; + + /** + * No flags set. + */ + public static final int ZERO = 0; + + public static final int PUBLISH_RECURSE = PUBLISH + RECURSE; + + private static final int PUBLISH_MERGE = PUBLISH + MERGE; + + /** + * Return true if the bean is being inserted. + */ + public static boolean isInsert(int state) { + return isSet(state, INSERT); + } + + /** + * Return true if persist cascading. + */ + public static boolean isRecurse(int state) { + return isSet(state, RECURSE); + } + + /** + * Return true if part of a Publish. + */ + public static boolean isPublish(int state) { + return isSet(state, PUBLISH); + } + + /** + * Return true if part of a Merge. + */ + public static boolean isMerge(int state) { + return isSet(state, PUBLISH); + } + + /** + * Return true if part of a Merge or Publish. + */ + public static boolean isPublishOrMerge(long state) { + return (state & PUBLISH_MERGE) != 0; + } + + /** + * Return true if the given flag is set. + */ + public static boolean isSet(int state, int flag) { + return (state & flag) == flag; + } + + /** + * Set Insert flag. + */ + public static int setInsert(int state) { + return set(state, INSERT, true); + } + + /** + * Parent was not inserted. + */ + public static int unsetInsert(int state) { + return set(state, INSERT, false); + } + + /** + * Set Recurse flag. + */ + public static int setRecurse(int state) { + return set(state, RECURSE, true); + } + + public static int unsetRecuse(int state) { + return set(state, RECURSE, false); + } + + /** + * Set Publish flag. + */ + public static int setPublish(int state) { + return set(state, PUBLISH, true); + } + + public static int unsetPublish(int state) { + return set(state, PUBLISH, false); + } + + /** + * Set Merge flag. + */ + public static int setMerge(int state) { + return set(state, MERGE, true); + } + + public static int unsetMerge(int state) { + return set(state, MERGE, false); + } + + private static int set(int state, int flag, boolean setFlag) { + if (setFlag) { + return (state |= flag); + } else { + return state &= ~flag; + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeContext.java b/src/main/java/io/ebeaninternal/server/persist/MergeContext.java new file mode 100644 index 000000000..8de5b7ee4 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeContext.java @@ -0,0 +1,56 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiTransaction; + +import java.util.ArrayList; +import java.util.List; + +/** + * Context used for merge processing. + */ +class MergeContext { + + private final SpiEbeanServer server; + + private final SpiTransaction transaction; + + private final List deleteBeans = new ArrayList<>(); + + private boolean clientGeneratedIds; + + MergeContext(SpiEbeanServer server, SpiTransaction transaction, boolean clientGeneratedIds) { + this.server = server; + this.transaction = transaction; + this.clientGeneratedIds = clientGeneratedIds; + } + + /** + * Add to the list of beans to delete. + */ + void addDelete(EntityBean deleteBean) { + deleteBeans.add(deleteBean); + } + + /** + * Return true if Ids must be checked against the DB. + */ + boolean isClientGeneratedIds() { + return clientGeneratedIds; + } + + /** + * Check if the Id / bean exists in the database. + */ + boolean idExists(Class beanType, Object beanId) { + return server.exists(beanType, beanId, transaction); + } + + /** + * Return the list of beans to delete. + */ + List getDeletedBeans() { + return deleteBeans; + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeHandler.java b/src/main/java/io/ebeaninternal/server/persist/MergeHandler.java new file mode 100644 index 000000000..c82febba7 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeHandler.java @@ -0,0 +1,147 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.CacheMode; +import io.ebean.MergeOptions; +import io.ebean.PersistenceContextScope; +import io.ebean.Query; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssoc; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; + +import javax.persistence.PersistenceException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Drives the merge processing. + */ +class MergeHandler { + + private final Pattern PATH_SPLIT = Pattern.compile("\\."); + + private final SpiEbeanServer server; + private final BeanDescriptor desc; + private final EntityBean bean; + private final MergeOptions options; + private final SpiTransaction transaction; + + private final Map nodes = new LinkedHashMap<>(); + + + MergeHandler(SpiEbeanServer server, BeanDescriptor desc, EntityBean bean, MergeOptions options, SpiTransaction transaction) { + this.server = server; + this.desc = desc; + this.bean = bean; + this.options = options; + this.transaction = transaction; + } + + /** + * Fetch the Ids for the graph and use them to determine inserts, updates and deletes for the merge paths. + */ + List merge() { + + Set paths = options.paths(); + if (paths.isEmpty() && !options.isClientGeneratedIds()) { + // just do a single insert or update based on Id value present + Object id = desc.getId(bean); + if (id != null) { + bean._ebean_getIntercept().setForceUpdate(true); + } + return Collections.emptyList(); + } + + EntityBean outline = fetchOutline(paths); + if (outline == null) { + // considered an insert ... + return Collections.emptyList(); + } + + // the top level bean is an update + bean._ebean_getIntercept().setForceUpdate(true); + + // detect what beans are updates and recursively set forceUpdate as needed + // and outline beans not in the merge graph are generally considered as deletes + MergeContext context = new MergeContext(server, transaction, options.isClientGeneratedIds()); + MergeRequest request = new MergeRequest(context, bean, outline); + for (MergeNode value : nodes.values()) { + value.merge(request); + } + + return context.getDeletedBeans(); + } + + /** + * Fetch the outline bean with associated one and associated many beans loaded with Id values only. + *

    + * We use the Id values to determine what are inserts, updates and deletes as part of the merge. + */ + private EntityBean fetchOutline(Set paths) { + + Query query = server.find(desc.getBeanType()); + + query.setBeanCacheMode(CacheMode.OFF); + query.setPersistenceContextScope(PersistenceContextScope.QUERY); + query.setId(desc.getId(bean)); + query.select(desc.getIdProperty().getName()); + + for (String path : paths) { + MergeNode node = buildNode(path); + node.addSelectId(query); + } + return (EntityBean) server.findOne(query, transaction); + } + + private MergeNode buildNode(String path) { + String[] split = PATH_SPLIT.split(path); + if (split.length == 1) { + return addRootLevelNode(split[0]); + } else { + return addSubNode(path, split); + } + } + + private MergeNode addSubNode(String fullPath, String[] split) { + MergeNode parent = nodes.get(split[0]); + if (parent == null) { + throw new PersistenceException("Unable to find parent path " + split[0] + " in merge paths?"); + } + + for (int i = 1; i < split.length - 1; i++) { + parent = parent.get(split[i]); + if (parent == null) { + throw new PersistenceException("Unable to find parent path " + split[0] + " in merge paths?"); + } + } + return parent.addChild(fullPath, split[split.length - 1]); + } + + private MergeNode addRootLevelNode(String rootPath) { + + MergeNode node = createMergeNode(rootPath, desc, rootPath); + nodes.put(rootPath, node); + return node; + } + + static MergeNode createMergeNode(String fullPath, BeanDescriptor targetDesc, String path) { + + BeanProperty prop = targetDesc.getBeanProperty(path); + if (prop == null || !(prop instanceof BeanPropertyAssoc)) { + throw new PersistenceException("merge path [" + path + "] is not a ToMany or ToOne property of " + targetDesc.getFullName()); + } + if (prop instanceof BeanPropertyAssocMany) { + return new MergeNodeAssocMany(fullPath, (BeanPropertyAssocMany) prop); + } else { + return new MergeNodeAssocOne(fullPath, (BeanPropertyAssocOne) prop); + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeNode.java b/src/main/java/io/ebeaninternal/server/persist/MergeNode.java new file mode 100644 index 000000000..0f7e47a48 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeNode.java @@ -0,0 +1,74 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.Query; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssoc; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Base class for merge nodes. + */ +abstract class MergeNode { + + protected final String fullPath; + protected final BeanDescriptor targetDescriptor; + protected Map children; + + MergeNode(String fullPath, BeanPropertyAssoc property) { + this.fullPath = fullPath; + this.targetDescriptor = property.getTargetDescriptor(); + } + + /** + * Perform the merge processing. + */ + abstract void merge(MergeRequest request); + + /** + * Add a child node given the fullPath and relative path. + */ + MergeNode addChild(String fullPath, String path) { + MergeNode childNode = MergeHandler.createMergeNode(fullPath, targetDescriptor, path); + if (children == null) { + children = new LinkedHashMap<>(); + } + children.put(path, childNode); + return childNode; + } + + /** + * Return the node given the relative path. + */ + MergeNode get(String path) { + if (children != null) { + return children.get(path); + } + return null; + } + + /** + * Add to the query to fetch the Ids values for the foreign keys basically. + */ + void addSelectId(Query query) { + + BeanProperty idProperty = targetDescriptor.getIdProperty(); + query.fetch(fullPath, idProperty.getName()); + } + + /** + * Cascade the merge processing if this has child nodes. + */ + protected void cascade(EntityBean entityBean, EntityBean outlineBean, MergeRequest request) { + + if (children != null && !children.isEmpty()) { + MergeRequest sub = request.sub(entityBean, outlineBean); + for (MergeNode node : children.values()) { + node.merge(sub); + } + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocMany.java b/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocMany.java new file mode 100644 index 000000000..d6e1a8e8f --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocMany.java @@ -0,0 +1,57 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Node for processing merge on ToMany properties. + */ +class MergeNodeAssocMany extends MergeNode { + + private final BeanPropertyAssocMany many; + + MergeNodeAssocMany(String fullPath, BeanPropertyAssocMany property) { + super(fullPath, property); + this.many = property; + } + + public void merge(MergeRequest request) { + + Collection beans = many.getRawCollection(request.getBean()); + Collection outlines = many.getRawCollection(request.getOutline()); + + Map outlineIds = new HashMap<>(); + if (outlines != null) { + for (Object outline : outlines) { + EntityBean outlineBean = (EntityBean) outline; + Object outlineId = targetDescriptor.getId(outlineBean); + outlineIds.put(outlineId, outlineBean); + } + } + + if (beans != null) { + for (Object bean : beans) { + EntityBean entityBean = (EntityBean) bean; + Object beanId = targetDescriptor.getId(entityBean); + if (beanId != null) { + EntityBean outlineBean = outlineIds.remove(beanId); + if (outlineBean != null) { + // must be an update + entityBean._ebean_getIntercept().setForceUpdate(true); + cascade(entityBean, outlineBean, request); + } + } + } + } + + // any remaining are considered deletes + for (EntityBean outlineBean : outlineIds.values()) { + request.addDelete(outlineBean); + } + } + +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocOne.java b/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocOne.java new file mode 100644 index 000000000..b33c393c5 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeNodeAssocOne.java @@ -0,0 +1,60 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; + +import java.util.Objects; + +/** + * Node for processing merge on ToOne properties. + */ +class MergeNodeAssocOne extends MergeNode { + + private final BeanPropertyAssocOne one; + + MergeNodeAssocOne(String fullPath, BeanPropertyAssocOne property) { + super(fullPath, property); + this.one = property; + } + + public void merge(MergeRequest request) { + + EntityBean entityBean = getEntityBean(request.getBean()); + if (entityBean == null) { + checkOrphanRemoval(request); + + } else { + Object beanId = targetDescriptor.getId(entityBean); + if (beanId == null) { + checkOrphanRemoval(request); + + } else { + EntityBean outlineBean = getEntityBean(request.getOutline()); + Object outlineId = (outlineBean == null) ? null : targetDescriptor.getId(outlineBean); + if (isUpdate(beanId, outlineId, request)) { + entityBean._ebean_getIntercept().setForceUpdate(true); + cascade(entityBean, outlineBean, request); + } + } + } + } + + private void checkOrphanRemoval(MergeRequest request) { + if (one.isOrphanRemoval()) { + EntityBean outlineBean = getEntityBean(request.getOutline()); + if (outlineBean != null) { + request.addDelete(outlineBean); + } + } + } + + private boolean isUpdate(Object beanId, Object outlineId, MergeRequest request) { + return Objects.equals(beanId, outlineId) + || !request.isClientGeneratedIds() + || request.idExists(targetDescriptor.getBeanType(), beanId); + } + + private EntityBean getEntityBean(Object bean) { + return (EntityBean) one.getVal(bean); + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/MergeRequest.java b/src/main/java/io/ebeaninternal/server/persist/MergeRequest.java new file mode 100644 index 000000000..303ccb382 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/MergeRequest.java @@ -0,0 +1,64 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.EntityBean; + +/** + * Request object used for processing the merge. + */ +class MergeRequest { + + private final EntityBean bean; + private final EntityBean outline; + + private final MergeContext context; + + MergeRequest(MergeContext context, EntityBean bean, EntityBean outline) { + this.context = context; + this.bean = bean; + this.outline = outline; + } + + /** + * Create a sub request with the given beans (to cascade the processing). + */ + public MergeRequest sub(EntityBean entityBean, EntityBean outlineBean) { + return new MergeRequest(context, entityBean, outlineBean); + } + + /** + * Return the entity bean being merged. + */ + public EntityBean getBean() { + return bean; + } + + /** + * Return the outline bean (only has Id property). + */ + public EntityBean getOutline() { + return outline; + } + + /** + * Add a bean to the deletion list. + */ + public void addDelete(EntityBean deleteRemain) { + context.addDelete(deleteRemain); + } + + /** + * Return true if the Ids are generated by the client. This means we can't know if a bean + * should be inserted or updated based on having an Id value. + */ + public boolean isClientGeneratedIds() { + return context.isClientGeneratedIds(); + } + + /** + * Return true if a bean of the type with the given Id exists in the database. + */ + public boolean idExists(Class beanType, Object beanId) { + return context.idExists(beanType, beanId); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java index 4556edcd2..97f9d1131 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java @@ -21,6 +21,7 @@ import java.util.Map; */ class SaveManyPropRequest { + private final PersistRequestBean request; private final boolean insertedParent; private final BeanPropertyAssocMany many; private final EntityBean parentBean; @@ -37,10 +38,10 @@ class SaveManyPropRequest { private Collection collection; private DefaultPersister persister; private boolean deleteMissing; - private boolean insertMode; private int sortOrder; SaveManyPropRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + this.request = request; this.insertedParent = insertedParent; this.many = many; this.cascade = many.getCascadeInfo().isSave(); @@ -70,6 +71,10 @@ class SaveManyPropRequest { return deleteMissingChildren; } + public int getFlags() { + return request.getFlags(); + } + boolean isInsertedParent() { return insertedParent; } @@ -108,11 +113,10 @@ class SaveManyPropRequest { } } - void saveDetails(DefaultPersister persister, boolean deleteMissing, boolean insertMode) { + void saveDetails(DefaultPersister persister, boolean deleteMissing) { this.persister = persister; this.deleteMissing = deleteMissing; - this.insertMode = insertMode; // check that the list is not null and if it is a BeanCollection // check that is has been populated (don't trigger lazy loading) @@ -198,7 +202,7 @@ class SaveManyPropRequest { } if (!skipSavingThisBean) { - persister.saveRecurse(detail, transaction, parentBean, insertMode, publish); + persister.saveRecurse(detail, transaction, parentBean, request.getFlags()); } } } diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index 62265c0fb..5755f6ed5 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -11,6 +11,7 @@ import io.ebean.Filter; import io.ebean.FutureIds; import io.ebean.FutureList; import io.ebean.FutureRowCount; +import io.ebean.MergeOptions; import io.ebean.PagedList; import io.ebean.PersistenceContextScope; import io.ebean.Query; @@ -236,6 +237,16 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return 0; } + @Override + public void merge(Object bean, MergeOptions options) { + + } + + @Override + public void merge(Object bean, MergeOptions options, Transaction transaction) { + + } + @Override public List> findVersions(Query query, Transaction transaction) { return null; @@ -551,6 +562,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { } + @Override + public boolean exists(Class beanType, Object beanId, Transaction transaction) { + return false; + } + @Override public T find(Class beanType, Object uid) { return null; diff --git a/src/test/java/io/ebeaninternal/server/persist/BatchedBeanHolderTest.java b/src/test/java/io/ebeaninternal/server/persist/BatchedBeanHolderTest.java index 2e200abd1..12a7acef0 100644 --- a/src/test/java/io/ebeaninternal/server/persist/BatchedBeanHolderTest.java +++ b/src/test/java/io/ebeaninternal/server/persist/BatchedBeanHolderTest.java @@ -6,8 +6,8 @@ import io.ebeaninternal.server.core.PersistRequest; import io.ebeaninternal.server.core.PersistRequestBean; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanManager; -import org.tests.model.basic.Customer; import org.junit.Test; +import org.tests.model.basic.Customer; import java.sql.Timestamp; @@ -17,8 +17,7 @@ public class BatchedBeanHolderTest extends BaseTestCase { @SuppressWarnings({ "rawtypes", "unchecked" }) @Test - public void testAppend() throws Exception { - + public void testAppend() { TDSpiEbeanServer server = new TDSpiEbeanServer("foo"); @@ -32,13 +31,13 @@ public class BatchedBeanHolderTest extends BaseTestCase { Customer customer = new Customer(); customer.setUpdtime(new Timestamp(System.currentTimeMillis())); - PersistRequestBean req1 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, false, false); + PersistRequestBean req1 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, 0); int size = holder.append(req1); assertEquals(1, size); - PersistRequestBean req2 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, false, false); + PersistRequestBean req2 = new PersistRequestBean(server, customer, null, beanManager, null, null, PersistRequest.Type.INSERT, 0); size = holder.append(req2); assertEquals(0, size); diff --git a/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java b/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java new file mode 100644 index 000000000..4e4d947c4 --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java @@ -0,0 +1,44 @@ +package io.ebeaninternal.server.persist; + + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class FlagsTest { + + + @Test + public void test() { + + int state = 0; + + state = Flags.setPublish(state); + assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue(); + + state = Flags.setMerge(state); + state = Flags.setInsert(state); + assertThat(Flags.isSet(state, Flags.PUBLISH)).isTrue(); + assertThat(Flags.isSet(state, Flags.MERGE)).isTrue(); + assertThat(Flags.isSet(state, Flags.INSERT)).isTrue(); + + state = Flags.unsetPublish(state); + assertThat(Flags.isSet(state, Flags.PUBLISH)).isFalse(); + assertThat(Flags.isSet(state, Flags.MERGE)).isTrue(); + assertThat(Flags.isSet(state, Flags.INSERT)).isTrue(); + + } + + @Test + public void isPublishOrMerge() { + + assertThat(Flags.isPublishOrMerge(0)).isFalse(); + assertThat(Flags.isPublishOrMerge(Flags.INSERT)).isFalse(); + + assertThat(Flags.isPublishOrMerge(Flags.PUBLISH)).isTrue(); + assertThat(Flags.isPublishOrMerge(Flags.MERGE)).isTrue(); + + int mergePublish = Flags.setMerge(Flags.setPublish(0)); + assertThat(Flags.isPublishOrMerge(mergePublish)).isTrue(); + } +} diff --git a/src/test/java/org/tests/merge/MAddress.java b/src/test/java/org/tests/merge/MAddress.java new file mode 100644 index 000000000..cfeb31bb6 --- /dev/null +++ b/src/test/java/org/tests/merge/MAddress.java @@ -0,0 +1,33 @@ +package org.tests.merge; + +import javax.persistence.Entity; + +@Entity +public class MAddress extends MBase { + + private String street; + + private String city; + + public MAddress(String street, String city) { + this.street = street; + this.city = city; + } + + public String getStreet() { + return street; + } + + public void setStreet(String street) { + this.street = street; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + +} diff --git a/src/test/java/org/tests/merge/MBase.java b/src/test/java/org/tests/merge/MBase.java new file mode 100644 index 000000000..0172e9893 --- /dev/null +++ b/src/test/java/org/tests/merge/MBase.java @@ -0,0 +1,32 @@ +package org.tests.merge; + +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.Version; +import java.util.UUID; + +@MappedSuperclass +public class MBase { + + @Id + private UUID id; + + @Version + private long version; + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/merge/MContact.java b/src/test/java/org/tests/merge/MContact.java new file mode 100644 index 000000000..9331bbb43 --- /dev/null +++ b/src/test/java/org/tests/merge/MContact.java @@ -0,0 +1,67 @@ +package org.tests.merge; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import java.util.List; + +@Entity +public class MContact extends MBase { + + String email; + String firstName; + String lastName; + + @ManyToOne + MCustomer customer; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact") + List messages; + + public MContact(String email, String firstName, String lastName) { + this.email = email; + this.firstName = firstName; + this.lastName = lastName; + } + + public MCustomer getCustomer() { + return customer; + } + + public void setCustomer(MCustomer customer) { + this.customer = customer; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public List getMessages() { + return messages; + } + + public void setMessages(List messages) { + this.messages = messages; + } +} diff --git a/src/test/java/org/tests/merge/MContactMessage.java b/src/test/java/org/tests/merge/MContactMessage.java new file mode 100644 index 000000000..95d22026f --- /dev/null +++ b/src/test/java/org/tests/merge/MContactMessage.java @@ -0,0 +1,54 @@ +package org.tests.merge; + +import javax.persistence.Entity; +import javax.persistence.ManyToOne; + +@Entity +public class MContactMessage extends MBase { + + private String title; + + private String subject; + + private String notes; + + @ManyToOne(optional = false) + private MContact contact; + + public MContactMessage(String title, String subject) { + this.title = title; + this.subject = subject; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public MContact getContact() { + return contact; + } + + public void setContact(MContact contact) { + this.contact = contact; + } +} diff --git a/src/test/java/org/tests/merge/MCustomer.java b/src/test/java/org/tests/merge/MCustomer.java new file mode 100644 index 000000000..802f8000b --- /dev/null +++ b/src/test/java/org/tests/merge/MCustomer.java @@ -0,0 +1,68 @@ +package org.tests.merge; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import java.util.List; + +@Entity +public class MCustomer extends MBase { + + private String name; + + private String notes; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer") + private List contacts; + + @ManyToOne(cascade = CascadeType.ALL) + private MAddress shippingAddress; + + @ManyToOne(cascade = CascadeType.ALL) + private MAddress billingAddress; + + public MCustomer(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + + public List getContacts() { + return contacts; + } + + public void setContacts(List contacts) { + this.contacts = contacts; + } + + public MAddress getShippingAddress() { + return shippingAddress; + } + + public void setShippingAddress(MAddress shippingAddress) { + this.shippingAddress = shippingAddress; + } + + public MAddress getBillingAddress() { + return billingAddress; + } + + public void setBillingAddress(MAddress billingAddress) { + this.billingAddress = billingAddress; + } +} diff --git a/src/test/java/org/tests/merge/TestMergeBasic.java b/src/test/java/org/tests/merge/TestMergeBasic.java new file mode 100644 index 000000000..03938fa71 --- /dev/null +++ b/src/test/java/org/tests/merge/TestMergeBasic.java @@ -0,0 +1,117 @@ +package org.tests.merge; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.MergeOptions; +import io.ebean.MergeOptionsBuilder; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; +import org.tests.model.basic.UUOne; +import org.tests.model.basic.UUTwo; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestMergeBasic extends BaseTestCase { + + + private UUOne rebuildViaJson(UUOne input) { + String asJson = Ebean.json().toJson(input); + return Ebean.json().toBean(UUOne.class, asJson); + } + + private UUOne build() { + UUOne uuOne = buildGraph(); + Ebean.save(uuOne); + return rebuildViaJson(uuOne); + } + + @Test + public void with_setClientGeneratedIds_expect_noDifferenceWithToMany() { + + UUOne one = build(); + + one.setDescription("mod"); + List comments = one.getComments(); + comments.remove(0); + comments.add(0, new UUTwo("twoMore", UUID.randomUUID())); + comments.add(new UUTwo("twoExtra", UUID.randomUUID())); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("comments") + .setClientGeneratedIds() + .build(); + + LoggedSqlCollector.start(); + Ebean.merge(one, options); + + + List sql = LoggedSqlCollector.stop(); + // fetch the Ids ... used to identity inserts, updates and deletes + assertThat(sql.get(0)).contains("select t0.id, t1.id from uuone t0 left join uutwo t1 on t1.master_id = t0.id where t0.id = ?"); + + // deletes of Ids that are no longer in the graph + assertThat(sql.get(1)).contains("delete from uutwo where id=?"); + + // cascade persist ... master + assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?"); + + // persist children ... + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + } + + @Test + public void test() { + + UUOne one = build(); + one.setDescription("mod"); + + List comments = one.getComments(); + comments.remove(0); + comments.add(0, new UUTwo("twoMore", UUID.randomUUID())); + comments.add(new UUTwo("twoExtra", UUID.randomUUID())); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("comments") + .build(); + + LoggedSqlCollector.start(); + Ebean.merge(one, options); + + + List sql = LoggedSqlCollector.stop(); + // fetch the Ids ... used to identity inserts, updates and deletes + assertThat(sql.get(0)).contains("select t0.id, t1.id from uuone t0 left join uutwo t1 on t1.master_id = t0.id where t0.id = ?"); + + // deletes of Ids that are no longer in the graph + assertThat(sql.get(1)).contains("delete from uutwo where id=?"); + + // cascade persist ... master + assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?"); + + // persist children ... + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + + } + + private UUOne buildGraph() { + UUOne one = new UUOne("one1", UUID.randomUUID()); + for (int i = 1; i < 5; i++) { + UUTwo two = new UUTwo("two" + i, UUID.randomUUID()); + one.getComments().add(two); + } + return one; + } +} diff --git a/src/test/java/org/tests/merge/TestMergeCustomer.java b/src/test/java/org/tests/merge/TestMergeCustomer.java new file mode 100644 index 000000000..8f314cac5 --- /dev/null +++ b/src/test/java/org/tests/merge/TestMergeCustomer.java @@ -0,0 +1,376 @@ +package org.tests.merge; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.FetchPath; +import io.ebean.MergeOptions; +import io.ebean.MergeOptionsBuilder; +import io.ebean.text.PathProperties; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestMergeCustomer extends BaseTestCase { + + private Random random = new Random(); + + /** + * So this is effectively the same as a stateless update. + */ + @Test + public void customerOnly_expect_updateOnly() { + + + MCustomer mCustomer = partial("cust1", "(id,name,version)"); + mCustomer.setName("NotCust1"); + + MergeOptions options = new MergeOptionsBuilder().build(); + + + LoggedSqlCollector.start(); + + Ebean.merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update mcustomer set name=?, version=? where id=? and version=?"); + } + + @Test + public void customerOnly_setClientGeneratedIds_expect_selectAndUpdate() { + + + MCustomer mCustomer = partial("cust2", "(id,name,version)"); + mCustomer.setName("NotCust2"); + + MergeOptions options = new MergeOptionsBuilder().setClientGeneratedIds().build(); + + LoggedSqlCollector.start(); + + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("select t0.id from mcustomer t0 where t0.id = ?"); + assertThat(sql.get(1)).contains("update mcustomer set name=?, version=? where id=? and version=?"); + } + + @Test + public void customerWithAddresses_setClientGeneratedIds_expect_selectAndUpdate() { + + + MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))"); + mCustomer.setName("NotCust3"); + mCustomer.getBillingAddress().setStreet("modBillStreet"); + mCustomer.getShippingAddress().setCity("modShipCity"); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("shippingAddress") + .addPath("billingAddress") + .setClientGeneratedIds() + .build(); + + LoggedSqlCollector.start(); + + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(4); + assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?"); + assertThat(sql.get(1)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); + assertThat(sql.get(2)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); + assertThat(sql.get(3)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + } + + @Test + public void customerWithAddresses_newAddress_setClientGeneratedIds_expect_insertAddress() { + + + MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))"); + mCustomer.setName("NotCust3"); + + // new billing address - no Id value so must be insert + mCustomer.setBillingAddress(new MAddress("Short", "Mid Wicket")); + mCustomer.getShippingAddress().setCity("modShipCity"); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("shippingAddress") + .addPath("billingAddress") + .setClientGeneratedIds() + .build(); + + LoggedSqlCollector.start(); + + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(4); + assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?"); + assertThat(sql.get(1)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); + assertThat(sql.get(2)).contains("insert into maddress (id, street, city, version) values (?,?,?,?);"); + assertThat(sql.get(3)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + } + + @Test + public void customerWithAddresses_newAddressWithId_setClientGeneratedIds_expect_additionalCheckForAddressInsert() { + + + MCustomer mCustomer = partial("cust3", "(id,name,version,shippingAddress(*),billingAddress(*))"); + mCustomer.setName("NotCust3"); + + // new billing address - has Id value + setClientGeneratedIds ... so extra query to check + MAddress mAddress = new MAddress("Short", "Mid Wicket"); + mAddress.setId(UUID.randomUUID()); + mCustomer.setBillingAddress(mAddress); + mCustomer.getShippingAddress().setCity("modShipCity"); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("shippingAddress") + .addPath("billingAddress") + .setClientGeneratedIds() // As we are using clientIds ... we don't know if the new UUID is an insert or update without checking + .build(); + + LoggedSqlCollector.start(); + + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("select t0.id, t2.id, t1.id from mcustomer t0 left join maddress t2 on t2.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id where t0.id = ?"); + + // Additional check to see if the address with the unknown UUID is 'insert' or 'update' + assertThat(sql.get(1)).contains("select t0.id from maddress t0 where t0.id = ?"); + + assertThat(sql.get(2)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); + assertThat(sql.get(3)).contains("insert into maddress (id, street, city, version) values (?,?,?,?);"); + assertThat(sql.get(4)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + } + + @Test + public void assocOne_onlineIsNull() { + + MCustomer c = new MCustomer("Null Address"); + c.setBillingAddress(new MAddress("Cow corner", "Mid Wicket")); + + Ebean.save(c); + + MCustomer mCustomer = rebuildViaJson(c); + + MAddress mAddress = new MAddress("Silly", "Mid Wicket"); + mAddress.setId(UUID.randomUUID()); + mCustomer.setShippingAddress(mAddress); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("shippingAddress") + .addPath("billingAddress") + .setClientGeneratedIds() + .build(); + + Ebean.merge(mCustomer, options); + + } + + private MCustomer rebuildViaJson(MCustomer input) { + String asJson = Ebean.json().toJson(input); + return Ebean.json().toBean(MCustomer.class, asJson); + } + + @Test + public void whenContacts_isNull_expect_deleteContacts() { + + MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))"); + + // null contacts ... but in path so this means - delete all contacts + mCustomer.setContacts(null); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("contacts") + .build(); + + LoggedSqlCollector.start(); + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?"); + assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?"); + assertThat(sql.get(2)).contains("delete from mcontact where id=?"); + + assertThat(sql.get(13)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + } + + + @Test + public void whenContacts_isEmpty_expect_deleteContacts() { + + MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))"); + + // empty contacts ... but in path so this means - delete all contacts + mCustomer.setContacts(new ArrayList<>()); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("contacts") + .build(); + + LoggedSqlCollector.start(); + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?"); + assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?"); + assertThat(sql.get(2)).contains("delete from mcontact where id=?"); + + assertThat(sql.get(13)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + } + + @Test + public void whenContacts_mixed_expect_deleteInsertUpdateContacts() { + + MCustomer mCustomer = partial("cust6", "(id,name,version,shippingAddress(id),billingAddress(id),contacts(*))"); + List contacts = mCustomer.getContacts(); + + MContact mContact = new MContact("z@a.com", "z", "zed"); + mContact.setId(UUID.randomUUID()); + + contacts.add(mContact); + + contacts.get(0).setEmail("a@beta.com"); + contacts.get(1).setEmail("b@beta.com"); + contacts.remove(4); + contacts.remove(2); + + MContact mContactEnd = new MContact("z@z.com", "zx", "zedXtra"); + mContactEnd.setId(UUID.randomUUID()); + contacts.add(mContactEnd); + + + MergeOptions options = new MergeOptionsBuilder() + .addPath("contacts") + .build(); + + LoggedSqlCollector.start(); + server().merge(mCustomer, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t1.id from mcustomer t0 left join mcontact t1 on t1.customer_id = t0.id where t0.id = ?"); + assertThat(sql.get(1)).contains("delete from mcontact_message where contact_id = ?"); + assertThat(sql.get(2)).contains("delete from mcontact where id=?"); + + assertThat(sql.get(5)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("insert into mcontact"); + assertThat(sql.get(7)).contains("insert into mcontact"); + assertThat(sql.get(8)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + assertThat(sql.get(11)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + } + + @Test + public void fullMonty() { + + MCustomer cust1 = customer("monty1"); + + modify(cust1); + + MergeOptions options = new MergeOptionsBuilder() + .addPath("billingAddress") + .addPath("shippingAddress") + .addPath("contacts") + .addPath("contacts.messages") + .setClientGeneratedIds() + .setDeletePermanent() + .build(); + + + LoggedSqlCollector.start(); + server().merge(cust1, options); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select t0.id, t3.id, t1.id, t2.id from mcustomer t0 left join maddress t3 on t3.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id left join mcontact t2 on t2.customer_id = t0.id where t0.id = ?"); + if (isH2()) { + // with nested OneToMany .. we need a second query to read the contact message ids + assertThat(sql.get(1)).contains("select t0.contact_id, t0.id from mcontact_message t0 where (t0.contact_id) in (?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"); + } + assertThat(sql.get(2)).contains("delete from mcontact_message where contact_id = ?"); + assertThat(sql.get(3)).contains("delete from mcontact where id=?"); + assertThat(sql.get(4)).contains("delete from mcontact_message where contact_id = ?"); + assertThat(sql.get(5)).contains("delete from mcontact where id=?"); + + assertThat(sql.get(6)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update mcustomer set name=?, notes=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); + + assertThat(sql.get(8)).contains("insert into mcontact"); + assertThat(sql.get(9)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + + assertThat(sql.get(13)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?"); + + } + + private void modify(MCustomer cust) { + + List contacts = cust.getContacts(); + MContact mContact = new MContact("z@a.com", "z", "zed"); + mContact.setId(UUID.randomUUID()); + + contacts.add(mContact); + + contacts.get(0).setEmail("a@beta.com"); + contacts.get(1).setEmail("b@beta.com"); + contacts.remove(4); + contacts.remove(2); + + cust.setName(cust.getName()+" modified"); + cust.getBillingAddress().setStreet("Short"); + + MAddress mAddress = new MAddress("Broken", "Dreams"); + mAddress.setId(UUID.randomUUID()); + cust.setShippingAddress(null); + } + + private MCustomer partial(String name, String fetchGraph) { + MCustomer cust1 = buildCustomer(name); + Ebean.save(cust1); + + FetchPath fetchPath = PathProperties.parse(fetchGraph); + String asJson = Ebean.json().toJson(cust1, fetchPath); + return Ebean.json().toBean(MCustomer.class, asJson); + } + + private MCustomer customer(String name) { + + MCustomer cust1 = buildCustomer(name); + Ebean.save(cust1); + + String asJson = Ebean.json().toJson(cust1); + + return Ebean.json().toBean(MCustomer.class, asJson); + } + + private MCustomer buildCustomer(String name) { + + MCustomer c = new MCustomer(name); + c.setShippingAddress(new MAddress("Fleet st", "London")); + c.setBillingAddress(new MAddress("Cow corner", "Mid Wicket")); + + c.getContacts().add(addContact("a@a.com", "a", "alligator")); + c.getContacts().add(addContact("b@a.com", "b", "beaver")); + c.getContacts().add(addContact("c@a.com", "c", "crow")); + c.getContacts().add(addContact("d@a.com", "d", "dog")); + c.getContacts().add(addContact("e@a.com", "e", "ent")); + c.getContacts().add(addContact("f@a.com", "f", "frog")); + + return c; + } + + private MContact addContact(String email, String first, String last) { + MContact mContact = new MContact(email, first, last); + int i = random.nextInt(2); + for (int j = 0; j < i; j++) { + mContact.getMessages().add(new MContactMessage(first+" "+i, last+" "+i)); + } + return mContact; + } +} diff --git a/src/test/java/org/tests/model/basic/UUOne.java b/src/test/java/org/tests/model/basic/UUOne.java index 8efe6da67..53c88446a 100644 --- a/src/test/java/org/tests/model/basic/UUOne.java +++ b/src/test/java/org/tests/model/basic/UUOne.java @@ -6,6 +6,7 @@ import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToMany; +import javax.persistence.Version; import java.util.List; import java.util.UUID; @@ -18,10 +19,22 @@ public class UUOne { String name; + String description; @OneToMany(cascade = CascadeType.ALL, mappedBy = "master") List comments; + @Version + long version; + + public UUOne() { + } + + public UUOne(String name, UUID id) { + this.name = name; + this.id = id; + } + public UUID getId() { return id; } @@ -38,6 +51,14 @@ public class UUOne { this.name = name; } + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + public List getComments() { return comments; } @@ -46,4 +67,11 @@ public class UUOne { this.comments = comments; } + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } } diff --git a/src/test/java/org/tests/model/basic/UUTwo.java b/src/test/java/org/tests/model/basic/UUTwo.java index cea9a9efd..f446fe397 100644 --- a/src/test/java/org/tests/model/basic/UUTwo.java +++ b/src/test/java/org/tests/model/basic/UUTwo.java @@ -4,6 +4,7 @@ import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; +import javax.persistence.Version; import java.util.UUID; @Entity @@ -14,9 +15,22 @@ public class UUTwo { String name; + String notes; + @ManyToOne(cascade = CascadeType.PERSIST) UUOne master; + @Version + long version; + + public UUTwo() { + } + + public UUTwo(String name, UUID id) { + this.name = name; + this.id = id; + } + public UUID getId() { return id; } @@ -33,6 +47,14 @@ public class UUTwo { this.name = name; } + public String getNotes() { + return notes; + } + + public void setNotes(String notes) { + this.notes = notes; + } + public UUOne getMaster() { return master; } @@ -41,4 +63,11 @@ public class UUTwo { this.master = master; } + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } } diff --git a/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java b/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java index 1cdd79c0d..cb7c6522d 100644 --- a/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java +++ b/src/test/java/org/tests/query/joins/TestDisjunctWhereOuterOnMany.java @@ -3,10 +3,10 @@ package org.tests.query.joins; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; -import org.tests.model.basic.UUOne; -import org.tests.model.basic.UUTwo; import org.junit.Assert; import org.junit.Test; +import org.tests.model.basic.UUOne; +import org.tests.model.basic.UUTwo; import java.util.List; @@ -58,11 +58,11 @@ public class TestDisjunctWhereOuterOnMany extends BaseTestCase { Assert.assertEquals(2, rowCount); if (isPostgres()) { - String expectedSql = "select distinct on (t0.id) t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; + String expectedSql = "select distinct on (t0.id) t0.id, t0.name, t0.description, t0.version from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; assertThat(sqlOf(query, 1)).contains(expectedSql); } else { - String expectedSql = "select distinct t0.id, t0.name from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; + String expectedSql = "select distinct t0.id, t0.name, t0.description, t0.version from uuone t0 left join uutwo u1 on u1.master_id = t0.id where (t0.name = ? or u1.name = ? ) "; assertThat(sqlOf(query, 1)).contains(expectedSql); } From 674617eb9e882dd0ec34bedbdd367d3180df84fa Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Mar 2018 00:02:58 +1300 Subject: [PATCH 0184/1036] [maven-release-plugin] prepare release ebean-11.15.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bfc7d5897..d2be4b31a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.1-SNAPSHOT + 11.15.1 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.15.1 From 4bc1f2ede4ecd4e9b8d440f21535085479ec49e7 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Mar 2018 00:03:11 +1300 Subject: [PATCH 0185/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d2be4b31a..37d6b08ad 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.1 + 11.15.2-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.15.1 + HEAD From 602a35d0b67975f9cef91ffe9f921e7d89d86c84 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 14 Mar 2018 16:23:16 +1300 Subject: [PATCH 0186/1036] #1348 - ENH: Add support for bitwiseAnd / bitwiseAny / bitwiseAll .. expressions for use with integer/long "Flags" properties --- pom.xml | 2 +- src/main/java/io/ebean/ExpressionFactory.java | 24 +++ src/main/java/io/ebean/ExpressionList.java | 55 ++++++- .../api/SpiExpressionRequest.java | 2 +- .../server/core/BaseDbExpression.java | 19 --- .../server/core/InternalConfiguration.java | 15 +- .../server/expression/BitwiseExpression.java | 63 ++++++++ .../server/expression/BitwiseOp.java | 22 +++ .../expression/DefaultExpressionFactory.java | 15 ++ .../expression/DefaultExpressionList.java | 18 +++ .../expression/DefaultExpressionRequest.java | 2 +- .../server/expression/JunctionExpression.java | 15 ++ .../expression/platform/BaseDbExpression.java | 60 ++++++++ .../platform}/BasicDbExpression.java | 2 +- .../platform}/DbExpressionHandler.java | 7 +- .../platform/DbExpressionHandlerFactory.java | 31 ++++ .../expression/platform/H2DbExpression.java | 20 +++ .../platform/MySqlDbExpression.java | 12 ++ .../platform}/OracleDbExpression.java | 10 +- .../platform}/PostgresCast.java | 2 +- .../platform}/PostgresDbExpression.java | 2 +- .../platform}/SqlServerDbExpression.java | 2 +- .../ebeaninternal/server/persist/Binder.java | 2 +- .../expression/TDSpiExpressionRequest.java | 2 +- .../platform}/PostgresCastTest.java | 6 +- .../org/tests/expression/bitwise/BwBean.java | 70 +++++++++ .../org/tests/expression/bitwise/BwFlags.java | 78 ++++++++++ .../bitwise/TestBitwiseExpressions.java | 141 ++++++++++++++++++ .../tests/repository/CustomerRepository.java | 5 +- 29 files changed, 652 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/BasicDbExpression.java (94%) rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/DbExpressionHandler.java (73%) create mode 100644 src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/OracleDbExpression.java (75%) rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/PostgresCast.java (95%) rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/PostgresDbExpression.java (97%) rename src/main/java/io/ebeaninternal/server/{core => expression/platform}/SqlServerDbExpression.java (95%) rename src/test/java/io/ebeaninternal/server/{core => expression/platform}/PostgresCastTest.java (84%) create mode 100644 src/test/java/org/tests/expression/bitwise/BwBean.java create mode 100644 src/test/java/org/tests/expression/bitwise/BwFlags.java create mode 100644 src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java diff --git a/pom.xml b/pom.xml index 37d6b08ad..85d2ecd68 100644 --- a/pom.xml +++ b/pom.xml @@ -254,7 +254,7 @@ com.microsoft.sqlserver mssql-jdbc - 6.1.3.jre8-preview + 6.4.0.jre8 test diff --git a/src/main/java/io/ebean/ExpressionFactory.java b/src/main/java/io/ebean/ExpressionFactory.java index a2c44cffb..0c81a32e3 100644 --- a/src/main/java/io/ebean/ExpressionFactory.java +++ b/src/main/java/io/ebean/ExpressionFactory.java @@ -327,6 +327,30 @@ public interface ExpressionFactory { */ Expression allEq(Map propertyMap); + /** + * Add expression for ANY of the given bit flags to be set. + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + Expression bitwiseAny(String propertyName, long flags); + + /** + * Add expression for ALL of the given bit flags to be set. + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + Expression bitwiseAll(String propertyName, long flags); + + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + Expression bitwiseAnd(String propertyName, long flags, long match); + /** * Add raw expression with a single parameter. *

    diff --git a/src/main/java/io/ebean/ExpressionList.java b/src/main/java/io/ebean/ExpressionList.java index 4723ab212..711d23906 100644 --- a/src/main/java/io/ebean/ExpressionList.java +++ b/src/main/java/io/ebean/ExpressionList.java @@ -482,7 +482,7 @@ public interface ExpressionList { /** * Extended version for setDistinct in conjunction with "findSingleAttributeList"; - * + *

    *

    {@code
        *
        *  List> orderStatusCount =
    @@ -878,7 +878,7 @@ public interface ExpressionList {
     
       /**
        * In - using a subQuery.
    -   *
    +   * 

    * This is exactly the same as in() and provided due to "in" being a Kotlin keyword * (and hence to avoid the slightly ugly escaping when using in() in Kotlin) */ @@ -888,7 +888,7 @@ public interface ExpressionList { /** * In - property has a value in the array of values. - * + *

    * This is exactly the same as in() and provided due to "in" being a Kotlin keyword * (and hence to avoid the slightly ugly escaping when using in() in Kotlin) */ @@ -898,7 +898,7 @@ public interface ExpressionList { /** * In - property has a value in the collection of values. - * + *

    * This is exactly the same as in() and provided due to "in" being a Kotlin keyword * (and hence to avoid the slightly ugly escaping when using in() in Kotlin) */ @@ -996,6 +996,53 @@ public interface ExpressionList { */ ExpressionList arrayIsNotEmpty(String propertyName); + /** + * Add expression for ANY of the given bit flags to be set. + *

    {@code
    +   *
    +   * where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
    +   *
    +   * }
    + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAny(String propertyName, long flags); + + /** + * Add expression for ALL of the given bit flags to be set. + *

    + *

    {@code
    +   *
    +   * where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR)
    +   *
    +   * }
    + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAll(String propertyName, long flags); + + /** + * Add bitwise AND expression of the given bit flags to compare with the match/mask. + *

    + *

    {@code
    +   *
    +   * // Flags Bulk + Size = Size
    +   * // ... meaning Bulk is not set and Size is set
    +   *
    +   * long selectedFlags = BwFlags.HAS_BULK + BwFlags.HAS_SIZE;
    +   * long mask = BwFlags.HAS_SIZE; // Only Size flag set
    +   *
    +   * where().bitwiseAnd("flags", selectedFlags, mask)
    +   *
    +   * }
    + * + * @param propertyName The property that holds the flags value + * @param flags The flags we are looking for + */ + ExpressionList bitwiseAnd(String propertyName, long flags, long match); + /** * Add raw expression with a single parameter. *

    diff --git a/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index 49bb47bf9..e61c9479e 100644 --- a/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -1,8 +1,8 @@ package io.ebeaninternal.api; -import io.ebeaninternal.server.core.DbExpressionHandler; import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; import java.util.List; diff --git a/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java deleted file mode 100644 index fe2c97893..000000000 --- a/src/main/java/io/ebeaninternal/server/core/BaseDbExpression.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.ebeaninternal.server.core; - -/** - * Not supported JSON or ARRAY expression handler. - */ -abstract class BaseDbExpression implements DbExpressionHandler { - - private final String concatOperator; - - BaseDbExpression(String concatOperator) { - this.concatOperator = concatOperator; - } - - @Override - public String getConcatOperator() { - return concatOperator; - } - -} diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index e9b423ece..ab0587d94 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -42,6 +42,8 @@ import io.ebeaninternal.server.deploy.parse.DeployInherit; import io.ebeaninternal.server.deploy.parse.DeployUtil; import io.ebeaninternal.server.dto.DtoBeanManager; import io.ebeaninternal.server.expression.DefaultExpressionFactory; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; +import io.ebeaninternal.server.expression.platform.DbExpressionHandlerFactory; import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.persist.DefaultPersister; import io.ebeaninternal.server.persist.platform.MultiValueBind; @@ -267,18 +269,7 @@ public class InternalConfiguration { * Return the JSON expression handler for the given database platform. */ private DbExpressionHandler getDbExpressionHandler(DatabasePlatform databasePlatform) { - Platform platform = databasePlatform.getPlatform(); - String concatOperator = databasePlatform.getConcatOperator(); - switch (platform) { - case POSTGRES: - return new PostgresDbExpression(concatOperator); - case ORACLE: - return new OracleDbExpression(concatOperator); - case SQLSERVER: - return new SqlServerDbExpression(concatOperator); - default: - return new BasicDbExpression(concatOperator); - } + return DbExpressionHandlerFactory.from(databasePlatform); } private MultiValueBind createMultiValueBind(Platform platform) { diff --git a/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java b/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java new file mode 100644 index 000000000..073ee51df --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/BitwiseExpression.java @@ -0,0 +1,63 @@ +package io.ebeaninternal.server.expression; + +import io.ebeaninternal.api.SpiExpression; +import io.ebeaninternal.api.SpiExpressionRequest; + +import java.io.IOException; + +/** + * Bitwise expression. + */ +class BitwiseExpression extends AbstractExpression { + + protected final BitwiseOp operator; + + private final String compare; + + protected final long flags; + + private final long match; + + BitwiseExpression(String propertyName, BitwiseOp operator, long flags, String compare, long match) { + super(propertyName); + this.operator = operator; + this.flags = flags; + this.compare = compare; + this.match = match; + } + + @Override + public void writeDocQuery(DocQueryContext context) throws IOException { + throw new IllegalStateException("Not supported for document queries"); + } + + @Override + public void queryPlanHash(StringBuilder builder) { + builder.append("Bitwise["); + builder.append(propName).append(" op:").append(operator).append(" cp:").append(compare); + builder.append(" ?2]"); + } + + @Override + public int queryBindHash() { + return Long.hashCode(flags); + } + + @Override + public boolean isSameByBind(SpiExpression other) { + BitwiseExpression that = (BitwiseExpression) other; + return operator == that.operator && compare.equals(that.compare) && flags == that.flags && match == that.match; + } + + @Override + public void addSql(SpiExpressionRequest request) { + // Use DB specific expression handling + request.getDbPlatformHandler().bitwise(request, propName, operator, flags, compare, match); + } + + @Override + public void addBindValues(SpiExpressionRequest request) { + request.addBindValue(flags); + request.addBindValue(match); + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java b/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java new file mode 100644 index 000000000..c7a063f54 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/BitwiseOp.java @@ -0,0 +1,22 @@ +package io.ebeaninternal.server.expression; + +/** + * Bitwise expression operator. + */ +public enum BitwiseOp { + + /** + * All flags are set (derived expression BITAND flags == flags). + */ + ALL, + + /** + * Any flags are set (derived expression BITAND flags != 0). + */ + ANY, + + /** + * BITAND flags == match. + */ + AND +} diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java index 4725d41e5..14ab457c8 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionFactory.java @@ -136,6 +136,21 @@ public class DefaultExpressionFactory implements SpiExpressionFactory { return new ArrayIsEmptyExpression(propertyName, false); } + @Override + public Expression bitwiseAny(String propertyName, long flags) { + return new BitwiseExpression(propertyName, BitwiseOp.ANY, flags, "!=", 0L); + } + + @Override + public Expression bitwiseAll(String propertyName, long flags) { + return new BitwiseExpression(propertyName, BitwiseOp.ALL, flags, "=", flags); + } + + @Override + public Expression bitwiseAnd(String propertyName, long flags, long match) { + return new BitwiseExpression(propertyName, BitwiseOp.AND, flags, "=", match); + } + /** * Equal To - property equal to the given value. */ diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java index 29747b439..ef2e8c89c 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionList.java @@ -699,6 +699,24 @@ public class DefaultExpressionList implements SpiExpressionList { return this; } + @Override + public ExpressionList bitwiseAny(String propertyName, long flags) { + add(expr.bitwiseAny(propertyName, flags)); + return this; + } + + @Override + public ExpressionList bitwiseAll(String propertyName, long flags) { + add(expr.bitwiseAll(propertyName, flags)); + return this; + } + + @Override + public ExpressionList bitwiseAnd(String propertyName, long flags, long match) { + add(expr.bitwiseAnd(propertyName, flags, match)); + return this; + } + @Override public ExpressionList eq(String propertyName, Object value) { add(expr.eq(propertyName, value)); diff --git a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java index a1cc868f0..557c53996 100644 --- a/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java +++ b/src/main/java/io/ebeaninternal/server/expression/DefaultExpressionRequest.java @@ -2,10 +2,10 @@ package io.ebeaninternal.server.expression; import io.ebeaninternal.api.SpiExpressionList; import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.server.core.DbExpressionHandler; import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.DeployParser; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.type.DataBind; diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index 4d4c3a53c..d7d6c0c7a 100644 --- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -533,6 +533,21 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression return exprList.arrayIsNotEmpty(propertyName); } + @Override + public ExpressionList bitwiseAny(String propertyName, long flags) { + return exprList.bitwiseAny(propertyName, flags); + } + + @Override + public ExpressionList bitwiseAll(String propertyName, long flags) { + return exprList.bitwiseAll(propertyName, flags); + } + + @Override + public ExpressionList bitwiseAnd(String propertyName, long flags, long match) { + return exprList.bitwiseAnd(propertyName, flags, match); + } + @Override public ExpressionList ge(String propertyName, Object value) { return exprList.ge(propertyName, value); diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java new file mode 100644 index 000000000..584215d4c --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -0,0 +1,60 @@ +package io.ebeaninternal.server.expression.platform; + +import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.BitwiseOp; + +/** + * Not supported JSON or ARRAY expression handler. + */ +abstract class BaseDbExpression implements DbExpressionHandler { + + private final String concatOperator; + + BaseDbExpression(String concatOperator) { + this.concatOperator = concatOperator; + } + + @Override + public String getConcatOperator() { + return concatOperator; + } + + @Override + public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + + String bitOp = bitOp(operator); + request.append("(").append(propName).append(" ").append(bitOp).append(" ? ").append(compare).append(" ?)"); + } + + private String bitOp(BitwiseOp operator) { + switch (operator) { + case ANY: + case AND: + case ALL: + return "&"; + default: + throw new IllegalArgumentException("Unknown Bitwise operator " + operator + " not handled?"); + } + } + + /** + * Common alternative where the bitwise operation is a function (specifically bitand is used - H2 and Oracle). + */ + protected void bitwiseFunction(SpiExpressionRequest request, String propName, BitwiseOp operator, String compare) { + + String funcName = functionName(operator); + request.append(funcName).append("(").append(propName).append(", ?) ").append(compare).append(" ?"); + } + + protected String functionName(BitwiseOp operator) { + switch (operator) { + case AND: + case ANY: + case ALL: + return "bitand"; + default: + throw new IllegalArgumentException("Unknown Bitwise operator " + operator + " not handled?"); + } + } + +} diff --git a/src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java similarity index 94% rename from src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java index ef8ad5b4a..adacca04d 100644 --- a/src/main/java/io/ebeaninternal/server/core/BasicDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; diff --git a/src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java similarity index 73% rename from src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java rename to src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java index 7ce5a4074..7cf6d696a 100644 --- a/src/main/java/io/ebeaninternal/server/core/DbExpressionHandler.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java @@ -1,6 +1,7 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.BitwiseOp; import io.ebeaninternal.server.expression.Op; /** @@ -28,4 +29,8 @@ public interface DbExpressionHandler { */ void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty); + /** + * Add the bitwise expression. + */ + void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java new file mode 100644 index 000000000..b7b62eb71 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java @@ -0,0 +1,31 @@ +package io.ebeaninternal.server.expression.platform; + +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DatabasePlatform; + + +public class DbExpressionHandlerFactory { + + /** + * Create and return the appropriate platform specific handing of expressions. + */ + public static DbExpressionHandler from(DatabasePlatform databasePlatform) { + + Platform platform = databasePlatform.getPlatform(); + String concatOperator = databasePlatform.getConcatOperator(); + switch (platform) { + case H2: + return new H2DbExpression(concatOperator); + case POSTGRES: + return new PostgresDbExpression(concatOperator); + case MYSQL: + return new MySqlDbExpression(concatOperator); + case ORACLE: + return new OracleDbExpression(concatOperator); + case SQLSERVER: + return new SqlServerDbExpression(concatOperator); + default: + return new BasicDbExpression(concatOperator); + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java new file mode 100644 index 000000000..4e0b544f2 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -0,0 +1,20 @@ +package io.ebeaninternal.server.expression.platform; + +import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.BitwiseOp; + +/** + * H2 handling of platform specific expressions. + */ +class H2DbExpression extends BasicDbExpression { + + H2DbExpression(String concatOperator) { + super(concatOperator); + } + + @Override + public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + + bitwiseFunction(request, propName, operator, compare); + } +} diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java new file mode 100644 index 000000000..e0e04ad1f --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -0,0 +1,12 @@ +package io.ebeaninternal.server.expression.platform; + +/** + * MySql specific handling of platform specific expressions. + */ +class MySqlDbExpression extends BasicDbExpression { + + MySqlDbExpression(String concatOperator) { + super(concatOperator); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java similarity index 75% rename from src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index 82480723d..4347d2e80 100644 --- a/src/main/java/io/ebeaninternal/server/core/OracleDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -1,10 +1,11 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.BitwiseOp; import io.ebeaninternal.server.expression.Op; /** - * Oracle JSON expression handler, ARRAY expressions not supported. + * Oracle handling of platform specific expressions. ARRAY expressions not supported. */ public class OracleDbExpression extends BaseDbExpression { @@ -25,6 +26,11 @@ public class OracleDbExpression extends BaseDbExpression { } } + @Override + public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + bitwiseFunction(request, propName, operator, compare); + } + @Override public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) { throw new IllegalStateException("ARRAY expressions not supported on Oracle"); diff --git a/src/main/java/io/ebeaninternal/server/core/PostgresCast.java b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java similarity index 95% rename from src/main/java/io/ebeaninternal/server/core/PostgresCast.java rename to src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java index 47dbb3f74..3e833cb12 100644 --- a/src/main/java/io/ebeaninternal/server/core/PostgresCast.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresCast.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; /** * Helper for determining type casting for JSON and ARRAY expressions. diff --git a/src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java similarity index 97% rename from src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index a6f42bc68..4af9aa2f7 100644 --- a/src/main/java/io/ebeaninternal/server/core/PostgresDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; diff --git a/src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java similarity index 95% rename from src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java rename to src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index 06a7824a1..dc52066e3 100644 --- a/src/main/java/io/ebeaninternal/server/core/SqlServerDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; diff --git a/src/main/java/io/ebeaninternal/server/persist/Binder.java b/src/main/java/io/ebeaninternal/server/persist/Binder.java index 7a69ee7eb..55833eae5 100644 --- a/src/main/java/io/ebeaninternal/server/persist/Binder.java +++ b/src/main/java/io/ebeaninternal/server/persist/Binder.java @@ -2,9 +2,9 @@ package io.ebeaninternal.server.persist; import io.ebean.config.dbplatform.DbPlatformType; import io.ebeaninternal.api.BindParams; -import io.ebeaninternal.server.core.DbExpressionHandler; import io.ebeaninternal.server.core.Message; import io.ebeaninternal.server.core.timezone.DataTimeZone; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; import io.ebeaninternal.server.persist.platform.MultiValueBind; import io.ebeaninternal.server.transaction.TransactionManager; import io.ebeaninternal.server.type.DataBind; diff --git a/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java b/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java index f0179ea0a..5bd44e3de 100644 --- a/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java +++ b/src/test/java/io/ebeaninternal/server/expression/TDSpiExpressionRequest.java @@ -1,9 +1,9 @@ package io.ebeaninternal.server.expression; import io.ebeaninternal.api.SpiExpressionRequest; -import io.ebeaninternal.server.core.DbExpressionHandler; import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; import java.util.ArrayList; import java.util.List; diff --git a/src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java b/src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java similarity index 84% rename from src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java rename to src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java index f8e43263f..526ca3353 100644 --- a/src/test/java/io/ebeaninternal/server/core/PostgresCastTest.java +++ b/src/test/java/io/ebeaninternal/server/expression/platform/PostgresCastTest.java @@ -1,4 +1,4 @@ -package io.ebeaninternal.server.core; +package io.ebeaninternal.server.expression.platform; import org.junit.Test; @@ -8,7 +8,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class PostgresCastTest { @Test - public void cast() throws Exception { + public void cast() { assertThat(PostgresCast.cast(1)).isEqualTo("::integer"); assertThat(PostgresCast.cast(1L)).isEqualTo("::bigint"); @@ -17,7 +17,7 @@ public class PostgresCastTest { } @Test - public void cast1() throws Exception { + public void cast1() { assertThat(PostgresCast.cast(1, true)).isEqualTo("::integer[]"); assertThat(PostgresCast.cast(1L, true)).isEqualTo("::bigint[]"); diff --git a/src/test/java/org/tests/expression/bitwise/BwBean.java b/src/test/java/org/tests/expression/bitwise/BwBean.java new file mode 100644 index 000000000..5c7fab206 --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/BwBean.java @@ -0,0 +1,70 @@ +package org.tests.expression.bitwise; + +import io.ebean.Model; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +@Entity +public class BwBean extends Model { + + @Id + long id; + + String name; + + // sqlserver wants integer type for bitwise AND operator + @Column(columnDefinition = "integer") + long flags; + + @Version + long version; + + public BwBean(String name) { + this.name = name; + } + + public BwBean(String name, long flags) { + this.name = name; + this.flags = flags; + } + + @Override + public String toString() { + return "nm:" + name; + } + + 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 long getFlags() { + return flags; + } + + public void setFlags(long flags) { + this.flags = flags; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/expression/bitwise/BwFlags.java b/src/test/java/org/tests/expression/bitwise/BwFlags.java new file mode 100644 index 000000000..41944659d --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/BwFlags.java @@ -0,0 +1,78 @@ +package org.tests.expression.bitwise; + +public class BwFlags { + + public static final int NOTHING = 0; + + /** + * Indicates the bean is being inserted. + */ + public static final int HAS_COLOUR = 0x00000001; + + /** + * Indicates persist cascade. + */ + public static final int HAS_SIZE = 0x00000002; + + /** + * Indicates Publish mode. + */ + public static final int HAS_BULK = 0x00000004; + + /** + * Return true if part of a Merge or Publish. + */ + public static boolean isColour(long state) { + return (state & HAS_COLOUR) != 0; + } + + /** + * Return true if the given flag is set. + */ + public static boolean isSet(int state, int flag) { + return (state & flag) == flag; + } + + public static int setHasColour(int state) { + return set(state, HAS_COLOUR, true); + } + + /** + * Parent was not inserted. + */ + public static int unsetHasColour(int state) { + return set(state, HAS_COLOUR, false); + } + + /** + * Set Recurse flag. + */ + public static int setHasSize(int state) { + return set(state, HAS_SIZE, true); + } + + public static int unsetHasSize(int state) { + return set(state, HAS_SIZE, false); + } + + /** + * Set Publish flag. + */ + public static int setHasBulk(int state) { + return set(state, HAS_BULK, true); + } + + public static int unsetHasBulk(int state) { + return set(state, HAS_BULK, false); + } + + + private static int set(int state, int flag, boolean setFlag) { + if (setFlag) { + return (state |= flag); + } else { + return state &= ~flag; + } + } + +} diff --git a/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java b/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java new file mode 100644 index 000000000..05be5d1ae --- /dev/null +++ b/src/test/java/org/tests/expression/bitwise/TestBitwiseExpressions.java @@ -0,0 +1,141 @@ +package org.tests.expression.bitwise; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestBitwiseExpressions extends BaseTestCase { + + @Test + public void where() { + + setup(); + bitwiseAnd(); + bitwiseAny(); + bitwiseAll(); + } + + private void bitwiseAnd() { + + List list = Ebean.find(BwBean.class) + // not bulk set AND size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE, BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + + list = Ebean.find(BwBean.class) + // bulk set AND not size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE, BwFlags.HAS_BULK) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("ColourAndBulk"); + + list = Ebean.find(BwBean.class) + // bulk set AND not size set + .where().bitwiseAnd("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR, BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + } + + private void bitwiseAny() { + + List list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(4); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_SIZE + BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(4); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAny("flags", BwFlags.HAS_COLOUR) + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + } + + private void bitwiseAll() { + + List list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_SIZE) + .findList(); + + assertThat(list).hasSize(1); + assertThat(list.get(0).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_BULK + BwFlags.HAS_COLOUR) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_SIZE) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(2); + assertThat(list.get(0).getName()).isEqualTo("SizeOnly"); + assertThat(list.get(1).getName()).isEqualTo("Everything"); + + list = Ebean.find(BwBean.class) + .where().bitwiseAll("flags", BwFlags.HAS_COLOUR) + .orderBy().asc("id") + .findList(); + + assertThat(list).hasSize(3); + assertThat(list.get(0).getName()).isEqualTo("ColourOnly"); + assertThat(list.get(1).getName()).isEqualTo("ColourAndBulk"); + assertThat(list.get(2).getName()).isEqualTo("Everything"); + + } + + private void setup() { + + Ebean.find(BwBean.class).delete(); + + new BwBean("Nothing", BwFlags.NOTHING).save(); + new BwBean("ColourOnly", BwFlags.HAS_COLOUR).save(); + new BwBean("SizeOnly", BwFlags.HAS_SIZE).save(); + new BwBean("ColourAndBulk", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK).save(); + new BwBean("Everything", BwFlags.HAS_COLOUR + BwFlags.HAS_BULK + BwFlags.HAS_SIZE).save(); + + } +} diff --git a/src/test/java/org/tests/repository/CustomerRepository.java b/src/test/java/org/tests/repository/CustomerRepository.java index 31d18ef96..1dfdb51b1 100644 --- a/src/test/java/org/tests/repository/CustomerRepository.java +++ b/src/test/java/org/tests/repository/CustomerRepository.java @@ -4,12 +4,13 @@ import io.ebean.BeanRepository; import io.ebean.EbeanServer; import org.tests.model.basic.Customer; -import javax.inject.Inject; import java.util.List; +//import javax.inject.Inject; + public class CustomerRepository extends BeanRepository { - @Inject + //@Inject public CustomerRepository(EbeanServer server) { super(Customer.class, server); } From 4799c56e25b3c0870ca63d542c1eea4dc5d94ff6 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Mar 2018 18:19:17 +1300 Subject: [PATCH 0187/1036] #225 - Mapping - Add / review support for @IdClass --- .../io/ebean/bean/EntityBeanIntercept.java | 14 ++ .../server/deploy/BeanDescriptorManager.java | 5 +- .../server/deploy/BeanProperty.java | 16 +- .../server/deploy/BeanPropertyAssocOne.java | 32 ++-- .../server/deploy/BeanPropertyIdClass.java | 35 +++++ .../server/deploy/BeanTable.java | 77 +++++----- .../deploy/meta/DeployBeanDescriptor.java | 111 +++++++------- .../deploy/meta/DeployBeanProperty.java | 24 +++ .../meta/DeployBeanPropertyAssocOne.java | 12 +- .../deploy/meta/DeployBeanPropertyLists.java | 74 +++++---- .../server/deploy/meta/DeployBeanTable.java | 20 +-- .../deploy/meta/DeployTableJoinColumn.java | 6 +- .../deploy/parse/AnnotationAssocManys.java | 8 +- .../deploy/parse/AnnotationAssocOnes.java | 4 +- .../server/deploy/parse/AnnotationClass.java | 6 + .../server/deploy/parse/AnnotationFields.java | 19 +-- .../server/deploy/parse/AnnotationParser.java | 32 ++++ .../server/deploy/parse/ReadAnnotations.java | 1 + .../server/persist/dml/InsertHandler.java | 1 - .../persist/dmlbind/BindableIdEmbedded.java | 16 +- .../dmlbind/FactoryBaseProperties.java | 8 +- .../persist/dmlbind/FactoryEmbedded.java | 4 - .../server/persist/dmlbind/FactoryId.java | 4 +- .../dmlbind/MatchedImportedEmbedded.java | 35 +++++ .../dmlbind/MatchedImportedFactory.java | 54 +++++++ .../dmlbind/MatchedImportedProperty.java | 81 +--------- .../dmlbind/MatchedImportedScalar.java | 27 ++++ .../org/tests/merge/TestMergeCustomer.java | 2 +- .../java/org/tests/model/bridge/BEmbId.java | 53 +++++++ .../{BSiteUser.java => BSiteUserA.java} | 30 +++- .../org/tests/model/bridge/BSiteUserD.java | 61 ++++++++ .../org/tests/model/bridge/BSiteUserE.java | 44 ++++++ .../bridge/TestExplicitM2MBridgeTable.java | 15 +- .../tests/model/bridge/TestIdClassScalar.java | 143 ++++++++++++++++++ 34 files changed, 765 insertions(+), 309 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanPropertyIdClass.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedEmbedded.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedFactory.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedScalar.java create mode 100644 src/test/java/org/tests/model/bridge/BEmbId.java rename src/test/java/org/tests/model/bridge/{BSiteUser.java => BSiteUserA.java} (67%) create mode 100644 src/test/java/org/tests/model/bridge/BSiteUserD.java create mode 100644 src/test/java/org/tests/model/bridge/BSiteUserE.java create mode 100644 src/test/java/org/tests/model/bridge/TestIdClassScalar.java diff --git a/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/src/main/java/io/ebean/bean/EntityBeanIntercept.java index cde09876f..e35384ad4 100644 --- a/src/main/java/io/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/io/ebean/bean/EntityBeanIntercept.java @@ -133,6 +133,20 @@ public final class EntityBeanIntercept implements Serializable { this.nodeUsageCollector = usageCollector; } + /** + * Return the ownerId (IdClass). + */ + public Object getOwnerId() { + return ownerId; + } + + /** + * Set the ownerId (IdClass). + */ + public void setOwnerId(Object ownerId) { + this.ownerId = ownerId; + } + /** * Return the owning bean for an embedded bean. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index d1d449120..6bd12fda2 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1350,7 +1350,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // already assigned (So custom or UUID) return; } - if (desc.propertiesId().isEmpty()) { + if (desc.idProperty() == null) { // bean doesn't have an Id property if (desc.isBaseTableType() && desc.getBeanFinder() == null) { // expecting an id property @@ -1491,6 +1491,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private boolean isPersistentField(DeployBeanProperty prop) { Field field = prop.getField(); + if (field == null) { + return false; + } int modifiers = field.getModifiers(); return !(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) && !field.isAnnotationPresent(Transient.class); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 85f66e177..a7260f269 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -61,10 +61,12 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class); /** - * Flag to mark this at part of the unique id. + * Flag to mark this is the id property. */ final boolean id; + final boolean importedPrimaryKey; + /** * Flag to make this as a dummy property for unidirecitonal relationships. */ @@ -274,6 +276,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty this.name = InternString.intern(deploy.getName()); this.propertyIndex = deploy.getPropertyIndex(); this.unidirectionalShadow = deploy.isUndirectionalShadow(); + this.importedPrimaryKey = deploy.isImportedPrimaryKey(); this.discriminator = deploy.isDiscriminator(); this.localEncrypted = deploy.isLocalEncrypted(); this.dbEncrypted = deploy.isDbEncrypted(); @@ -395,6 +398,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty this.softDeleteDbSet = source.softDeleteDbSet; this.softDeleteDbPredicate = source.softDeleteDbPredicate; this.fetchEager = source.fetchEager; + this.importedPrimaryKey = source.importedPrimaryKey; this.unidirectionalShadow = source.unidirectionalShadow; this.discriminator = source.discriminator; this.localEncrypted = source.isLocalEncrypted(); @@ -473,8 +477,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty this.deployOrder = deployOrder; } - public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, - boolean propertyDeploy) { + public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) { return null; } @@ -935,6 +938,13 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty return null; } + /** + * If true this bean maps to the primary key. + */ + public boolean isImportedPrimaryKey() { + return importedPrimaryKey; + } + @Override public boolean isAssocMany() { // Returns false - override in BeanPropertyAssocMany. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 305ea9aa4..2d34242b1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -40,8 +40,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { private final boolean orphanRemoval; - private final boolean importedPrimaryKey; - private final boolean primaryKeyExport; private final PropertyForeignKey foreignKey; @@ -76,7 +74,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { foreignKey = deploy.getForeignKey(); primaryKeyExport = deploy.isPrimaryKeyExport(); - importedPrimaryKey = deploy.isImportedPrimaryKey(); oneToOne = deploy.isOneToOne(); oneToOneExported = deploy.isOneToOneExported(); orphanRemoval = deploy.isOrphanRemoval(); @@ -346,13 +343,6 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { return orphanRemoval; } - /** - * If true this bean maps to the primary key. - */ - public boolean isImportedPrimaryKey() { - return importedPrimaryKey; - } - @Override public void diff(String prefix, Map map, EntityBean newBean, EntityBean oldBean) { @@ -626,6 +616,14 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } + @Override + public void setValueIntercept(EntityBean bean, Object value) { + super.setValueIntercept(bean, value); + if (embedded && value instanceof EntityBean) { + setEmbeddedOwner(bean, value); + } + } + /** * For embedded bean set the owner and all properties to be loaded (recursively). */ @@ -638,18 +636,10 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } - private void setEmbeddedOwner(EntityBean bean, Object value) { + void setEmbeddedOwner(EntityBean bean, Object value) { ((EntityBean) value)._ebean_getIntercept().setEmbeddedOwner(bean, propertyIndex); } - @Override - public void setValueIntercept(EntityBean bean, Object value) { - super.setValueIntercept(bean, value); - if (embedded && value instanceof EntityBean) { - setEmbeddedOwner(bean, value); - } - } - @Override public void loadIgnore(DbReadContext ctx) { localHelp.loadIgnore(ctx); @@ -708,10 +698,10 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { if (embedded) { writeJson.writeFieldName(name); BeanDescriptor refDesc = descriptor.getBeanDescriptor(value.getClass()); - refDesc.jsonWriteForInsert(writeJson, (EntityBean)value); + refDesc.jsonWriteForInsert(writeJson, (EntityBean) value); } else { - jsonWriteTargetId(writeJson, (EntityBean)value); + jsonWriteTargetId(writeJson, (EntityBean) value); } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyIdClass.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyIdClass.java new file mode 100644 index 000000000..bd8486b39 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyIdClass.java @@ -0,0 +1,35 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; + +/** + * Bean property for an IdClass embeddedId. + */ +public class BeanPropertyIdClass extends BeanPropertyAssocOne { + + public BeanPropertyIdClass(BeanDescriptorMap owner, BeanDescriptor descriptor, DeployBeanPropertyAssocOne deploy) { + super(owner, descriptor, deploy); + } + + @Override + public void setValue(EntityBean bean, Object value) { + bean._ebean_getIntercept().setOwnerId(value); + } + + @Override + public void setValueIntercept(EntityBean bean, Object value) { + bean._ebean_getIntercept().setOwnerId(value); + } + + @Override + public Object getValue(EntityBean bean) { + return bean._ebean_getIntercept().getOwnerId(); + } + + @Override + public Object getValueIntercept(EntityBean bean) { + return bean._ebean_getIntercept().getOwnerId(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java index d9e3e1413..c481660e8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java @@ -30,7 +30,7 @@ public class BeanTable { */ private final String baseTable; - private final BeanProperty[] idProperties; + private final BeanProperty idProperty; /** * Create the BeanTable. @@ -39,7 +39,7 @@ public class BeanTable { this.owner = owner; this.beanType = mutable.getBeanType(); this.baseTable = InternString.intern(mutable.getBaseTable()); - this.idProperties = mutable.createIdProperties(owner); + this.idProperty = mutable.createIdProperty(owner); } @Override @@ -69,8 +69,8 @@ public class BeanTable { /** * Return the Id properties. */ - public BeanProperty[] getIdProperties() { - return idProperties; + public BeanProperty getIdProperty() { + return idProperty; } /** @@ -82,52 +82,51 @@ public class BeanTable { public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect) { - boolean complexKey = false; - BeanProperty[] props = idProperties; - - if (idProperties.length == 1) { - if (idProperties[0] instanceof BeanPropertyAssocOne) { - BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne) idProperties[0]; - props = assocOne.getProperties(); - complexKey = true; - } + if (idProperty == null) { + return; } - for (BeanProperty prop : props) { + if (idProperty instanceof BeanPropertyAssocOne) { + BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne) idProperty; + BeanProperty[] props = assocOne.getProperties(); + for (BeanProperty prop : props) { + addToJoin(foreignKeyPrefix, join, reverse, sqlFormulaSelect, true, prop); + } + } else { + addToJoin(foreignKeyPrefix, join, reverse, sqlFormulaSelect, false, idProperty); + } + } - String lc = prop.getDbColumn(); - String fk = lc; - if (foreignKeyPrefix != null) { - fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk); - } + private void addToJoin(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect, boolean complexKey, BeanProperty prop) { - if (complexKey) { - // just to copy the column name rather than prefix with the foreignKeyPrefix. - // I think that with complex keys this is the more common approach. - logger.debug("On table[{}] foreign key column [{}]", baseTable, lc); - fk = lc; - } - if (sqlFormulaSelect != null) { - fk = sqlFormulaSelect; - } - - DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk); - joinCol.setForeignSqlFormula(sqlFormulaSelect); - if (reverse) { - joinCol = joinCol.reverse(); - } - join.addJoinColumn(joinCol); + String lc = prop.getDbColumn(); + String fk = lc; + if (foreignKeyPrefix != null) { + fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk); } + if (complexKey) { + // just to copy the column name rather than prefix with the foreignKeyPrefix. + // I think that with complex keys this is the more common approach. + logger.debug("On table[{}] foreign key column [{}]", baseTable, lc); + fk = lc; + } + if (sqlFormulaSelect != null) { + fk = sqlFormulaSelect; + } + + DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk); + joinCol.setForeignSqlFormula(sqlFormulaSelect); + if (reverse) { + joinCol = joinCol.reverse(); + } + join.addJoinColumn(joinCol); } /** * Return the primary key DB column. */ public String getIdColumn() { - if (idProperties.length != 1) { - throw new IllegalStateException("Expecting only one Id column to join to on "+beanType); - } - return idProperties[0].dbColumn; + return idProperty.dbColumn; } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 1df0d8ffd..1855dee14 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -15,7 +15,6 @@ import io.ebean.event.BeanPostLoad; import io.ebean.event.BeanQueryAdapter; import io.ebean.event.changelog.ChangeLogFilter; import io.ebean.text.PathProperties; -import io.ebean.util.CamelCaseHelper; import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.server.core.CacheOptions; import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType; @@ -91,6 +90,10 @@ public class DeployBeanDescriptor { */ private IdType idType; + private Class idClass; + + private DeployBeanPropertyAssocOne idClassProperty; + /** * Set to true if the identity is default for the platform. */ @@ -205,7 +208,7 @@ public class DeployBeanDescriptor { private DocStoreMode docStoreUpdate; private DocStoreMode docStoreDelete; - private List idProperties; + private DeployBeanProperty idProperty; private TableJoin primaryKeyJoin; private short profileId; @@ -219,6 +222,20 @@ public class DeployBeanDescriptor { this.beanType = beanType; } + /** + * Set the IdClass to use. + */ + public void setIdClass(Class idClass) { + this.idClass = idClass; + } + + /** + * Return true if there is a IdClass set. + */ + public boolean isIdClass() { + return idClass != null; + } + /** * PK is also a FK. */ @@ -335,7 +352,7 @@ public class DeployBeanDescriptor { DeployBeanTable beanTable = new DeployBeanTable(getBeanType()); beanTable.setBaseTable(baseTable); - beanTable.setIdProperties(propertiesId()); + beanTable.setIdProperty(idProperty()); return beanTable; } @@ -443,6 +460,10 @@ public class DeployBeanDescriptor { return cacheOptions; } + public DeployBeanPropertyAssocOne getIdClassProperty() { + return idClassProperty; + } + public DeployBeanPropertyAssocOne getUnidirectional() { return unidirectional; } @@ -684,6 +705,15 @@ public class DeployBeanDescriptor { } } + public void postAnnotations() { + if (idClass != null) { + idClassProperty = new DeployBeanPropertyAssocOne<>(this, idClass); + idClassProperty.setName("_idClass"); + idClassProperty.setEmbedded(); + idClassProperty.setNullable(false); + } + } + /** * Add a bean property. */ @@ -691,32 +721,8 @@ public class DeployBeanDescriptor { return propMap.put(prop.getName(), prop); } - /** - * Find the matching property for a given property name or dbColumn. - *

    - * This is primarily to find imported primary key columns (ManyToOne that also match the PK). - *

    - */ - DeployBeanProperty findMatch(String propertyName, String dbColumn) { - - DeployBeanProperty prop = propMap.get(propertyName); - if (prop != null) { - return prop; - } - if (dbColumn != null) { - String asCamel = CamelCaseHelper.toCamelFromUnderscore(dbColumn); - prop = propMap.get(asCamel); - if (prop != null) { - return prop; - } - // scan looking for dbColumn match - for (DeployBeanProperty property : propMap.values()) { - if (dbColumn.equals(property.getDbColumn())) { - return property; - } - } - } - return null; + public Collection properties() { + return propMap.values(); } /** @@ -935,16 +941,14 @@ public class DeployBeanDescriptor { */ public boolean isPrimaryKeyCompoundOrNonNumeric() { - List ids = propertiesId(); - if (ids.size() != 1) { - // compound key - return true; + DeployBeanProperty id = idProperty(); + if (id == null) { + return false; } - DeployBeanProperty p = ids.get(0); - if (p instanceof DeployBeanPropertyAssocOne) { - return ((DeployBeanPropertyAssocOne) p).isCompound(); + if (id instanceof DeployBeanPropertyAssocOne) { + return ((DeployBeanPropertyAssocOne) id).isCompound(); } else { - return !p.isDbNumberType(); + return !id.isDbNumberType(); } } @@ -953,37 +957,32 @@ public class DeployBeanDescriptor { * compound). This is for the purpose of defining a sequence name. */ public String getSinglePrimaryKeyColumn() { - List ids = propertiesId(); - if (ids.size() == 1) { - DeployBeanProperty p = ids.get(0); - if (p instanceof DeployBeanPropertyAssoc) { + DeployBeanProperty id = idProperty(); + if (id != null) { + if (id instanceof DeployBeanPropertyAssoc) { // its a compound primary key return null; } else { - return p.getDbColumn(); + return id.getDbColumn(); } } return null; } /** - * Return the BeanProperty that make up the unique id. - *

    - * The order of these properties can be relied on to be consistent if the bean - * itself doesn't change or the xml deployment order does not change. - *

    + * Return the BeanProperty that is the Id. */ - public List propertiesId() { - - if (idProperties == null) { - idProperties = new ArrayList<>(2); - for (DeployBeanProperty prop : propMap.values()) { - if (prop.isId()) { - idProperties.add(prop); - } + public DeployBeanProperty idProperty() { + if (idProperty != null) { + return idProperty; + } + for (DeployBeanProperty prop : propMap.values()) { + if (prop.isId()) { + idProperty = prop; + return idProperty; } } - return idProperties; + return null; } public DeployBeanPropertyAssocOne findJoinToTable(String tableName) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index a363fdbdd..ce091b2ec 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -51,6 +51,7 @@ public class DeployBeanProperty { private static final int AUDITCOLUMN_ORDER = -1000000; private static final int VERSIONCOLUMN_ORDER = -1000000; private static final Set> PRIMITIVE_NUMBER_TYPES = new HashSet<>(); + static { PRIMITIVE_NUMBER_TYPES.add(float.class); PRIMITIVE_NUMBER_TYPES.add(double.class); @@ -64,6 +65,8 @@ public class DeployBeanProperty { */ private boolean id; + boolean importedPrimaryKey; + /** * Flag to mark the property as embedded. This could be on * BeanPropertyAssocOne rather than here. Put it here for checking Id type @@ -611,6 +614,16 @@ public class DeployBeanProperty { this.dbUpdateable = false; } + public void setImportedPrimaryKey() { + this.importedPrimaryKey = true; + } + + /** + * Set to true if this is part of the primary key. + */ + public void setImportedPrimaryKeyColumn(DeployBeanProperty primaryKey) { + this.importedPrimaryKey = true; + } public boolean isAggregation() { return aggregation != null; @@ -889,6 +902,13 @@ public class DeployBeanProperty { return genericType; } + /** + * Return true if this is part of the primary key. + */ + public boolean isImportedPrimaryKey() { + return importedPrimaryKey; + } + /** * Return true if this is included in the unique id. */ @@ -1046,6 +1066,10 @@ public class DeployBeanProperty { return tenantId; } + public boolean isIdClass() { + return desc.isIdClass(); + } + public void addDbMigrationInfo(DbMigrationInfo info) { if (dbMigrationInfos == null) { dbMigrationInfos = new ArrayList<>(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index 021f5e2f8..ed26cc045 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -17,8 +17,6 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { private boolean primaryKeyExport; - private boolean importedPrimaryKey; - private DeployBeanEmbedded deployEmbedded; private String columnPrefix; @@ -92,17 +90,11 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { this.oneToOneExported = true; } - /** - * Return true if this is part of the primary key. - */ - public boolean isImportedPrimaryKey() { - return importedPrimaryKey; - } - /** * Set to true if this is part of the primary key. */ - void setImportedPrimaryKey(DeployBeanProperty primaryKey) { + @Override + public void setImportedPrimaryKeyColumn(DeployBeanProperty primaryKey) { this.importedPrimaryKey = true; String dbColumn = primaryKey.getDbColumn(); if (dbColumn != null) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index 8c849e76b..241c56484 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -5,6 +5,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptorMap; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.BeanPropertyIdClass; import io.ebeaninternal.server.deploy.BeanPropertyOrderColumn; import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection; import io.ebeaninternal.server.deploy.InheritInfo; @@ -39,7 +40,7 @@ public class DeployBeanPropertyLists { private final LinkedHashMap propertyMap; - private final List ids = new ArrayList<>(); + private BeanProperty id; private final List local = new ArrayList<>(); @@ -70,7 +71,13 @@ public class DeployBeanPropertyLists { public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor desc, DeployBeanDescriptor deploy) { this.desc = desc; - setImportedPrimaryKeys(deploy); + DeployBeanPropertyAssocOne deployId = deploy.getIdClassProperty(); + if (deployId != null) { + this.id = new BeanPropertyIdClass(owner, desc, deployId); + setImportedPrimaryKeysFor(deploy, deployId); + } else { + setImportedPrimaryKeys(deploy); + } DeployBeanProperty deployOrderColumn = deploy.getOrderColumn(); this.orderColumn = deployOrderColumn != null ? new BeanPropertyOrderColumn(desc, deployOrderColumn) : null; @@ -142,23 +149,43 @@ public class DeployBeanPropertyLists { *

    */ private void setImportedPrimaryKeys(DeployBeanDescriptor deploy) { + DeployBeanProperty id = deploy.idProperty(); + if (id instanceof DeployBeanPropertyAssocOne) { + setImportedPrimaryKeysFor(deploy, (DeployBeanPropertyAssocOne) id); + } + } - List ids = deploy.propertiesId(); - if (ids.size() == 1) { - DeployBeanProperty id = ids.get(0); - if (id instanceof DeployBeanPropertyAssocOne) { - // only interested if the primary key is a compound key - DeployBeanDescriptor targetDeploy = ((DeployBeanPropertyAssocOne) id).getTargetDeploy(); - for (DeployBeanPropertyAssocOne assoc : deploy.propertiesAssocOne()) { - DeployBeanProperty pkMatch = targetDeploy.findMatch(assoc.getName(), assoc.getDbColumn()); - if (pkMatch != null) { - assoc.setImportedPrimaryKey(pkMatch); - } - } + private void setImportedPrimaryKeysFor(DeployBeanDescriptor deploy, DeployBeanPropertyAssocOne id) { + + for (DeployBeanProperty prop : id.getTargetDeploy().properties()) { + DeployBeanProperty match = findImported(deploy, prop); + if (match != null) { + match.setImportedPrimaryKeyColumn(prop); } } } + private DeployBeanProperty findImported(DeployBeanDescriptor deploy, DeployBeanProperty embeddedScalar) { + + // the logical name and db column we are looking for a match on + String name = embeddedScalar.getName(); + String dbColumn = embeddedScalar.getDbColumn(); + + DeployBeanProperty match = deploy.getBeanProperty(name); + if (match != null) { + return match; + } + // could look to match more by dbColumn + + for (DeployBeanPropertyAssocOne assocOne : deploy.propertiesAssocOne()) { + if (name.equals(assocOne.getName()) || (dbColumn != null && dbColumn.equals(assocOne.getDbColumn()))) { + return assocOne; + } + } + + return null; + } + /** * Return the unidirectional. */ @@ -188,12 +215,13 @@ public class DeployBeanPropertyLists { return; } if (prop.isId()) { - ids.add(prop); + if (id != null) { + throw new IllegalStateException("More that one @Id property on " + desc.getFullName() + " ?"); + } + id = prop; return; - } else { - nonTransients.add(prop); } - + nonTransients.add(prop); if (prop.isMutableScalarType()) { mutable.add(prop); } @@ -255,15 +283,7 @@ public class DeployBeanPropertyLists { } public BeanProperty getId() { - if (ids.size() > 1) { - String msg = "Issue with bean " + desc + ". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId." - + " Please email the ebean google group if you need further clarification."; - throw new IllegalStateException(msg); - } - if (ids.isEmpty()) { - return null; - } - return ids.get(0); + return id; } public BeanProperty[] getNonTransients() { diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanTable.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanTable.java index d37b4a6e8..0693210dc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanTable.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanTable.java @@ -4,9 +4,6 @@ import io.ebeaninternal.server.deploy.BeanDescriptorMap; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; -import java.util.List; - - /** * Used for associated beans in place of a BeanDescriptor. This is done to avoid * recursion issues due to the potentially bi-directional and circular @@ -25,12 +22,12 @@ public class DeployBeanTable { */ private String baseTable; - private List idProperties; + private DeployBeanProperty idProperty; /** * Create the BeanTable. */ - public DeployBeanTable(Class beanType) { + DeployBeanTable(Class beanType) { this.beanType = beanType; } @@ -53,12 +50,8 @@ public class DeployBeanTable { /** * Return the id properties. */ - public BeanProperty[] createIdProperties(BeanDescriptorMap owner) { - BeanProperty[] props = new BeanProperty[idProperties.size()]; - for (int i = 0; i < idProperties.size(); i++) { - props[i] = createProperty(owner, idProperties.get(i)); - } - return props; + public BeanProperty createIdProperty(BeanDescriptorMap owner) { + return idProperty == null ? null : createProperty(owner, idProperty); } @SuppressWarnings({"unchecked", "rawtypes"}) @@ -70,14 +63,13 @@ public class DeployBeanTable { } else { return new BeanProperty(prop); } - } /** * Set the Id properties. */ - public void setIdProperties(List idProperties) { - this.idProperties = idProperties; + public void setIdProperty(DeployBeanProperty idProperty) { + this.idProperty = idProperty; } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java index 2df36a716..c45de396f 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java @@ -92,9 +92,9 @@ public class DeployTableJoinColumn { private void setReferencedColumn(BeanTable beanTable) { if (localDbColumn == null) { - BeanProperty[] idProperties = beanTable.getIdProperties(); - if (idProperties.length == 1) { - localDbColumn = idProperties[0].getDbColumn(); + BeanProperty idProperty = beanTable.getIdProperty(); + if (idProperty != null) { + localDbColumn = idProperty.getDbColumn(); } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index df4edb1d6..dce5962c1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -247,8 +247,8 @@ class AnnotationAssocManys extends AnnotationParser { } if (!intJoin.hasJoinColumns()) { // define foreign key columns - BeanProperty[] localIds = localTable.getIdProperties(); - for (BeanProperty localId : localIds) { + BeanProperty localId = localTable.getIdProperty(); + if (localId != null) { // add the source to intersection join columns String fkCol = localTableName + "_" + localId.getDbColumn(); intJoin.addJoinColumn(new DeployTableJoinColumn(localId.getDbColumn(), namingConvention.getColumnFromProperty(null, fkCol))); @@ -257,8 +257,8 @@ class AnnotationAssocManys extends AnnotationParser { if (!destJoin.hasJoinColumns()) { // define inverse foreign key columns - BeanProperty[] otherIds = otherTable.getIdProperties(); - for (BeanProperty otherId : otherIds) { + BeanProperty otherId = otherTable.getIdProperty(); + if (otherId != null) { // set the intersection to dest table join columns final String fkCol = otherTableName + "_" + otherId.getDbColumn(); destJoin.addJoinColumn(new DeployTableJoinColumn(namingConvention.getColumnFromProperty(null, fkCol), otherId.getDbColumn())); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 7c614dee6..cd53cd350 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -92,9 +92,7 @@ public class AnnotationAssocOnes extends AnnotationParser { // May as well check for Id. Makes sense to me. Id id = get(prop, Id.class); if (id != null) { - prop.setEmbedded(); - prop.setId(); - prop.setNullable(false); + readIdAssocOne(prop); } DbForeignKey dbForeignKey = get(prop, DbForeignKey.class); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java index aa4902a9b..c5cb0b810 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java @@ -23,6 +23,7 @@ import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Embeddable; import javax.persistence.Entity; +import javax.persistence.IdClass; import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @@ -127,6 +128,11 @@ public class AnnotationClass extends AnnotationParser { } } + IdClass idClass = AnnotationUtil.findAnnotationRecursive(cls, IdClass.class); + if (idClass != null) { + descriptor.setIdClass(idClass.value()); + } + Embeddable embeddable = AnnotationUtil.findAnnotationRecursive(cls, Embeddable.class); if (embeddable != null) { descriptor.setEntityType(EntityType.EMBEDDED); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java index eecdaeda0..a84af1f0c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -91,7 +91,7 @@ public class AnnotationFields extends AnnotationParser { */ private FetchType defaultLobFetchType = FetchType.LAZY; - public AnnotationFields(GeneratedPropertyFactory generatedPropFactory, DeployBeanInfo info, + AnnotationFields(GeneratedPropertyFactory generatedPropFactory, DeployBeanInfo info, boolean javaxValidationAnnotations, boolean jacksonAnnotationsPresent, boolean eagerFetchLobs) { super(info, javaxValidationAnnotations); @@ -127,8 +127,7 @@ public class AnnotationFields extends AnnotationParser { Id id = get(prop, Id.class); if (id != null) { - prop.setId(); - prop.setNullable(false); + readIdAssocOne(prop); } EmbeddedId embeddedId = get(prop, EmbeddedId.class); @@ -211,7 +210,7 @@ public class AnnotationFields extends AnnotationParser { Id id = get(prop, Id.class); if (id != null) { - readId(prop); + readIdScalar(prop); } // determine the JDBC type using Lob/Temporal @@ -517,18 +516,6 @@ public class AnnotationFields extends AnnotationParser { return util.createDataEncryptSupport(table, column); } - private void readId(DeployBeanProperty prop) { - - prop.setId(); - prop.setNullable(false); - - if (prop.getPropertyType().equals(UUID.class)) { - if (descriptor.getIdGeneratorName() == null) { - descriptor.setUuidGenerator(); - } - } - } - private void readGenValue(GeneratedValue gen, DeployBeanProperty prop) { String genName = gen.generator(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java index 838f9308d..034caa595 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy.parse; import io.ebeaninternal.server.deploy.BeanCascadeInfo; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; +import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import javax.persistence.AttributeOverride; @@ -11,6 +12,7 @@ import javax.persistence.Column; import javax.validation.groups.Default; import java.util.HashMap; import java.util.Set; +import java.util.UUID; /** * Base class for reading deployment annotations. @@ -39,6 +41,36 @@ public abstract class AnnotationParser extends AnnotationBase { @Override public abstract void parse(); + /** + * Read the Id annotation on an embeddedId. + */ + protected void readIdAssocOne(DeployBeanPropertyAssoc prop) { + prop.setNullable(false); + if (prop.isIdClass()) { + prop.setImportedPrimaryKey(); + } else { + prop.setId(); + prop.setEmbedded(); + } + } + + /** + * Read the Id annotation on scalar property. + */ + protected void readIdScalar(DeployBeanProperty prop) { + prop.setNullable(false); + if (prop.isIdClass()) { + prop.setImportedPrimaryKey(); + } else { + prop.setId(); + if (prop.getPropertyType().equals(UUID.class)) { + if (descriptor.getIdGeneratorName() == null) { + descriptor.setUuidGenerator(); + } + } + } + } + /** * Helper method to set cascade types to the CascadeInfo on BeanProperty. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java index 41f065a9a..6af425828 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java @@ -83,6 +83,7 @@ public class ReadAnnotations { new AnnotationSql(info, javaxValidationAnnotations).parse(); new AnnotationClass(info).parseAttributeOverride(); + info.getDescriptor().postAnnotations(); } catch (RuntimeException e) { throw new RuntimeException("Error reading annotations for " + info, e); diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java index ec8cdd7df..7887c4b5a 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java @@ -69,7 +69,6 @@ public class InsertHandler extends DmlHandler { // expecting a concatenated key that can // be built from supplied AssocOne beans withId = meta.deriveConcatenatedId(persistRequest); - } else if (meta.supportsGetGeneratedKeys()) { // Identity with getGeneratedKeys useGeneratedKeys = true; diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java index c415eb943..1f094b0c5 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java @@ -2,7 +2,6 @@ package io.ebeaninternal.server.persist.dmlbind; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.core.PersistRequestBean; -import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.persist.dml.GenerateDmlRequest; @@ -15,7 +14,7 @@ import java.util.List; /** * Bindable for a EmbeddedId. */ -public final class BindableIdEmbedded implements BindableId { +final class BindableIdEmbedded implements BindableId { private final BeanPropertyAssocOne embId; @@ -23,10 +22,10 @@ public final class BindableIdEmbedded implements BindableId { private final MatchedImportedProperty[] matches; - public BindableIdEmbedded(BeanPropertyAssocOne embId, BeanDescriptor desc) { + BindableIdEmbedded(BeanPropertyAssocOne embId, MatchedImportedProperty[] matches) { this.embId = embId; this.props = embId.getProperties(); - matches = MatchedImportedProperty.build(props, desc); + this.matches = matches; } @Override @@ -67,13 +66,10 @@ public final class BindableIdEmbedded implements BindableId { public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException { EntityBean idValue = (EntityBean) embId.getValue(bean); - for (BeanProperty prop : props) { - Object value = prop.getValue(idValue); request.bind(value, prop); } - request.setIdValue(idValue); } @@ -88,7 +84,7 @@ public final class BindableIdEmbedded implements BindableId { public boolean deriveConcatenatedId(PersistRequestBean persist) { if (matches == null) { - String m = "Matches for the concatenated key columns where not found?" + String m = "No matches for " + embId.getFullBeanName() + " the concatenated key columns where not found?" + " I expect that the concatenated key was null, and this bean does" + " not have ManyToOne assoc beans matching the primary key columns?"; throw new PersistenceException(m); @@ -100,8 +96,8 @@ public final class BindableIdEmbedded implements BindableId { EntityBean newId = (EntityBean) embId.createEmbeddedId(); // populate it from the assoc one id values... - for (MatchedImportedProperty matche : matches) { - matche.populate(bean, newId); + for (MatchedImportedProperty match : matches) { + match.populate(bean, newId); } // support PropertyChangeSupport diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java index 48ac8ad1f..36c0998b8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryBaseProperties.java @@ -27,9 +27,11 @@ public class FactoryBaseProperties { public void create(List list, BeanDescriptor desc, DmlMode mode, boolean withLobs) { for (BeanProperty prop : desc.propertiesBaseScalar()) { - Bindable item = factoryProperty.create(prop, mode, withLobs); - if (item != null) { - list.add(item); + if (!prop.isImportedPrimaryKey()) { + Bindable item = factoryProperty.create(prop, mode, withLobs); + if (item != null) { + list.add(item); + } } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryEmbedded.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryEmbedded.java index b568d72d5..585bf1292 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryEmbedded.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryEmbedded.java @@ -27,18 +27,14 @@ public class FactoryEmbedded { BeanPropertyAssocOne[] embedded = desc.propertiesEmbedded(); for (BeanPropertyAssocOne anEmbedded : embedded) { - BeanProperty[] props = anEmbedded.getProperties(); - List bindList = new ArrayList<>(props.length); - for (BeanProperty prop : props) { Bindable item = factoryProperty.create(prop, mode, withLobs); if (item != null) { bindList.add(item); } } - list.add(new BindableEmbedded(anEmbedded, bindList)); } } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryId.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryId.java index bc67aa4c8..d517e051b 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryId.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/FactoryId.java @@ -20,14 +20,14 @@ public class FactoryId { BeanProperty id = desc.getIdProperty(); if (id == null) { return new BindableIdEmpty(); - } if (!id.isEmbedded()) { return new BindableIdScalar(id); } else { BeanPropertyAssocOne embId = (BeanPropertyAssocOne) id; - return new BindableIdEmbedded(embId, desc); + MatchedImportedProperty[] matches = MatchedImportedFactory.build(embId.getProperties(), desc); + return new BindableIdEmbedded(embId, matches); } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedEmbedded.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedEmbedded.java new file mode 100644 index 000000000..4ce1bb63d --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedEmbedded.java @@ -0,0 +1,35 @@ +package io.ebeaninternal.server.persist.dmlbind; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; + +/** + * Matches local embedded id properties to 'matching' properties from a + * ManyToOne associated bean that is a 'imported primary key'. + */ +class MatchedImportedEmbedded implements MatchedImportedProperty { + + private final BeanProperty localProp; + + private final BeanPropertyAssocOne assocOne; + + private final BeanProperty foreignProp; + + MatchedImportedEmbedded(BeanProperty localProp, BeanPropertyAssocOne assocOne, BeanProperty foreignProp) { + this.localProp = localProp; + this.assocOne = assocOne; + this.foreignProp = foreignProp; + } + + @Override + public void populate(EntityBean sourceBean, EntityBean embeddedId) { + Object assocBean = assocOne.getValue(sourceBean); + if (assocBean == null) { + throw new NullPointerException("The assoc bean for " + assocOne + " is null?"); + } + Object value = foreignProp.getValue((EntityBean) assocBean); + localProp.setValue(embeddedId, value); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedFactory.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedFactory.java new file mode 100644 index 000000000..f1ba04d9b --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedFactory.java @@ -0,0 +1,54 @@ +package io.ebeaninternal.server.persist.dmlbind; + +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; + +class MatchedImportedFactory { + + /** + * Create the array of matchedImportedProperty based on the properties and descriptor. + */ + protected static MatchedImportedProperty[] build(BeanProperty[] props, BeanDescriptor desc) { + + MatchedImportedProperty[] matches = new MatchedImportedProperty[props.length]; + + for (int i = 0; i < props.length; i++) { + // find matching assoc one property for dbColumn + matches[i] = findMatch(props[i], desc); + if (matches[i] == null) { + // ok, the assoc ones are not on the bean? + return null; + } + } + return matches; + } + + private static MatchedImportedProperty findMatch(BeanProperty prop, BeanDescriptor desc) { + + // find matching against the local database column + String dbColumn = prop.getDbColumn(); + + BeanPropertyAssocOne[] assocOnes = desc.propertiesOne(); + for (BeanPropertyAssocOne assocOne1 : assocOnes) { + if (assocOne1.isImportedPrimaryKey()) { + // search using the ImportedId from the assoc one + BeanProperty foreignMatch = assocOne1.getImportedId().findMatchImport(dbColumn); + if (foreignMatch != null) { + return new MatchedImportedEmbedded(prop, assocOne1, foreignMatch); + } + } + } + + BeanProperty[] scalar = desc.propertiesBaseScalar(); + for (BeanProperty beanProperty : scalar) { + if (dbColumn.equals(beanProperty.getDbColumn())) { + return new MatchedImportedScalar(prop, beanProperty); + } + } + + // there was no matching assoc one property. + // example UserRole bean missing assoc one to User? + return null; + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedProperty.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedProperty.java index d6b128d6d..cf0a37869 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedProperty.java +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedProperty.java @@ -1,86 +1,11 @@ package io.ebeaninternal.server.persist.dmlbind; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; -/** - * Matches local embedded id properties to 'matching' properties from a - * ManyToOne associated bean that is a 'imported primary key'. - *

    - * This object is designed to help BindableIdEmbedded and BindableIdMap to - * create a concatenated id from the id values from ManyToOne associated beans. - * This can be done when those ManyToOne associated beans make up the primary - * key. This typically means the BindableIdEmbedded is for a intersection table - * of a Many to Many relationship. - *

    - */ -class MatchedImportedProperty { - - private final BeanPropertyAssocOne assocOne; - - private final BeanProperty foreignProp; - - private final BeanProperty localProp; - - protected MatchedImportedProperty(BeanPropertyAssocOne assocOne, BeanProperty foreignProp, - BeanProperty localProp) { - this.assocOne = assocOne; - this.foreignProp = foreignProp; - this.localProp = localProp; - } - - protected void populate(EntityBean sourceBean, EntityBean destBean) { - Object assocBean = assocOne.getValue(sourceBean); - if (assocBean == null) { - String msg = "The assoc bean for " + assocOne + " is null?"; - throw new NullPointerException(msg); - } - - Object value = foreignProp.getValue((EntityBean) assocBean); - localProp.setValue(destBean, value); - } +public interface MatchedImportedProperty { /** - * Create the array of matchedImportedProperty based on the properties and descriptor. + * Populate the embeddedId bean from the source entity. */ - protected static MatchedImportedProperty[] build(BeanProperty[] props, BeanDescriptor desc) { - - MatchedImportedProperty[] matches = new MatchedImportedProperty[props.length]; - - for (int i = 0; i < props.length; i++) { - // find matching assoc one property for dbColumn - matches[i] = MatchedImportedProperty.findMatch(props[i], desc); - if (matches[i] == null) { - // ok, the assoc ones are not on the bean? - return null; - } - } - return matches; - } - - private static MatchedImportedProperty findMatch(BeanProperty prop, BeanDescriptor desc) { - - // find matching against the local database column - String dbColumn = prop.getDbColumn(); - - BeanPropertyAssocOne[] assocOnes = desc.propertiesOne(); - for (BeanPropertyAssocOne assocOne1 : assocOnes) { - if (assocOne1.isImportedPrimaryKey()) { - - // search using the ImportedId from the assoc one - BeanProperty foreignMatch = assocOne1.getImportedId().findMatchImport(dbColumn); - - if (foreignMatch != null) { - return new MatchedImportedProperty(assocOne1, foreignMatch, prop); - } - } - } - - // there was no matching assoc one property. - // example UserRole bean missing assoc one to User? - return null; - } - + void populate(EntityBean sourceBean, EntityBean embeddedId); } diff --git a/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedScalar.java b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedScalar.java new file mode 100644 index 000000000..436ef69a5 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/dmlbind/MatchedImportedScalar.java @@ -0,0 +1,27 @@ +package io.ebeaninternal.server.persist.dmlbind; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.BeanProperty; + +/** + * Matches local embedded id properties to 'matching' imported primary key scalar properties. + */ +class MatchedImportedScalar implements MatchedImportedProperty { + + private final BeanProperty localProp; + + private final BeanProperty foreignProp; + + MatchedImportedScalar(BeanProperty localProp, BeanProperty foreignProp) { + this.localProp = localProp; + this.foreignProp = foreignProp; + } + + @Override + public void populate(EntityBean sourceBean, EntityBean embeddedId) { + + Object value = foreignProp.getValue(sourceBean); + localProp.setValue(embeddedId, value); + } + +} diff --git a/src/test/java/org/tests/merge/TestMergeCustomer.java b/src/test/java/org/tests/merge/TestMergeCustomer.java index 8f314cac5..7bf86d1d8 100644 --- a/src/test/java/org/tests/merge/TestMergeCustomer.java +++ b/src/test/java/org/tests/merge/TestMergeCustomer.java @@ -367,7 +367,7 @@ public class TestMergeCustomer extends BaseTestCase { private MContact addContact(String email, String first, String last) { MContact mContact = new MContact(email, first, last); - int i = random.nextInt(2); + int i = 1 + random.nextInt(2); for (int j = 0; j < i; j++) { mContact.getMessages().add(new MContactMessage(first+" "+i, last+" "+i)); } diff --git a/src/test/java/org/tests/model/bridge/BEmbId.java b/src/test/java/org/tests/model/bridge/BEmbId.java new file mode 100644 index 000000000..ad99b4a2d --- /dev/null +++ b/src/test/java/org/tests/model/bridge/BEmbId.java @@ -0,0 +1,53 @@ +package org.tests.model.bridge; + +import javax.persistence.Embeddable; +import java.util.Objects; +import java.util.UUID; + +@Embeddable +public class BEmbId { + + private UUID siteId; + private UUID userId; + + public BEmbId(UUID siteId, UUID userId) { + this.siteId = siteId; + this.userId = userId; + } + + public UUID getSiteId() { + return siteId; + } + + public UUID getUserId() { + return userId; + } + + @Override + public String toString() { + return "st:" + siteId + " ui:" + userId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + BEmbId that = (BEmbId) o; + return Objects.equals(siteId, that.siteId) && Objects.equals(userId, that.userId); + } + + @Override + public int hashCode() { + return Objects.hash(siteId, userId); + } + + /** + * Just simulating the hash from Objects.hash(...) + */ + int otherHash() { + int result = 31 + siteId.hashCode(); + result = 31 * result + userId.hashCode(); + return result; + } +} diff --git a/src/test/java/org/tests/model/bridge/BSiteUser.java b/src/test/java/org/tests/model/bridge/BSiteUserA.java similarity index 67% rename from src/test/java/org/tests/model/bridge/BSiteUser.java rename to src/test/java/org/tests/model/bridge/BSiteUserA.java index b4ff1724e..e3c57c10d 100644 --- a/src/test/java/org/tests/model/bridge/BSiteUser.java +++ b/src/test/java/org/tests/model/bridge/BSiteUserA.java @@ -4,10 +4,12 @@ import javax.persistence.Embeddable; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.ManyToOne; +import javax.persistence.Version; +import java.util.Objects; import java.util.UUID; @Entity -public class BSiteUser { +public class BSiteUserA { @Embeddable public static class Id { @@ -16,21 +18,23 @@ public class BSiteUser { public UUID siteId; public UUID userId; + public Id(UUID siteId, UUID userId) { + this.siteId = siteId; + this.userId = userId; + } + @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - Id id = (Id) o; - if (!siteId.equals(id.siteId)) return false; - return userId.equals(id.userId); + Id that = (Id) o; + return Objects.equals(siteId, that.siteId) && Objects.equals(userId, that.userId); } @Override public int hashCode() { - int result = siteId.hashCode(); - result = 31 * result + userId.hashCode(); - return result; + return Objects.hash(siteId, userId); } } @@ -45,8 +49,10 @@ public class BSiteUser { @ManyToOne(optional = false) private final BUser user; + @Version + private long version; - public BSiteUser(BAccessLevel accessLevel, BSite site, BUser user) { + public BSiteUserA(BAccessLevel accessLevel, BSite site, BUser user) { this.accessLevel = accessLevel; this.site = site; this.user = user; @@ -75,4 +81,12 @@ public class BSiteUser { public void setAccessLevel(BAccessLevel accessLevel) { this.accessLevel = accessLevel; } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } } diff --git a/src/test/java/org/tests/model/bridge/BSiteUserD.java b/src/test/java/org/tests/model/bridge/BSiteUserD.java new file mode 100644 index 000000000..4ff4513f4 --- /dev/null +++ b/src/test/java/org/tests/model/bridge/BSiteUserD.java @@ -0,0 +1,61 @@ +package org.tests.model.bridge; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Version; +import java.util.UUID; + +@Entity +@IdClass(BEmbId.class) +public class BSiteUserD { + + @Id + private UUID siteId; + + @Id + private UUID userId; + + private BAccessLevel accessLevel; + + @Version + private long version; + + public BSiteUserD(BAccessLevel accessLevel, UUID siteId, UUID userId) { + this.accessLevel = accessLevel; + this.siteId = siteId; + this.userId = userId; + } + + public UUID getSiteId() { + return siteId; + } + + public void setSiteId(UUID siteId) { + this.siteId = siteId; + } + + public UUID getUserId() { + return userId; + } + + public void setUserId(UUID userId) { + this.userId = userId; + } + + public BAccessLevel getAccessLevel() { + return accessLevel; + } + + public void setAccessLevel(BAccessLevel accessLevel) { + this.accessLevel = accessLevel; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/bridge/BSiteUserE.java b/src/test/java/org/tests/model/bridge/BSiteUserE.java new file mode 100644 index 000000000..a6795de77 --- /dev/null +++ b/src/test/java/org/tests/model/bridge/BSiteUserE.java @@ -0,0 +1,44 @@ +package org.tests.model.bridge; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.ManyToOne; + +@Entity +@IdClass(BEmbId.class) +public class BSiteUserE { + + @Id + @ManyToOne + private final BSite site; + + @Id + @ManyToOne + private final BUser user; + + private BAccessLevel accessLevel; + + + public BSiteUserE(BAccessLevel accessLevel, BSite site, BUser user) { + this.accessLevel = accessLevel; + this.site = site; + this.user = user; + } + + public BAccessLevel getAccessLevel() { + return accessLevel; + } + + public BSite getSite() { + return site; + } + + public BUser getUser() { + return user; + } + + public void setAccessLevel(BAccessLevel accessLevel) { + this.accessLevel = accessLevel; + } +} diff --git a/src/test/java/org/tests/model/bridge/TestExplicitM2MBridgeTable.java b/src/test/java/org/tests/model/bridge/TestExplicitM2MBridgeTable.java index 142f9aee5..ed22ae4c4 100644 --- a/src/test/java/org/tests/model/bridge/TestExplicitM2MBridgeTable.java +++ b/src/test/java/org/tests/model/bridge/TestExplicitM2MBridgeTable.java @@ -19,7 +19,7 @@ public class TestExplicitM2MBridgeTable extends BaseTestCase { Ebean.save(user); Ebean.save(site); - insertUpdateBridge(user, site); + insertUpdateBridgeA(user, site); insertUpdateBridgeB(user, site); insertUpdateBridgeC(user, site); } @@ -27,21 +27,26 @@ public class TestExplicitM2MBridgeTable extends BaseTestCase { /** * Test where matching by db column naming convention. */ - private void insertUpdateBridge(BUser user, BSite site) { + private void insertUpdateBridgeA(BUser user, BSite site) { - BSiteUser access = new BSiteUser(BAccessLevel.ONE, site, user); + BSiteUserA access = new BSiteUserA(BAccessLevel.ONE, site, user); Ebean.save(access); access.setAccessLevel(BAccessLevel.TWO); Ebean.save(access); - List list = Ebean.find(BSiteUser.class).findList(); + List list = Ebean.find(BSiteUserA.class).findList(); assertThat(list).isNotEmpty(); - for (BSiteUser bridge : list) { + for (BSiteUserA bridge : list) { assertThat(bridge.getId().siteId).isEqualTo(bridge.getSite().id); assertThat(bridge.getId().userId).isEqualTo(bridge.getUser().id); } + + BSiteUserA found = Ebean.find(BSiteUserA.class, new BSiteUserA.Id(site.id, user.id)); + found.setAccessLevel(BAccessLevel.THREE); + + Ebean.save(found); } /** diff --git a/src/test/java/org/tests/model/bridge/TestIdClassScalar.java b/src/test/java/org/tests/model/bridge/TestIdClassScalar.java new file mode 100644 index 000000000..5ad291d0d --- /dev/null +++ b/src/test/java/org/tests/model/bridge/TestIdClassScalar.java @@ -0,0 +1,143 @@ +package org.tests.model.bridge; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestIdClassScalar extends BaseTestCase { + + private BUser user = new BUser("Fiona"); + private BSite site = new BSite("avaje.io"); + + @Test + public void testBEmbId_equalsHashcode() { + + BEmbId a = new BEmbId(UUID.randomUUID(), UUID.randomUUID()); + BEmbId b = new BEmbId(a.getSiteId(), a.getUserId()); + + BEmbId c = new BEmbId(UUID.randomUUID(), UUID.randomUUID()); + + BEmbId d = new BEmbId(a.getSiteId(), UUID.randomUUID()); + + assertThat(a).isEqualTo(b); + assertThat(a.hashCode()).isEqualTo(b.hashCode()); + + assertThat(a).isNotEqualTo(c); + assertThat(a.hashCode()).isNotEqualTo(c.hashCode()); + + assertThat(a).isNotEqualTo(d); + assertThat(a.hashCode()).isNotEqualTo(d.hashCode()); + + + assertThat(a.hashCode()).isEqualTo(a.otherHash()); + + } + + @Test + public void test() { + + Ebean.save(user); + Ebean.save(site); + + insertUpdateBridgeD(user, site); + insertUpdateBridgeE(user, site); + } + + /** + * Test where matching by db column naming convention. + */ + private void insertUpdateBridgeD(BUser user, BSite site) { + + LoggedSqlCollector.start(); + + BSiteUserD access = new BSiteUserD(BAccessLevel.ONE, site.id, user.id); + Ebean.save(access); + + access.setAccessLevel(BAccessLevel.TWO); + Ebean.save(access); + + List list = Ebean.find(BSiteUserD.class).findList(); + assertThat(list).isNotEmpty(); + + for (BSiteUserD bridge : list) { + assertThat(bridge.getSiteId()).isEqualTo(site.id); + assertThat(bridge.getUserId()).isEqualTo(user.id); + } + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into bsite_user_d (site_id, user_id, access_level, version) values (?,?,?,?)"); + assertThat(sql.get(1)).contains("update bsite_user_d set access_level=?, version=? where site_id=? and user_id=? and version=?"); + assertThat(trimSql(sql.get(2))).contains("select t0.site_id, t0.user_id, t0.site_id, t0.user_id, t0.access_level, t0.version from bsite_user_d t0"); + + + BEmbId id = new BEmbId(site.id, user.id); + BSiteUserD one = Ebean.find(BSiteUserD.class, id); + + assertThat(one).isNotNull(); + assertThat(one.getSiteId()).isEqualTo(site.id); + assertThat(one.getUserId()).isEqualTo(user.id); + + one.setAccessLevel(BAccessLevel.THREE); + Ebean.save(one); + + sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.site_id, t0.user_id, t0.site_id, t0.user_id, t0.access_level, t0.version from bsite_user_d t0 where t0.site_id = ? and t0.user_id = ?"); + assertThat(sql.get(1)).contains("update bsite_user_d set access_level=?, version=? where site_id=? and user_id=? and version=?"); + } + + /** + * Test where matching by db column naming convention. + */ + private void insertUpdateBridgeE(BUser user, BSite site) { + + LoggedSqlCollector.start(); + + BSiteUserE access = new BSiteUserE(BAccessLevel.ONE, site, user); + Ebean.save(access); + + access.setAccessLevel(BAccessLevel.TWO); + Ebean.save(access); + + List list = Ebean.find(BSiteUserE.class).findList(); + assertThat(list).isNotEmpty(); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into bsite_user_e (site_id, user_id, access_level)"); + assertThat(sql.get(1)).contains("update bsite_user_e set access_level=? where site_id=? and user_id=?"); + assertThat(trimSql(sql.get(2))).contains("select t0.site_id, t0.user_id, t0.access_level, t0.site_id, t0.user_id from bsite_user_e t0"); + + + for (BSiteUserE bridge : list) { + assertThat(bridge.getSite().id).isEqualTo(site.id); + assertThat(bridge.getUser().id).isEqualTo(user.id); + } + + BEmbId id = new BEmbId(site.id, user.id); + + BSiteUserE one = Ebean.find(BSiteUserE.class, id); + + assertThat(one).isNotNull(); + assertThat(one.getSite().id).isEqualTo(site.id); + assertThat(one.getUser().id).isEqualTo(user.id); + + one.setAccessLevel(BAccessLevel.THREE); + Ebean.save(one); + + sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.site_id, t0.user_id, t0.access_level, t0.site_id, t0.user_id from bsite_user_e t0 where t0.site_id = ? and t0.user_id = ?"); + assertThat(sql.get(1)).contains("update bsite_user_e set access_level=? where site_id=? and user_id=?"); + + } +} From 9895e48485685b7c6bbe6986c3a11e97e80468b2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 15 Mar 2018 22:47:37 +1300 Subject: [PATCH 0188/1036] #1349 - Example passing test for - RawSql fetch object with inheritance / 2 --- .../inheritance/TestInheritanceRawSql.java | 68 ++++++++++++++++++- .../java/org/tests/model/basic/Vehicle.java | 12 ++++ .../org/tests/model/basic/VehicleLease.java | 64 +++++++++++++++++ .../tests/model/basic/VehicleLeaseLong.java | 32 +++++++++ .../tests/model/basic/VehicleLeaseShort.java | 33 +++++++++ 5 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/tests/model/basic/VehicleLease.java create mode 100644 src/test/java/org/tests/model/basic/VehicleLeaseLong.java create mode 100644 src/test/java/org/tests/model/basic/VehicleLeaseShort.java diff --git a/src/test/java/org/tests/inheritance/TestInheritanceRawSql.java b/src/test/java/org/tests/inheritance/TestInheritanceRawSql.java index 5b7d88620..a7cd1a4ab 100644 --- a/src/test/java/org/tests/inheritance/TestInheritanceRawSql.java +++ b/src/test/java/org/tests/inheritance/TestInheritanceRawSql.java @@ -4,13 +4,18 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.RawSql; import io.ebean.RawSqlBuilder; -import org.tests.model.basic.Truck; -import org.tests.model.basic.Vehicle; import org.junit.Assert; import org.junit.Test; +import org.tests.model.basic.Truck; +import org.tests.model.basic.Vehicle; +import org.tests.model.basic.VehicleLeaseLong; +import java.math.BigDecimal; +import java.time.LocalDate; import java.util.List; +import static org.assertj.core.api.Assertions.assertThat; + public class TestInheritanceRawSql extends BaseTestCase { @Test @@ -48,4 +53,63 @@ public class TestInheritanceRawSql extends BaseTestCase { Ebean.save(truck2); } + @Test + public void testJoinToInheritance() { + + VehicleLeaseLong longLease = new VehicleLeaseLong(); + longLease.setName("Long one"); + longLease.setBond(new BigDecimal("1000")); + longLease.setMinDuration(100); + longLease.setActiveEnd(LocalDate.now()); + + Ebean.save(longLease); + + + Truck truck = new Truck(); + truck.setCapacity(100D); + truck.setLicenseNumber("ZK1"); + truck.setLease(longLease); + + Ebean.save(truck); + + + String sql = "select v.dtype, v.id, v.license_number, l.dtype, l.id, l.name " + + "from vehicle v " + + "join vehicle_lease l on l.id = v.lease_id " + + "where v.id = ?"; + + RawSql rawSql = RawSqlBuilder.parse(sql) + .tableAliasMapping("v", null) + .tableAliasMapping("l", "lease") + .create(); + + Vehicle veh = Ebean.find(Vehicle.class) + .setRawSql(rawSql) + .setParameter(1, truck.getId()) + .findOne(); + + assertThat(veh).isNotNull(); + assertThat(veh.getLicenseNumber()).isEqualTo("ZK1"); + assertThat(veh.getLease().getName()).isEqualTo("Long one"); + + + RawSql rawSql2 = RawSqlBuilder.parse(sql) + .columnMappingIgnore("v.dtype") + .columnMapping("v.id", "id") + .columnMapping("v.license_number", "licenseNumber") + .columnMappingIgnore("l.dtype") + .columnMapping("l.id", "lease.id") + .columnMapping("l.name", "lease.name") + .create(); + + Vehicle veh2 = Ebean.find(Vehicle.class) + .setRawSql(rawSql2) + .setParameter(1, truck.getId()) + .findOne(); + + assertThat(veh2).isNotNull(); + assertThat(veh2.getLicenseNumber()).isEqualTo("ZK1"); + assertThat(veh2.getLease().getName()).isEqualTo("Long one"); + } + } diff --git a/src/test/java/org/tests/model/basic/Vehicle.java b/src/test/java/org/tests/model/basic/Vehicle.java index 4da993c42..cab8c4dde 100644 --- a/src/test/java/org/tests/model/basic/Vehicle.java +++ b/src/test/java/org/tests/model/basic/Vehicle.java @@ -3,6 +3,7 @@ package org.tests.model.basic; import javax.persistence.DiscriminatorColumn; import javax.persistence.Entity; import javax.persistence.Inheritance; +import javax.persistence.ManyToOne; import java.util.Date; @Entity @@ -19,6 +20,9 @@ public abstract class Vehicle extends BasicDomain { // @Transient private transient String testTransient; + @ManyToOne + private VehicleLease lease; + public String getLicenseNumber() { return licenseNumber; } @@ -42,4 +46,12 @@ public abstract class Vehicle extends BasicDomain { public void setTestTransient(String testTransient) { this.testTransient = testTransient; } + + public VehicleLease getLease() { + return lease; + } + + public void setLease(VehicleLease lease) { + this.lease = lease; + } } diff --git a/src/test/java/org/tests/model/basic/VehicleLease.java b/src/test/java/org/tests/model/basic/VehicleLease.java new file mode 100644 index 000000000..1aa7b703d --- /dev/null +++ b/src/test/java/org/tests/model/basic/VehicleLease.java @@ -0,0 +1,64 @@ +package org.tests.model.basic; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.Version; +import java.time.LocalDate; + +@Entity +@Inheritance +public abstract class VehicleLease { + + @Id + long id; + + String name; + + LocalDate activeStart; + + LocalDate activeEnd; + + @Version + long version; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDate getActiveStart() { + return activeStart; + } + + public void setActiveStart(LocalDate activeStart) { + this.activeStart = activeStart; + } + + public LocalDate getActiveEnd() { + return activeEnd; + } + + public void setActiveEnd(LocalDate activeEnd) { + this.activeEnd = activeEnd; + } +} diff --git a/src/test/java/org/tests/model/basic/VehicleLeaseLong.java b/src/test/java/org/tests/model/basic/VehicleLeaseLong.java new file mode 100644 index 000000000..4af74793f --- /dev/null +++ b/src/test/java/org/tests/model/basic/VehicleLeaseLong.java @@ -0,0 +1,32 @@ +package org.tests.model.basic; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import java.math.BigDecimal; + +@Entity +@Inheritance +@DiscriminatorValue("LONG") +public class VehicleLeaseLong extends VehicleLease { + + BigDecimal bond; + + int minDuration; + + public BigDecimal getBond() { + return bond; + } + + public void setBond(BigDecimal bond) { + this.bond = bond; + } + + public int getMinDuration() { + return minDuration; + } + + public void setMinDuration(int minDuration) { + this.minDuration = minDuration; + } +} diff --git a/src/test/java/org/tests/model/basic/VehicleLeaseShort.java b/src/test/java/org/tests/model/basic/VehicleLeaseShort.java new file mode 100644 index 000000000..6e5ccbee5 --- /dev/null +++ b/src/test/java/org/tests/model/basic/VehicleLeaseShort.java @@ -0,0 +1,33 @@ +package org.tests.model.basic; + +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Inheritance; +import java.math.BigDecimal; + +@Entity +@Inheritance +@DiscriminatorValue("SHORT") +public class VehicleLeaseShort extends VehicleLease { + + + BigDecimal dayRate; + + Integer maxDays; + + public BigDecimal getDayRate() { + return dayRate; + } + + public void setDayRate(BigDecimal dayRate) { + this.dayRate = dayRate; + } + + public Integer getMaxDays() { + return maxDays; + } + + public void setMaxDays(Integer maxDays) { + this.maxDays = maxDays; + } +} From 9d336cb20b33e551b5a0dd6e816a672030429cb0 Mon Sep 17 00:00:00 2001 From: yuanxuegui Date: Sat, 17 Mar 2018 13:13:39 +0800 Subject: [PATCH 0189/1036] ENH: Add mappingsLocation config to search xml mapping files. ENH: Add mappingsLocation config to search xml mapping files. ENH: Add mappingsLocation config to search xml mapping files. ENH: Add mappingsLocation config to search xml mapping files. ENH: Add mappingsLocation config to search xml mapping files. ENH: Add mappingsLocation config to search xml mapping files. remove unused import. ENH: Add mappingsLocation config and search xml mapping files feature. --- .../java/io/ebean/config/ServerConfig.java | 65 +++++++++++++------ .../server/deploy/BeanDescriptorManager.java | 39 ++++++++++- .../java/io/ebean/EbeanServer_eqlTest.java | 15 +++++ .../org/tests/rawsql/TestRawSqlOrmQuery.java | 26 ++++++++ .../ebean-xml-mappings/CustomerMapping.xml | 14 ++++ .../ebean-xml-mappings/OrderMapping.xml | 19 ++++++ src/test/resources/ebean.properties | 2 + 7 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 src/test/resources/ebean-xml-mappings/CustomerMapping.xml create mode 100644 src/test/resources/ebean-xml-mappings/OrderMapping.xml diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 51221e96f..8d0d6f797 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -14,14 +14,7 @@ import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbType; import io.ebean.config.dbplatform.IdType; import io.ebean.config.properties.PropertiesLoader; -import io.ebean.event.BeanFindController; -import io.ebean.event.BeanPersistController; -import io.ebean.event.BeanPersistListener; -import io.ebean.event.BeanPostConstructListener; -import io.ebean.event.BeanPostLoad; -import io.ebean.event.BeanQueryAdapter; -import io.ebean.event.BulkTableEventListener; -import io.ebean.event.ServerConfigStartup; +import io.ebean.event.*; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeLogRegister; @@ -33,14 +26,7 @@ import io.ebean.util.StringHelper; import org.avaje.datasource.DataSourceConfig; import javax.sql.DataSource; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.ServiceLoader; +import java.util.*; /** * The configuration used for creating a EbeanServer. @@ -488,6 +474,12 @@ public class ServerConfig { */ private boolean defaultOrderById = false; + /** + * The mappingLocations for searching xml mapping. Only used when + * mappingLocations is empty/not explicitly specified. + */ + private List mappingLocations = new ArrayList<>(); + /** * Construct a Server Configuration for programmatically creating an EbeanServer. */ @@ -2782,7 +2774,7 @@ public class ServerConfig { if (packages != null) { String packagesProp = p.get("search.packages", p.get("packages", null)); - packages = getSearchJarsPackages(packagesProp); + packages = getSearchList(packagesProp); } collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode); @@ -2862,6 +2854,12 @@ public class ServerConfig { tenantSchemaProvider = p.createInstance(TenantSchemaProvider.class, "tenant.schemaProvider", tenantSchemaProvider); tenantPartitionColumn = p.get("tenant.partitionColumn", tenantPartitionColumn); classes = getClasses(p); + + + if (mappingLocations != null) { + String mappingsProp = p.get("search.mappingsLocations", p.get("mappingsLocations", null)); + mappingLocations = getSearchList(mappingsProp); + } } private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) { @@ -2898,10 +2896,10 @@ public class ServerConfig { return classes; } - private List getSearchJarsPackages(String searchPackages) { + private List getSearchList(String searchNames) { - if (searchPackages != null) { - String[] entries = StringHelper.splitNames(searchPackages); + if (searchNames != null) { + String[] entries = StringHelper.splitNames(searchNames); List hitList = new ArrayList<>(entries.length); Collections.addAll(hitList, entries); @@ -3076,6 +3074,33 @@ public class ServerConfig { return config; } + /** + * Add a mapping location to search for xml mapping via class path search. + */ + public void addMappingLocation(String mappingLocation) { + if (mappingLocations == null) { + mappingLocations = new ArrayList<>(); + } + mappingLocations.add(mappingLocation); + } + + /** + * Return mapping locations to search for xml mapping via class path search. + */ + public List getMappingLocations() { + return mappingLocations; + } + + /** + * Set mapping locations to search for xml mapping via class path search. + *

    + * This is only used if classes have not been explicitly specified. + *

    + */ + public void setMappingLocations(List mappingLocations) { + this.mappingLocations = mappingLocations; + } + public enum UuidVersion { VERSION4, VERSION1, diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 6bd12fda2..1f37d27b3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -26,6 +26,7 @@ import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.TransactionEventTable; import io.ebeaninternal.server.cache.SpiCacheManager; +import io.ebeaninternal.server.core.ClassPathScanners; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.core.InternalConfiguration; import io.ebeaninternal.server.core.Message; @@ -65,6 +66,9 @@ import io.ebeaninternal.xmlmapping.model.XmNamedQuery; import io.ebeaninternal.xmlmapping.model.XmRawSql; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; import io.ebeanservice.docstore.api.DocStoreFactory; +import org.avaje.classpath.scanner.ClassPathScanner; +import org.avaje.classpath.scanner.Resource; +import org.avaje.classpath.scanner.ResourceFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +76,7 @@ import javax.persistence.MappedSuperclass; import javax.persistence.PersistenceException; import javax.persistence.Transient; import javax.sql.DataSource; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -416,6 +421,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } + List xmlMappingResources = searchXmlMapping(); + for (Resource xmlMappingRes : xmlMappingResources) { + try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) { + mappings.add(XmlMappingReader.read(is)); + } + } + for (XmEbean mapping : mappings) { List entityDeploy = mapping.getEntity(); for (XmEntity deploy : entityDeploy) { @@ -424,10 +436,35 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } catch (IOException e) { - throw new RuntimeException("Error reading ebean.xml", e); + throw new RuntimeException("Error reading ebean xml mapping", e); } } + private List searchXmlMapping() { + List scanners = ClassPathScanners.find(serverConfig); + List mappingLocations = serverConfig.getMappingLocations(); + List resourceList = new ArrayList<>(); + + long st = System.currentTimeMillis(); + if (mappingLocations != null && !mappingLocations.isEmpty()) { + for (ClassPathScanner finder : scanners) { + for (String mappingLocation : mappingLocations) { + resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() { + + @Override + public boolean isMatch(String resourceName) { + return resourceName.endsWith(".xml"); + } + })); + } + } + } + + long searchTime = System.currentTimeMillis() - st; + logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime); + return resourceList; + } + private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) { String entityClassName = entityDeploy.getClazz(); diff --git a/src/test/java/io/ebean/EbeanServer_eqlTest.java b/src/test/java/io/ebean/EbeanServer_eqlTest.java index a29e00bad..75c0c1f4f 100644 --- a/src/test/java/io/ebean/EbeanServer_eqlTest.java +++ b/src/test/java/io/ebean/EbeanServer_eqlTest.java @@ -250,4 +250,19 @@ public class EbeanServer_eqlTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id "); } + + @Test + public void namedQuery_fromCustomXmlLocations() { + + ResetBasicData.reset(); + + Query query = server() + .createNamedQuery(Customer.class, "withContactsById2") + .setParameter("id", 1); + + query.setUseCache(false); + query.findOne(); + + assertThat(query.getGeneratedSql()).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id "); + } } diff --git a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java index 51e3d53c5..cabde9917 100644 --- a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java +++ b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java @@ -51,6 +51,32 @@ public class TestRawSqlOrmQuery extends BaseTestCase { assertThat(sql).contains("where o.status = ? order by c.name, c.id"); } + @IgnorePlatform(Platform.ORACLE) + @Test + public void testNamed_fromCustomXmlLocations() { + + ResetBasicData.reset(); + + Query query = Ebean.createNamedQuery(Order.class, "myRawTest2"); + query.setParameter("orderStatus", Order.Status.NEW); + query.setMaxRows(10); + List list = query.findList(); + for (Order order : list) { + order.getCretime(); + } + + String sql = query.getGeneratedSql(); + if (isSqlServer()) { + assertThat(sql).contains("select top 10 o.id,"); + } else { + assertThat(sql).contains("select o.id,"); + assertThat(sql).contains("limit 10"); + } + assertThat(sql).contains("o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city from o_order o"); + assertThat(sql).contains("join o_customer c on o.kcustomer_id = c.id "); + assertThat(sql).contains("where o.status = ? order by c.name, c.id"); + } + @Test public void test() { diff --git a/src/test/resources/ebean-xml-mappings/CustomerMapping.xml b/src/test/resources/ebean-xml-mappings/CustomerMapping.xml new file mode 100644 index 000000000..b55626fbf --- /dev/null +++ b/src/test/resources/ebean-xml-mappings/CustomerMapping.xml @@ -0,0 +1,14 @@ + + + + + + + select (name, version) + fetch contacts (firstName, lastName, email) + where id = :id + + + + + diff --git a/src/test/resources/ebean-xml-mappings/OrderMapping.xml b/src/test/resources/ebean-xml-mappings/OrderMapping.xml new file mode 100644 index 000000000..cd35e81a9 --- /dev/null +++ b/src/test/resources/ebean-xml-mappings/OrderMapping.xml @@ -0,0 +1,19 @@ + + + + + + + + + select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city + from o_order o + join o_customer c on o.kcustomer_id = c.id + join o_address a on c.billing_address_id = a.id + where o.status = :orderStatus + order by c.name, c.id + + + + + diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 3b048c4c2..3616698d1 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -168,3 +168,5 @@ ebean.migrationtest.ddl.header=-- Migrationscripts for ebean unittest ebean.migrationtest.migration.appName=migrationtest ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest ebean.migrationtest.migration.strict=true + +ebean.mappingsLocations=classpath:/ebean-xml-mappings From f3251691e2e3e8ef658ee8dd9be2b94ccdae5f00 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 19 Mar 2018 09:18:00 +1300 Subject: [PATCH 0190/1036] Test only change - Add test for SavePoint and compare to transaction.setRollbackOnly() --- .../org/tests/transaction/TestSavepoint.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/test/java/org/tests/transaction/TestSavepoint.java diff --git a/src/test/java/org/tests/transaction/TestSavepoint.java b/src/test/java/org/tests/transaction/TestSavepoint.java new file mode 100644 index 000000000..5a159b333 --- /dev/null +++ b/src/test/java/org/tests/transaction/TestSavepoint.java @@ -0,0 +1,65 @@ +package org.tests.transaction; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Transaction; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; +import org.junit.Test; +import org.tests.model.basic.EBasicVer; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Savepoint; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestSavepoint extends BaseTestCase { + + @ForPlatform({Platform.POSTGRES, Platform.H2}) + @Test + public void test() throws SQLException { + + EBasicVer basicVer = new EBasicVer("save1"); + basicVer.setOther("other1"); + Ebean.save(basicVer); + + try (Transaction transaction = Ebean.beginTransaction()) { + + Connection connection = transaction.getConnection(); + Savepoint savepoint = connection.setSavepoint(); + + basicVer.setOther("changeOther"); + Ebean.save(basicVer); + + connection.rollback(savepoint); + transaction.commit(); + } + + EBasicVer found = Ebean.find(EBasicVer.class, basicVer.getId()); + assertThat(found.getOther()).isEqualTo("other1"); + + } + + @ForPlatform({Platform.POSTGRES, Platform.H2}) + @Test + public void rollbackOnly_expect_similarResult() { + + EBasicVer basicVer = new EBasicVer("save2"); + basicVer.setOther("other2"); + Ebean.save(basicVer); + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.setRollbackOnly(); + + basicVer.setOther("changeOther"); + Ebean.save(basicVer); + + transaction.commit(); + } + + EBasicVer found = Ebean.find(EBasicVer.class, basicVer.getId()); + assertThat(found.getOther()).isEqualTo("other2"); + + } +} From 5575273c96fd3b49f876814045a0fabf8e467f23 Mon Sep 17 00:00:00 2001 From: yuanxuegui Date: Mon, 19 Mar 2018 18:04:49 +0800 Subject: [PATCH 0191/1036] ENH: Add named DtoQuery, such that we can define native SQL queries in ebean mapping xml for DtoQuery. --- src/main/java/io/ebean/EbeanServer.java | 25 +- .../server/core/DefaultServer.java | 25 +- .../server/core/InternalConfiguration.java | 51 ++- .../server/deploy/BeanDescriptorManager.java | 87 +---- .../server/dto/DtoBeanDescriptor.java | 62 +++- .../server/dto/DtoBeanManager.java | 55 ++- .../xmlmapping/XmlMappingReader.java | 40 ++- .../ebeaninternal/xmlmapping/model/XmDto.java | 121 +++++++ .../xmlmapping/model/XmEbean.java | 19 +- src/main/resources/ebean-1.0.xsd | 11 + src/test/java/io/ebean/NamedDtoQueryTest.java | 335 ++++++++++++++++++ .../ebeaninternal/api/TDSpiEbeanServer.java | 10 +- .../ebean-xml-mappings/DCustMapping.xml | 77 ++++ 13 files changed, 814 insertions(+), 104 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java create mode 100644 src/test/java/io/ebean/NamedDtoQueryTest.java create mode 100644 src/test/resources/ebean-xml-mappings/DCustMapping.xml diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java index f13cb86e7..78619886b 100644 --- a/src/main/java/io/ebean/EbeanServer.java +++ b/src/main/java/io/ebean/EbeanServer.java @@ -8,12 +8,6 @@ import io.ebean.plugin.Property; import io.ebean.plugin.SpiServer; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.persistence.NonUniqueResultException; -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -22,6 +16,11 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Predicate; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.persistence.NonUniqueResultException; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; /** * Provides the API for fetching and saving beans to a particular DataSource. @@ -105,6 +104,7 @@ public interface EbeanServer { * * @param shutdownDataSource if true then shutdown the underlying DataSource if it is the EbeanORM * DataSource implementation. + * DataSource implementation. * @param deregisterDriver if true then deregister the JDBC driver if it is the EbeanORM * DataSource implementation. */ @@ -437,6 +437,19 @@ public interface EbeanServer { */ DtoQuery findDto(Class dtoType, String sql); + /** + * Create a named Query for DTO beans. + *

    + * DTO beans are just normal bean like classes with public constructor(s) and setters. + * They do not need to be registered with Ebean before use. + *

    + * + * @param dtoType The type of the DTO bean the rows will be mapped into. + * @param namedQuery The name of the query + * @param The type of the DTO bean. + */ + DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery); + /** * Create a SqlQuery for executing native sql * query statements. diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 7a75abd5f..da3d5af00 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -105,13 +105,6 @@ import io.ebeaninternal.server.transaction.TransactionManager; import io.ebeaninternal.util.ParamTypeHelper; import io.ebeaninternal.util.ParamTypeHelper.TypeInfo; import io.ebeanservice.docstore.api.DocStoreIntegration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.persistence.NonUniqueResultException; -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; -import javax.sql.DataSource; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -126,6 +119,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import javax.persistence.NonUniqueResultException; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; +import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The default server side implementation of EbeanServer. @@ -966,7 +965,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { } @Override - public Query createQuery(Class beanType, String eql) { + public DefaultOrmQuery createQuery(Class beanType, String eql) { DefaultOrmQuery query = createQuery(beanType); EqlParser.parse(eql, query); return query; @@ -999,6 +998,16 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return new DefaultDtoQuery<>(this, descriptor, sql.trim()); } + @Override + public DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery) { + DtoBeanDescriptor descriptor = dtoBeanManager.getDescriptor(dtoType); + SpiRawSql rawSql = descriptor.getNamedRawSql(namedQuery); + if (rawSql != null) { + return new DefaultDtoQuery<>(this, descriptor, rawSql.getSql().getUnparsedSql()); + } + throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName()); + } + @Override public DtoQuery findDto(Class dtoType, SpiQuery ormQuery) { diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index ab0587d94..82d395aed 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -69,19 +69,23 @@ import io.ebeaninternal.server.transaction.TransactionManagerOptions; import io.ebeaninternal.server.transaction.TransactionScopeManager; import io.ebeaninternal.server.type.DefaultTypeManager; import io.ebeaninternal.server.type.TypeManager; +import io.ebeaninternal.xmlmapping.XmlMappingReader; +import io.ebeaninternal.xmlmapping.model.XmEbean; import io.ebeanservice.docstore.api.DocStoreFactory; import io.ebeanservice.docstore.api.DocStoreIntegration; import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; import io.ebeanservice.docstore.none.NoneDocStoreFactory; -import org.avaje.datasource.DataSourcePool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.avaje.classpath.scanner.ClassPathScanner; +import org.avaje.classpath.scanner.Resource; +import org.avaje.classpath.scanner.ResourceFilter; +import org.avaje.datasource.DataSourcePool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Used to extend the ServerConfig with additional objects used to configure and @@ -134,6 +138,8 @@ public class InternalConfiguration { private final MultiValueBind multiValueBind; + private List xmlEbeanList = new ArrayList<>(); + public InternalConfiguration(ClusterManager clusterManager, SpiCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor, ServerConfig serverConfig, BootupClasses bootupClasses) { @@ -153,12 +159,20 @@ public class InternalConfiguration { this.multiValueBind = createMultiValueBind(databasePlatform.getPlatform()); this.deployInherit = new DeployInherit(bootupClasses); + xmlEbeanList = XmlMappingReader.readByResourceName(serverConfig.getClassLoadConfig().getClassLoader(), + "ebean.xml"); + List searchXmlMapping = searchXmlMapping(); + xmlEbeanList.addAll(XmlMappingReader.readByResourceList(serverConfig.getClassLoadConfig().getClassLoader(), + searchXmlMapping)); + this.deployCreateProperties = new DeployCreateProperties(typeManager); this.deployUtil = new DeployUtil(typeManager, serverConfig); this.dtoBeanManager = new DtoBeanManager(typeManager); + dtoBeanManager.readXmlMapping(serverConfig.getClassLoadConfig().getClassLoader(), + xmlEbeanList); this.beanDescriptorManager = new BeanDescriptorManager(this); - Map asOfTableMapping = beanDescriptorManager.deploy(); + Map asOfTableMapping = beanDescriptorManager.deploy(xmlEbeanList); Map draftTableMap = beanDescriptorManager.getDraftTableMap(); beanDescriptorManager.scheduleBackgroundTrim(); @@ -167,6 +181,31 @@ public class InternalConfiguration { this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap); } + private List searchXmlMapping() { + List scanners = ClassPathScanners.find(serverConfig); + List mappingLocations = serverConfig.getMappingLocations(); + List resourceList = new ArrayList<>(); + + long st = System.currentTimeMillis(); + if (mappingLocations != null && !mappingLocations.isEmpty()) { + for (ClassPathScanner finder : scanners) { + for (String mappingLocation : mappingLocations) { + resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() { + + @Override + public boolean isMatch(String resourceName) { + return resourceName.endsWith(".xml"); + } + })); + } + } + } + + long searchTime = System.currentTimeMillis() - st; + logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime); + return resourceList; + } + /** * Create and return the ExpressionFactory based on configuration and database platform. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 1f37d27b3..0aba19bb6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -26,7 +26,6 @@ import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.TransactionEventTable; import io.ebeaninternal.server.cache.SpiCacheManager; -import io.ebeaninternal.server.core.ClassPathScanners; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.core.InternalConfiguration; import io.ebeaninternal.server.core.Message; @@ -57,7 +56,6 @@ import io.ebeaninternal.server.query.CQueryPlan; import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.server.type.ScalarTypeInteger; import io.ebeaninternal.server.type.TypeManager; -import io.ebeaninternal.xmlmapping.XmlMappingReader; import io.ebeaninternal.xmlmapping.model.XmAliasMapping; import io.ebeaninternal.xmlmapping.model.XmColumnMapping; import io.ebeaninternal.xmlmapping.model.XmEbean; @@ -66,27 +64,12 @@ import io.ebeaninternal.xmlmapping.model.XmNamedQuery; import io.ebeaninternal.xmlmapping.model.XmRawSql; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; import io.ebeanservice.docstore.api.DocStoreFactory; -import org.avaje.classpath.scanner.ClassPathScanner; -import org.avaje.classpath.scanner.Resource; -import org.avaje.classpath.scanner.ResourceFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.persistence.MappedSuperclass; -import javax.persistence.PersistenceException; -import javax.persistence.Transient; -import javax.sql.DataSource; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -94,6 +77,12 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.persistence.MappedSuperclass; +import javax.persistence.PersistenceException; +import javax.persistence.Transient; +import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Creates BeanDescriptors. @@ -370,12 +359,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap { /** * Deploy returning the asOfTableMap (which is required by the SQL builders). */ - public Map deploy() { + public Map deploy(List mappings) { try { createListeners(); readEntityDeploymentInitial(); - readXmlMapping(); + readXmlMapping(mappings); readEmbeddedDeployment(); readEntityBeanTable(); readEntityDeploymentAssociations(); @@ -406,63 +395,15 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } - private void readXmlMapping() { + private void readXmlMapping(List mappings) { + ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader(); - try { - ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader(); - - Enumeration resources = classLoader.getResources("ebean.xml"); - - List mappings = new ArrayList<>(); - while (resources.hasMoreElements()) { - URL url = resources.nextElement(); - try (InputStream is = url.openStream()) { - mappings.add(XmlMappingReader.read(is)); - } - } - - List xmlMappingResources = searchXmlMapping(); - for (Resource xmlMappingRes : xmlMappingResources) { - try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) { - mappings.add(XmlMappingReader.read(is)); - } - } - - for (XmEbean mapping : mappings) { - List entityDeploy = mapping.getEntity(); - for (XmEntity deploy : entityDeploy) { - readEntityMapping(classLoader, deploy); - } - } - - } catch (IOException e) { - throw new RuntimeException("Error reading ebean xml mapping", e); - } - } - - private List searchXmlMapping() { - List scanners = ClassPathScanners.find(serverConfig); - List mappingLocations = serverConfig.getMappingLocations(); - List resourceList = new ArrayList<>(); - - long st = System.currentTimeMillis(); - if (mappingLocations != null && !mappingLocations.isEmpty()) { - for (ClassPathScanner finder : scanners) { - for (String mappingLocation : mappingLocations) { - resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() { - - @Override - public boolean isMatch(String resourceName) { - return resourceName.endsWith(".xml"); - } - })); - } + for (XmEbean mapping : mappings) { + List entityDeploy = mapping.getEntity(); + for (XmEntity deploy : entityDeploy) { + readEntityMapping(classLoader, deploy); } } - - long searchTime = System.currentTimeMillis() - st; - logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime); - return resourceList; } private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) { diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java index 04060e8a4..0e8f4b42f 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java @@ -1,7 +1,9 @@ package io.ebeaninternal.server.dto; import io.ebean.meta.MetricVisitor; - +import io.ebeaninternal.server.rawsql.SpiRawSql; +import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -10,15 +12,25 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DtoBeanDescriptor { + private static final Map EMPTY_NAMED_QUERY = new HashMap<>(); + + private static final Map EMPTY_RAW_MAP = new HashMap<>(); + private final Map plans = new ConcurrentHashMap<>(); private final Class dtoType; private final DtoMeta meta; + private Map namedRawSql; + + private Map namedQuery; + DtoBeanDescriptor(Class dtoType, DtoMeta meta) { this.dtoType = dtoType; this.meta = meta; + this.namedQuery = getNamedQuery(); + this.namedRawSql = getNamedRawSql(); } public Class getType() { @@ -42,4 +54,52 @@ public class DtoBeanDescriptor { plan.visit(visitor); } } + + /** + * Return the named ORM query. + */ + public String getNamedQuery(String name) { + return namedQuery.get(name); + } + + /** + * Return the named RawSql query. + */ + public SpiRawSql getNamedRawSql(String named) { + return namedRawSql.get(named); + } + + /** + * Return the named ORM queries. + */ + public Map getNamedQuery() { + return (namedQuery != null) ? namedQuery : EMPTY_NAMED_QUERY; + } + + /** + * Add a named query. + */ + public void addNamedQuery(String name, String query) { + if (namedQuery == null) { + namedQuery = new LinkedHashMap<>(); + } + namedQuery.put(name, query); + } + + /** + * Return the named RawSql queries. + */ + public Map getNamedRawSql() { + return (namedRawSql != null) ? namedRawSql : EMPTY_RAW_MAP; + } + + /** + * Add a named RawSql from ebean.xml file. + */ + public void addRawSql(String name, SpiRawSql rawSql) { + if (namedRawSql == null) { + namedRawSql = new HashMap<>(); + } + namedRawSql.put(name, rawSql); + } } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java index 7cbd9488d..2871b6192 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java @@ -1,16 +1,28 @@ package io.ebeaninternal.server.dto; +import io.ebean.RawSqlBuilder; import io.ebean.meta.MetricVisitor; +import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.type.TypeManager; - +import io.ebeaninternal.xmlmapping.model.XmAliasMapping; +import io.ebeaninternal.xmlmapping.model.XmColumnMapping; +import io.ebeaninternal.xmlmapping.model.XmDto; +import io.ebeaninternal.xmlmapping.model.XmEbean; +import io.ebeaninternal.xmlmapping.model.XmNamedQuery; +import io.ebeaninternal.xmlmapping.model.XmRawSql; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Manages all the DTO bean descriptors. */ public class DtoBeanManager { + private static final Logger logger = LoggerFactory.getLogger(DtoBeanManager.class); + private final TypeManager typeManager; private final Map descriptorMap = new ConcurrentHashMap<>(); @@ -43,4 +55,45 @@ public class DtoBeanManager { value.visit(visitor); } } + + public void readXmlMapping(ClassLoader classLoader, List mappings) { + for (XmEbean mapping : mappings) { + List dtoList = mapping.getDto(); + for (XmDto dto : dtoList) { + readDtoMapping(classLoader, dto); + } + } + } + + private void readDtoMapping(ClassLoader classLoader, XmDto dto) { + String dtoClassName = dto.getClazz(); + Class dtoClass; + try { + dtoClass = Class.forName(dtoClassName, false, classLoader); + } catch (Exception e) { + logger.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry"); + return; + } + + DtoBeanDescriptor dtoBeanDescriptor = getDescriptor(dtoClass); + if (dtoBeanDescriptor == null) { + logger.error("No dto bean for ebean xml entry " + dtoClass); + + } else { + for (XmRawSql sql : dto.getRawSql()) { + RawSqlBuilder builder = RawSqlBuilder.parse(sql.getQuery().getValue()); + for (XmColumnMapping columnMapping : sql.getColumnMapping()) { + builder.columnMapping(columnMapping.getColumn(), columnMapping.getProperty()); + } + for (XmAliasMapping aliasMapping : sql.getAliasMapping()) { + builder.tableAliasMapping(aliasMapping.getAlias(), aliasMapping.getProperty()); + } + dtoBeanDescriptor.addRawSql(sql.getName(), (SpiRawSql)builder.create()); + } + + for (XmNamedQuery namedQuery : dto.getNamedQuery()) { + dtoBeanDescriptor.addNamedQuery(namedQuery.getName(), namedQuery.getQuery().getValue()); + } + } + } } diff --git a/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java b/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java index e9e598e42..3e267349b 100644 --- a/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java +++ b/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java @@ -1,11 +1,17 @@ package io.ebeaninternal.xmlmapping; import io.ebeaninternal.xmlmapping.model.XmEbean; - +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Unmarshaller; -import java.io.InputStream; +import org.avaje.classpath.scanner.Resource; public class XmlMappingReader { @@ -24,4 +30,34 @@ public class XmlMappingReader { throw new RuntimeException(e); } } + + public static List readByResourceName(ClassLoader classLoader, String resourceName){ + try { + Enumeration resources = classLoader.getResources(resourceName); + List mappings = new ArrayList<>(); + while (resources.hasMoreElements()) { + URL url = resources.nextElement(); + try (InputStream is = url.openStream()) { + mappings.add(XmlMappingReader.read(is)); + } + } + return mappings; + } catch (IOException e) { + throw new RuntimeException("Error reading ebean xml mapping", e); + } + } + + public static List readByResourceList(ClassLoader classLoader, List resourceList){ + try { + List mappings = new ArrayList<>(); + for (Resource xmlMappingRes : resourceList) { + try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) { + mappings.add(XmlMappingReader.read(is)); + } + } + return mappings; + } catch (IOException e) { + throw new RuntimeException("Error reading ebean xml mapping", e); + } + } } diff --git a/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java b/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java new file mode 100644 index 000000000..cb64fbfa6 --- /dev/null +++ b/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java @@ -0,0 +1,121 @@ +package io.ebeaninternal.xmlmapping.model; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

    Java class for anonymous complex type. + *

    + *

    The following schema fragment specifies the expected content contained within this class. + *

    + *

    + * <complexType>
    + *   <complexContent>
    + *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
    + *       <sequence>
    + *         <element ref="{http://ebean-orm.github.io/xml/ns/ebean}named-query" maxOccurs="unbounded"/>
    + *         <element ref="{http://ebean-orm.github.io/xml/ns/ebean}raw-sql" maxOccurs="unbounded"/>
    + *       </sequence>
    + *       <attribute name="class" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
    + *     </restriction>
    + *   </complexContent>
    + * </complexType>
    + * 
    + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "namedQuery", + "rawSql" +}) +@XmlRootElement(name = "dto") +public class XmDto { + + @XmlElement(name = "named-query", required = true) + protected List namedQuery; + @XmlElement(name = "raw-sql", required = true) + protected List rawSql; + @XmlAttribute(name = "class", required = true) + protected String clazz; + + /** + * Gets the value of the namedQuery property. + *

    + *

    + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the namedQuery property. + *

    + *

    + * For example, to add a new item, do as follows: + *

    +   *    getNamedQuery().add(newItem);
    +   * 
    + *

    + *

    + *

    + * Objects of the following type(s) are allowed in the list + * {@link XmNamedQuery } + */ + public List getNamedQuery() { + if (namedQuery == null) { + namedQuery = new ArrayList<>(); + } + return this.namedQuery; + } + + /** + * Gets the value of the rawSql property. + *

    + *

    + * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the rawSql property. + *

    + *

    + * For example, to add a new item, do as follows: + *

    +   *    getRawSql().add(newItem);
    +   * 
    + *

    + *

    + *

    + * Objects of the following type(s) are allowed in the list + * {@link XmRawSql } + */ + public List getRawSql() { + if (rawSql == null) { + rawSql = new ArrayList<>(); + } + return this.rawSql; + } + + /** + * Gets the value of the clazz property. + * + * @return possible object is + * {@link String } + */ + public String getClazz() { + return clazz; + } + + /** + * Sets the value of the clazz property. + * + * @param value allowed object is + * {@link String } + */ + public void setClazz(String value) { + this.clazz = value; + } + +} diff --git a/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java b/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java index d1bc12236..4979fc865 100644 --- a/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java +++ b/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java @@ -1,12 +1,12 @@ package io.ebeaninternal.xmlmapping.model; +import java.util.ArrayList; +import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; -import java.util.ArrayList; -import java.util.List; /** @@ -28,14 +28,18 @@ import java.util.List; */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { - "entity" + "entity", + "dto" }) @XmlRootElement(name = "ebean") public class XmEbean { - @XmlElement(required = true) + @XmlElement(required = false) protected List entity; + @XmlElement(required = false) + protected List dto; + /** * Gets the value of the entity property. *

    @@ -63,4 +67,11 @@ public class XmEbean { return this.entity; } + public List getDto() { + if (dto == null) { + dto = new ArrayList<>(); + } + return this.dto; + } + } diff --git a/src/main/resources/ebean-1.0.xsd b/src/main/resources/ebean-1.0.xsd index c830f851f..4a79daecb 100644 --- a/src/main/resources/ebean-1.0.xsd +++ b/src/main/resources/ebean-1.0.xsd @@ -8,6 +8,7 @@ + @@ -22,6 +23,16 @@ + + + + + + + + + + diff --git a/src/test/java/io/ebean/NamedDtoQueryTest.java b/src/test/java/io/ebean/NamedDtoQueryTest.java new file mode 100644 index 000000000..ec3b810e4 --- /dev/null +++ b/src/test/java/io/ebean/NamedDtoQueryTest.java @@ -0,0 +1,335 @@ +package io.ebean; + +import io.ebean.meta.BasicMetricVisitor; +import io.ebean.meta.MetaQueryMetric; +import java.util.List; +import java.util.Optional; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.tests.model.basic.ResetBasicData; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NamedDtoQueryTest extends BaseTestCase { + + private static final Logger log = LoggerFactory.getLogger(NamedDtoQueryTest.class); + + @Test + public void dto_findList_constructorMatch() { + + ResetBasicData.reset(); + + DtoQuery dtoQuery = server().createNamedDtoQuery(DCust.class, "findList"); + + List list = dtoQuery.findList(); + + log.info(list.toString()); + assertThat(list).isNotEmpty(); + } + + @Test + public void dto_findEach_constructorMatch() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + server().createNamedDtoQuery(DCust.class, "findGtId") + .setParameter("id", 0) + .findEach(it -> log.info("got " + it.getId() + " " + it.getName())); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select id, name from o_customer where id > ?"); + } + + @Test + public void dto_findEachWhile_constructorMatch() { + + ResetBasicData.reset(); + + LoggedSqlCollector.start(); + server().createNamedDtoQuery(DCust.class, "findGtIdDesc") + .setParameter("id", 0) + .findEachWhile(customer -> { + log.info("got " + customer.getId() + " " + customer.getName()); + return customer.getId() > 3; + }); + + List sql = LoggedSqlCollector.stop(); + assertThat(sql.get(0)).contains("select id, name from o_customer where id > ?"); + } + + @Test + public void dto_findOneEmpty() { + + ResetBasicData.reset(); + + Optional rob = server().createNamedDtoQuery(DCust.class, "findByName") + .setParameter("name", "Fiona") + .findOneOrEmpty(); + + assertThat(rob.isPresent()).isTrue(); + + Optional oneOrEmpty = server().createNamedDtoQuery(DCust.class, "findByName") + .setParameter("name", "DoesNotExistMyFriend") + .findOneOrEmpty(); + + assertThat(oneOrEmpty.isPresent()).isFalse(); + } + + @Test + public void dto_findOne() { + + ResetBasicData.reset(); + + DCust fiona = server().createNamedDtoQuery(DCust.class, "findByName") + .setParameter("name", "Fiona") + .findOne(); + + assertThat(fiona.getName()).isEqualTo("Fiona"); + + DCust empty = server().createNamedDtoQuery(DCust.class, "findByName") + .setParameter("name", "DoesNotExistMyFriend") + .findOne(); + + assertThat(empty).isNull(); + } + + + @Test + public void dto_queryPlanHits() { + + ResetBasicData.reset(); + + resetAllMetrics(); + + String[] names = {"Rob", "Fiona", "Shrek"}; + + for (String name : names) { + + List custs = server().createNamedDtoQuery(DCust.class, "findByName_c3") + .setLabel("basic") + .setParameter("name", name) + .findList(); + + log.info("Found " + custs); + } + + // collect without reset + BasicMetricVisitor basic = new BasicMetricVisitor(false, true, true); + server().getMetaInfoManager().visitMetrics(basic); + + List stats = basic.getDtoQueryMetrics(); + assertThat(stats).hasSize(1); + + MetaQueryMetric queryMetric = stats.get(0); + assertThat(queryMetric.getLabel()).isEqualTo("basic"); + assertThat(queryMetric.getCount()).isEqualTo(3); + assertThat(queryMetric.getName()).isEqualTo("basic"); + + + server().createNamedDtoQuery(DCust.class, "findByName_c4") + .setLabel("basic2") + .setParameter("name", "rob") + .findList(); + + BasicMetricVisitor metric2 = server().getMetaInfoManager().visitBasic(); + + stats = metric2.getDtoQueryMetrics(); + assertThat(stats).hasSize(2); + + log.info("stats " + stats); + + } + + @Test + public void dto_findList_relaxedMode() { + + ResetBasicData.reset(); + + List list = server().createNamedDtoQuery(DCust3.class, "findByName_relaxedMode") + .setRelaxedMode() + .findList(); + + log.info(list.toString()); + assertThat(list).isNotEmpty(); + } + + @Test + public void dto_findList_relaxedMode_defaultConstructor() { + + ResetBasicData.reset(); + + List list = server().createNamedDtoQuery(DCust2.class, "findByName_relaxedMode") + .setRelaxedMode() + .findList(); + + log.info(list.toString()); + assertThat(list).isNotEmpty(); + } + + @Test + public void dto_findList_constructorPlusMatch() { + + ResetBasicData.reset(); + + List dtos = server().createNamedDtoQuery(DCust.class, "findListByName") + .setParameter("name", "Rob") + .findList(); + + log.info(dtos.toString()); + assertThat(dtos).isNotEmpty(); + } + + @Test + public void dto_findList_setters() { + + ResetBasicData.reset(); + + DtoQuery dtoQuery = server().createNamedDtoQuery(DCust2.class, "findList"); + + List list = dtoQuery.findList(); + + assertThat(list).isNotEmpty(); + } + + @Test + public void dto3_findList_constructorMatch() { + + ResetBasicData.reset(); + + List robs = server().createNamedDtoQuery(DCust3.class, "findByNameLike") + .setParameter(1, "Rob") + .setMaxRows(10) + .findList(); + + + log.info(robs.toString()); + assertThat(robs).isNotEmpty(); + } + + @Test + public void dto3_findList_settersMatch() { + + ResetBasicData.reset(); + + List robs = server().createNamedDtoQuery(DCust3.class, "findByName") + .setParameter("name", "Rob") + .findList(); + + + log.info(robs.toString()); + assertThat(robs).isNotEmpty(); + } + + public static class DCust { + + final Integer id; + + final String name; + + int totalOrders; + + public DCust(Integer id, String name) { + this.id = id; + this.name = name; + } + + @Override + public String toString() { + return "id:" + id + " name:" + name + " totalOrders:" + totalOrders; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public int getTotalOrders() { + return totalOrders; + } + + public void setTotalOrders(int totalOrders) { + this.totalOrders = totalOrders; + } + } + + public static class DCust2 { + + Integer id; + + String name; + + @Override + public String toString() { + return "id:" + id + " name:" + name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + public static class DCust3 { + + Integer id; + + String name; + + int totalOrders; + + public DCust3() { + } + + public DCust3(Integer id, String name, int totalOrders) { + this.id = id; + this.name = name; + this.totalOrders = totalOrders; + } + + @Override + public String toString() { + return "id:" + id + " name:" + name + " totalOrders:" + totalOrders; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public int getTotalOrders() { + return totalOrders; + } + + public void setTotalOrders(int totalOrders) { + this.totalOrders = totalOrders; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index 5755f6ed5..5f538f9d5 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -48,9 +48,6 @@ import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.query.CQuery; import io.ebeaninternal.server.transaction.RemoteTransactionEvent; - -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; import java.lang.reflect.Type; import java.util.Collection; import java.util.Collections; @@ -61,6 +58,8 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Predicate; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; /** @@ -432,6 +431,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return null; } + @Override + public DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery) { + return null; + } + @Override public DtoQuery findDto(Class dtoType, SpiQuery ormQuery) { return null; diff --git a/src/test/resources/ebean-xml-mappings/DCustMapping.xml b/src/test/resources/ebean-xml-mappings/DCustMapping.xml new file mode 100644 index 000000000..c104f4cd5 --- /dev/null +++ b/src/test/resources/ebean-xml-mappings/DCustMapping.xml @@ -0,0 +1,77 @@ + + + + + + + select id, name from o_customer + + + + + select id, name from o_customer where id > :id + + + + + select id, name from o_customer where id > :id order by id desc + + + + + select id, name from o_customer where name = :name + + + + + select c3.id, c3.name from o_customer c3 where c3.name = :name + + + + + select c4.id, c4.name from o_customer c4 where lower(c4.name) = :name + + + + + select c.id, c.name, count(o.id) as totalOrders + from o_customer c + join o_order o on o.kcustomer_id = c.id + where c.name like :name + group by c.id, c.name + + + + + + + + select id, '42' as something_we_cannot_map, name from o_customer + + + + + select id, name from o_customer + + + + + + + + select id, name, 42 as total, '42' as something_we_cannot_map from o_customer + + + + + select id, name, 42 as totalOrders from o_customer where name like ? + + + + + select id, name from o_customer where name = :name + + + + + From 012322503f05adf86ee9a20d432a925d2bb7ddd3 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Mar 2018 09:03:16 +1300 Subject: [PATCH 0192/1036] #115 - Supporting changes for Element collection support --- .../ebean/common/AbstractBeanCollection.java | 8 ---- .../config/UnderscoreNamingConvention.java | 34 +------------- .../java/io/ebean/util/CamelCaseHelper.java | 46 +++++++++++++++++++ 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/src/main/java/io/ebean/common/AbstractBeanCollection.java b/src/main/java/io/ebean/common/AbstractBeanCollection.java index 866d8d0c0..e4641814a 100644 --- a/src/main/java/io/ebean/common/AbstractBeanCollection.java +++ b/src/main/java/io/ebean/common/AbstractBeanCollection.java @@ -6,7 +6,6 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; -import javax.persistence.PersistenceException; import java.util.Set; /** @@ -96,13 +95,6 @@ abstract class AbstractBeanCollection implements BeanCollection { if (loader == null) { loader = (BeanCollectionLoader) Ebean.getServer(ebeanServerName); } - if (loader == null) { - String msg = "Lazy loading but LazyLoadEbeanServer is null?" - + " The LazyLoadEbeanServer needs to be set after deserialization" - + " to support lazy loading."; - throw new PersistenceException(msg); - } - loader.loadMany(this, onlyIds); checkEmptyLazyLoad(); } diff --git a/src/main/java/io/ebean/config/UnderscoreNamingConvention.java b/src/main/java/io/ebean/config/UnderscoreNamingConvention.java index 8fffed5fb..16b685227 100644 --- a/src/main/java/io/ebean/config/UnderscoreNamingConvention.java +++ b/src/main/java/io/ebean/config/UnderscoreNamingConvention.java @@ -112,39 +112,7 @@ public class UnderscoreNamingConvention extends AbstractNamingConvention { * Convert and return the string to underscore from camel case. */ protected String toUnderscoreFromCamel(String camelCase) { - - int lastUpper = -1; - StringBuilder sb = new StringBuilder(camelCase.length() + 4); - for (int i = 0; i < camelCase.length(); i++) { - char c = camelCase.charAt(i); - - if ('_' == c) { - // Underscores should just be passed through - sb.append(c); - lastUpper = i; - } else if (Character.isDigit(c)) { - if (i > lastUpper + 1 && !digitsCompressed) { - sb.append("_"); - } - sb.append(c); - lastUpper = i; - - } else if (Character.isUpperCase(c)) { - if (i > lastUpper + 1) { - sb.append("_"); - } - sb.append(Character.toLowerCase(c)); - lastUpper = i; - - } else { - sb.append(c); - } - } - String ret = sb.toString(); - if (forceUpperCase) { - ret = ret.toUpperCase(); - } - return ret; + return CamelCaseHelper.toUnderscoreFromCamel(camelCase, digitsCompressed, forceUpperCase); } /** diff --git a/src/main/java/io/ebean/util/CamelCaseHelper.java b/src/main/java/io/ebean/util/CamelCaseHelper.java index 9ef24656a..d3573309e 100644 --- a/src/main/java/io/ebean/util/CamelCaseHelper.java +++ b/src/main/java/io/ebean/util/CamelCaseHelper.java @@ -2,6 +2,52 @@ package io.ebean.util; public class CamelCaseHelper { + /** + * To underscore from camel case using digits compressed true and force upper case false. + */ + public static String toUnderscoreFromCamel(String camelCase) { + return toUnderscoreFromCamel(camelCase, true, false); + } + + /** + * Convert and return the string to underscore from camel case. + */ + public static String toUnderscoreFromCamel(String camelCase, boolean digitsCompressed, boolean forceUpperCase) { + + int lastUpper = -1; + StringBuilder sb = new StringBuilder(camelCase.length() + 4); + for (int i = 0; i < camelCase.length(); i++) { + char c = camelCase.charAt(i); + + if ('_' == c) { + // Underscores should just be passed through + sb.append(c); + lastUpper = i; + } else if (Character.isDigit(c)) { + if (i > lastUpper + 1 && !digitsCompressed) { + sb.append("_"); + } + sb.append(c); + lastUpper = i; + + } else if (Character.isUpperCase(c)) { + if (i > lastUpper + 1) { + sb.append("_"); + } + sb.append(Character.toLowerCase(c)); + lastUpper = i; + + } else { + sb.append(c); + } + } + String ret = sb.toString(); + if (forceUpperCase) { + ret = ret.toUpperCase(); + } + return ret; + } + /** * To camel from underscore. * From c44931ea25fadd6762da81943bef880a5914e967 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Mar 2018 09:04:58 +1300 Subject: [PATCH 0193/1036] #115 - Supporting changes for Element collection support --- .../model/visitor/VisitAllUsing.java | 56 ++++++++++++------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/visitor/VisitAllUsing.java b/src/main/java/io/ebeaninternal/dbmigration/model/visitor/VisitAllUsing.java index e0d13ec04..2ce73123a 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/visitor/VisitAllUsing.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/visitor/VisitAllUsing.java @@ -16,6 +16,14 @@ import java.util.List; */ public class VisitAllUsing { + /** + * Visit a single Descriptor using the given visitor. + */ + public static void visitOne(BeanDescriptor descriptor, BeanPropertyVisitor visitor) { + + new VisitAllUsing().visitProperties(descriptor, visitor); + } + protected final BeanVisitor visitor; protected final List> descriptors; @@ -36,6 +44,11 @@ public class VisitAllUsing { this.descriptors = descriptors; } + private VisitAllUsing() { + this.visitor = null; + this.descriptors = null; + } + public void visitAllBeans() { for (BeanDescriptor desc : descriptors) { if (desc.isBaseTable()) { @@ -51,29 +64,32 @@ public class VisitAllUsing { BeanPropertyVisitor propertyVisitor = visitor.visitBean(desc); if (propertyVisitor != null) { - - BeanProperty idProp = desc.getIdProperty(); - if (idProp != null) { - visit(propertyVisitor, idProp); - } - - BeanPropertyAssocOne unidirectional = desc.getUnidirectional(); - if (unidirectional != null) { - visit(propertyVisitor, unidirectional); - } - - BeanProperty[] propertiesNonTransient = desc.propertiesNonTransient(); - for (BeanProperty p : propertiesNonTransient) { - if (p.isDDLColumn()) { - visit(propertyVisitor, p); - } - } - - visitInheritanceProperties(desc, propertyVisitor); - propertyVisitor.visitEnd(); + visitProperties(desc, propertyVisitor); } } + private void visitProperties(BeanDescriptor desc, BeanPropertyVisitor propertyVisitor) { + BeanProperty idProp = desc.getIdProperty(); + if (idProp != null) { + visit(propertyVisitor, idProp); + } + + BeanPropertyAssocOne unidirectional = desc.getUnidirectional(); + if (unidirectional != null) { + visit(propertyVisitor, unidirectional); + } + + BeanProperty[] propertiesNonTransient = desc.propertiesNonTransient(); + for (BeanProperty p : propertiesNonTransient) { + if (p.isDDLColumn()) { + visit(propertyVisitor, p); + } + } + + visitInheritanceProperties(desc, propertyVisitor); + propertyVisitor.visitEnd(); + } + /** * Visit the property. */ From 74a9019535d0f0355babaac15fb42f7dfc810745 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Mar 2018 14:22:29 +1300 Subject: [PATCH 0194/1036] #115 - Mapping - Add support for @ElementCollection enhancement Initial support - simple List. --- .../io/ebeaninternal/api/LoadManyRequest.java | 5 +- .../model/build/ModelBuildContext.java | 50 ++++ .../model/build/ModelBuildElementTable.java | 34 +++ .../build/ModelBuildIntersectionTable.java | 33 +-- .../build/ModelBuildPropertyVisitor.java | 33 +-- .../service/ProfileOriginNodeUsage.java | 4 +- .../server/core/OrmQueryRequest.java | 15 +- .../server/deploy/BaseCollectionHelp.java | 50 ++++ .../server/deploy/BeanCollectionHelp.java | 3 +- .../deploy/BeanCollectionHelpFactory.java | 8 +- .../server/deploy/BeanDescriptor.java | 137 +++++++--- .../server/deploy/BeanDescriptorElement.java | 24 ++ .../deploy/BeanDescriptorInitContext.java | 32 +++ .../server/deploy/BeanDescriptorManager.java | 80 ++++-- .../server/deploy/BeanListHelp.java | 47 +--- .../server/deploy/BeanListHelpElement.java | 37 +++ .../server/deploy/BeanMapHelp.java | 11 +- .../server/deploy/BeanProperty.java | 32 ++- .../server/deploy/BeanPropertyAssoc.java | 73 ++++- .../server/deploy/BeanPropertyAssocMany.java | 251 ++++------------- .../deploy/BeanPropertyAssocManyJsonHelp.java | 4 +- .../BeanPropertyAssocManyJsonTransient.java | 4 +- .../deploy/BeanPropertyAssocManySqlHelp.java | 258 ++++++++++++++++++ .../server/deploy/BeanPropertyAssocOne.java | 36 +-- .../deploy/BeanPropertySimpleCollection.java | 19 ++ .../server/deploy/BeanSetHelp.java | 41 +-- .../server/deploy/BeanTable.java | 10 + .../server/deploy/DbReadContext.java | 3 +- .../server/deploy/DynamicPropertyBase.java | 16 +- .../server/deploy/ElementEntityBean.java | 81 ++++++ .../server/deploy/FormulaPropertyPath.java | 4 +- .../server/deploy/InheritInfo.java | 2 +- .../server/deploy/id/IdBinder.java | 3 +- .../meta/BeanPropertyElementSetter.java | 26 ++ .../deploy/meta/DeployBeanProperty.java | 14 +- .../meta/DeployBeanPropertyAssocMany.java | 27 ++ .../meta/DeployBeanPropertyAssocOne.java | 9 + .../deploy/parse/AnnotationAssocManys.java | 85 +++++- .../deploy/parse/AnnotationAssocOnes.java | 6 +- .../server/deploy/parse/AnnotationClass.java | 20 +- .../server/deploy/parse/AnnotationFields.java | 13 +- .../server/deploy/parse/AnnotationParser.java | 7 +- .../server/deploy/parse/AnnotationSql.java | 6 +- .../server/deploy/parse/DeployBeanInfo.java | 10 - .../deploy/parse/ReadAnnotationConfig.java | 58 ++++ .../server/deploy/parse/ReadAnnotations.java | 51 +--- .../deploy/parse/TransientProperties.java | 25 +- .../server/loadcontext/DLoadContext.java | 2 +- .../server/loadcontext/DLoadManyContext.java | 2 +- .../server/persist/DefaultPersister.java | 24 +- .../server/persist/SaveManyPropRequest.java | 14 +- .../persist/SaveManySimpleCollection.java | 39 +++ .../io/ebeaninternal/server/query/CQuery.java | 60 ++-- .../server/query/CQueryBuilder.java | 10 +- .../server/query/CQueryCollectionAdd.java | 21 ++ .../server/query/CQueryCollectionAddNoop.java | 27 ++ .../server/query/CQueryPlan.java | 8 +- .../server/query/CQueryPredicates.java | 2 +- .../ebeaninternal/server/query/ExtraJoin.java | 20 ++ ...qlTreeProperty.java => STreeProperty.java} | 14 +- .../server/query/STreePropertyAssoc.java | 39 +++ .../server/query/STreePropertyAssocMany.java | 45 +++ .../server/query/STreePropertyAssocOne.java | 16 ++ .../ebeaninternal/server/query/STreeType.java | 136 +++++++++ .../ebeaninternal/server/query/SqlTree.java | 12 +- .../server/query/SqlTreeAlias.java | 16 +- .../server/query/SqlTreeBuilder.java | 102 +++---- .../server/query/SqlTreeNodeBean.java | 83 +++--- .../server/query/SqlTreeNodeExtraJoin.java | 19 +- .../server/query/SqlTreeNodeManyRoot.java | 5 +- .../query/SqlTreeNodeManyWhereJoin.java | 19 +- .../server/query/SqlTreeNodeRoot.java | 6 +- .../server/query/SqlTreeProperties.java | 12 +- .../server/querydefn/OrmQueryDetail.java | 4 +- .../docstore/api/support/DocStructure.java | 2 +- .../deploy/FormulaPropertyPathTest.java | 4 +- .../org/tests/basic/TestAnnotationBase.java | 16 +- .../model/elementcollection/EcPerson.java | 69 +++++ .../TestElementCollectionBasic.java | 51 ++++ 79 files changed, 1891 insertions(+), 805 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorInitContext.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementEntityBean.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/meta/BeanPropertyElementSetter.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotationConfig.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java create mode 100644 src/main/java/io/ebeaninternal/server/query/CQueryCollectionAdd.java create mode 100644 src/main/java/io/ebeaninternal/server/query/CQueryCollectionAddNoop.java create mode 100644 src/main/java/io/ebeaninternal/server/query/ExtraJoin.java rename src/main/java/io/ebeaninternal/server/query/{SqlTreeProperty.java => STreeProperty.java} (85%) create mode 100644 src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java create mode 100644 src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java create mode 100644 src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java create mode 100644 src/main/java/io/ebeaninternal/server/query/STreeType.java create mode 100644 src/test/java/org/tests/model/elementcollection/EcPerson.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java diff --git a/src/main/java/io/ebeaninternal/api/LoadManyRequest.java b/src/main/java/io/ebeaninternal/api/LoadManyRequest.java index d92ce3222..1b28ed2c3 100644 --- a/src/main/java/io/ebeaninternal/api/LoadManyRequest.java +++ b/src/main/java/io/ebeaninternal/api/LoadManyRequest.java @@ -1,6 +1,5 @@ package io.ebeaninternal.api; -import io.ebean.EbeanServer; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebean.util.StringHelper; @@ -124,11 +123,11 @@ public class LoadManyRequest extends LoadRequest { return loadContext.getBeanProperty(); } - public SpiQuery createQuery(EbeanServer server, int batchSize) { + public SpiQuery createQuery(SpiEbeanServer server, int batchSize) { BeanPropertyAssocMany many = getMany(); - SpiQuery query = (SpiQuery) server.createQuery(many.getTargetType()); + SpiQuery query = many.newQuery(server); String orderBy = many.getLazyFetchOrderBy(); if (orderBy != null) { query.orderBy(orderBy); diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java index c897617a9..9fc213faa 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildContext.java @@ -4,13 +4,18 @@ import io.ebean.config.DbConstraintNaming; import io.ebean.config.dbplatform.DbPlatformType; import io.ebean.config.dbplatform.DbPlatformTypeMapping; import io.ebeaninternal.dbmigration.model.MColumn; +import io.ebeaninternal.dbmigration.model.MCompoundForeignKey; import io.ebeaninternal.dbmigration.model.MTable; import io.ebeaninternal.dbmigration.model.ModelContainer; +import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.TableJoin; +import io.ebeaninternal.server.deploy.TableJoinColumn; import io.ebeaninternal.server.type.ScalarType; import java.util.Collection; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * The context used during DDL generation. @@ -187,4 +192,49 @@ public class ModelBuildContext { addTable(draftTable); } + /** + * Return a builder to add foreign keys. + */ + public FkeyBuilder fkeyBuilder(MTable destTable) { + return new FkeyBuilder(this, destTable); + } + + public static class FkeyBuilder { + + private final AtomicInteger count = new AtomicInteger(); + + private final ModelBuildContext ctx; + + private final MTable destTable; + + private final String tableName; + + FkeyBuilder(ModelBuildContext ctx, MTable destTable) { + this.ctx = ctx; + this.destTable = destTable; + this.tableName = destTable.getName(); + } + + /** + * Add a foreign key based on the table join. + */ + public FkeyBuilder addForeignKey(BeanDescriptor desc, TableJoin tableJoin, boolean direction) { + + String baseTable = ctx.normaliseTable(desc.getBaseTable()); + String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, count.incrementAndGet()); + String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, count.get()); + + MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex); + + for (TableJoinColumn column : tableJoin.columns()) { + String localCol = direction ? column.getForeignDbColumn() : column.getLocalDbColumn(); + String refCol = !direction ? column.getForeignDbColumn() : column.getLocalDbColumn(); + foreignKey.addColumnPair(localCol, refCol); + } + + destTable.addForeignKey(foreignKey); + return this; + } + + } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java new file mode 100644 index 000000000..94a2526a8 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java @@ -0,0 +1,34 @@ +package io.ebeaninternal.dbmigration.model.build; + +import io.ebeaninternal.dbmigration.model.MTable; +import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.BeanTable; + +/** + * Add the element collection table to the model. + */ +public class ModelBuildElementTable { + + /** + * Build and add the MTable model for the ElementCollection property. + */ + public static void build(ModelBuildContext ctx, BeanPropertyAssocMany manyProp) { + + BeanTable beanTable = manyProp.getBeanTable(); + + BeanDescriptor targetDescriptor = manyProp.getTargetDescriptor(); + + MTable table = new MTable(beanTable.getBaseTable()); + + VisitAllUsing.visitOne(targetDescriptor, new ModelBuildPropertyVisitor(ctx, table, targetDescriptor)); + + ctx.fkeyBuilder(table) + .addForeignKey(manyProp.getBeanDescriptor(), manyProp.getTableJoin(), true); + + ctx.addTable(table); + } + + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java index 9bf4d50c0..6772e57d6 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildIntersectionTable.java @@ -1,7 +1,6 @@ package io.ebeaninternal.dbmigration.model.build; import io.ebeaninternal.dbmigration.model.MColumn; -import io.ebeaninternal.dbmigration.model.MCompoundForeignKey; import io.ebeaninternal.dbmigration.model.MTable; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; @@ -12,7 +11,7 @@ import io.ebeaninternal.server.deploy.TableJoinColumn; /** * Add the intersection table to the model. */ -public class ModelBuildIntersectionTable { +class ModelBuildIntersectionTable { private final ModelBuildContext ctx; @@ -22,9 +21,7 @@ public class ModelBuildIntersectionTable { private MTable intersectionTable; - private int countForeignKey; - - public ModelBuildIntersectionTable(ModelBuildContext ctx, BeanPropertyAssocMany manyProp) { + ModelBuildIntersectionTable(ModelBuildContext ctx, BeanPropertyAssocMany manyProp) { this.ctx = ctx; this.manyProp = manyProp; this.intersectionTableJoin = manyProp.getIntersectionTableJoin(); @@ -51,33 +48,13 @@ public class ModelBuildIntersectionTable { private void buildFkConstraints() { - BeanDescriptor localDesc = manyProp.getBeanDescriptor(); - buildFkConstraints(localDesc, intersectionTableJoin.columns(), true); - - BeanDescriptor targetDesc = manyProp.getTargetDescriptor(); - buildFkConstraints(targetDesc, tableJoin.columns(), false); + ctx.fkeyBuilder(intersectionTable) + .addForeignKey(manyProp.getBeanDescriptor(), intersectionTableJoin, true) + .addForeignKey(manyProp.getTargetDescriptor(), tableJoin, false); intersectionTable.checkDuplicateForeignKeys(); } - - private void buildFkConstraints(BeanDescriptor desc, TableJoinColumn[] columns, boolean direction) { - - String tableName = intersectionTableJoin.getTable(); - String baseTable = ctx.normaliseTable(desc.getBaseTable()); - String fkName = ctx.foreignKeyConstraintName(tableName, baseTable, ++countForeignKey); - String fkIndex = ctx.foreignKeyIndexName(tableName, baseTable, countForeignKey); - - MCompoundForeignKey foreignKey = new MCompoundForeignKey(fkName, desc.getBaseTable(), fkIndex); - intersectionTable.addForeignKey(foreignKey); - - for (TableJoinColumn column : columns) { - String localCol = direction ? column.getForeignDbColumn() : column.getLocalDbColumn(); - String refCol = !direction ? column.getForeignDbColumn() : column.getLocalDbColumn(); - foreignKey.addColumnPair(localCol, refCol); - } - } - private MTable createTable() { BeanDescriptor localDesc = manyProp.getBeanDescriptor(); diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java index dc9bc4692..c1ad11197 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildPropertyVisitor.java @@ -123,27 +123,24 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor { @Override public void visitMany(BeanPropertyAssocMany p) { - if (p.hasJoinTable()) { - if (p.getMappedBy() == null) { - // only create on other 'owning' side + if (p.hasJoinTable() && p.getMappedBy() == null) { + // only create on other 'owning' side - //TableJoin intersectionTableJoin = p.getIntersectionTableJoin(); - // check if the intersection table has already been created - - // build the create table and fkey constraints - // putting the DDL into ctx for later output as we are - // in the middle of rendering the create table DDL - MTable intersectionTable = new ModelBuildIntersectionTable(ctx, p).build(); - if (p.isO2mJoinTable()) { - intersectionTable.clearForeignKeyIndexes(); - Collection cols = intersectionTable.allColumns(); - if (cols.size() == 2) { - // always the second column that we put the unique constraint on - MColumn col = new ArrayList<>(cols).get(1); - col.setUnique(determineUniqueConstraintName(col.getName())); - } + // build the create table and fkey constraints + // putting the DDL into ctx for later output as we are + // in the middle of rendering the create table DDL + MTable intersectionTable = new ModelBuildIntersectionTable(ctx, p).build(); + if (p.isO2mJoinTable()) { + intersectionTable.clearForeignKeyIndexes(); + Collection cols = intersectionTable.allColumns(); + if (cols.size() == 2) { + // always the second column that we put the unique constraint on + MColumn col = new ArrayList<>(cols).get(1); + col.setUnique(determineUniqueConstraintName(col.getName())); } } + } else if (p.isElementCollection()) { + ModelBuildElementTable.build(ctx, p); } } diff --git a/src/main/java/io/ebeaninternal/server/autotune/service/ProfileOriginNodeUsage.java b/src/main/java/io/ebeaninternal/server/autotune/service/ProfileOriginNodeUsage.java index 391db0366..9b9ebc50c 100644 --- a/src/main/java/io/ebeaninternal/server/autotune/service/ProfileOriginNodeUsage.java +++ b/src/main/java/io/ebeaninternal/server/autotune/service/ProfileOriginNodeUsage.java @@ -2,11 +2,11 @@ package io.ebeaninternal.server.autotune.service; import io.ebean.bean.NodeUsageCollector; import io.ebean.text.PathProperties; +import io.ebean.util.SplitName; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssoc; import io.ebeaninternal.server.el.ElPropertyValue; -import io.ebean.util.SplitName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +56,7 @@ public class ProfileOriginNodeUsage { } for (String propName : aggregateUsed) { - BeanProperty beanProp = desc.getBeanPropertyFromPath(propName); + BeanProperty beanProp = desc.findPropertyFromPath(propName); if (beanProp == null) { logger.warn("AutoTune: Can't find property[" + propName + "] for " + desc.getName()); diff --git a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java index 5a9e3f6a8..ed09fdb20 100644 --- a/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/OrmQueryRequest.java @@ -79,6 +79,8 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery private List cacheBeans; + private BeanPropertyAssocMany manyProperty; + /** * Create the InternalQueryRequest. */ @@ -496,11 +498,18 @@ public final class OrmQueryRequest extends BeanRequest implements SpiOrmQuery } /** - * Return the many property that is fetched in the query or null if there is - * not one. + * Determine and return the ToMany property that is included in the query. + */ + public BeanPropertyAssocMany determineMany() { + manyProperty = beanDescriptor.getManyProperty(query); + return manyProperty; + } + + /** + * Return the many property that is fetched in the query or null if there is not one. */ public BeanPropertyAssocMany getManyProperty() { - return beanDescriptor.getManyProperty(query); + return manyProperty; } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java index 5e50e9700..4d8dbda97 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java @@ -1,11 +1,47 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; +import io.ebean.bean.BeanCollectionLoader; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import java.io.IOException; import java.util.Collection; abstract class BaseCollectionHelp implements BeanCollectionHelp { + final BeanPropertyAssocMany many; + final BeanDescriptor targetDescriptor; + final String propertyName; + + BeanCollectionLoader loader; + + BaseCollectionHelp(BeanPropertyAssocMany many) { + this.many = many; + this.targetDescriptor = many.getTargetDescriptor(); + this.propertyName = many.getName(); + } + + BaseCollectionHelp() { + this.many = null; + this.targetDescriptor = null; + this.propertyName = null; + } + + @Override + public void setLoader(BeanCollectionLoader loader) { + this.loader = loader; + } + + @Override + public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { + if (withCheck) { + collection.internalAddWithCheck(bean); + } else { + collection.internalAdd(bean); + } + } + @Override public Collection underlying(Object value) { if (value instanceof BeanCollection) { @@ -14,4 +50,18 @@ abstract class BaseCollectionHelp implements BeanCollectionHelp { return (Collection)value; } } + + void jsonWriteCollection(SpiJsonWriter ctx, String name, Collection list) throws IOException { + if (!list.isEmpty() || ctx.isIncludeEmpty()) { + ctx.beginAssocMany(name); + for (Object bean : list) { + jsonWriteElement(ctx, bean); + } + ctx.endAssocMany(); + } + } + + void jsonWriteElement(SpiJsonWriter ctx, Object bean) throws IOException { + targetDescriptor.jsonWrite(ctx, (EntityBean) bean); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java index 8891048bb..569e22403 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java @@ -7,6 +7,7 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.query.CQueryCollectionAdd; import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; @@ -15,7 +16,7 @@ import java.util.Collection; /** * Helper functions for performing tasks on Lists Sets or Maps. */ -public interface BeanCollectionHelp { +public interface BeanCollectionHelp extends CQueryCollectionAdd { /** * Set the EbeanServer that owns the configuration. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java index 2ba289d75..f74a67243 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java @@ -20,10 +20,12 @@ public class BeanCollectionHelpFactory { */ public static BeanCollectionHelp create(BeanPropertyAssocMany manyProperty) { + boolean elementCollection = manyProperty.isElementCollection(); + ManyType manyType = manyProperty.getManyType(); switch (manyType) { case LIST: - return new BeanListHelp<>(manyProperty); + return elementCollection ? new BeanListHelpElement<>(manyProperty) : new BeanListHelp<>(manyProperty); case SET: return new BeanSetHelp<>(manyProperty); case MAP: @@ -35,9 +37,7 @@ public class BeanCollectionHelpFactory { } @SuppressWarnings("unchecked") - public static BeanCollectionHelp create(OrmQueryRequest request) { - - SpiQuery.Type manyType = request.getQuery().getType(); + public static BeanCollectionHelp create(SpiQuery.Type manyType, OrmQueryRequest request) { if (manyType == SpiQuery.Type.LIST) { return LIST_HELP; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 8ba1b5ae6..a7614cbba 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -62,7 +62,13 @@ import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.DmlUtil; import io.ebeaninternal.server.query.CQueryPlan; -import io.ebeaninternal.server.query.SqlTreeProperty; +import io.ebeaninternal.server.query.ExtraJoin; +import io.ebeaninternal.server.query.STreeProperty; +import io.ebeaninternal.server.query.STreePropertyAssoc; +import io.ebeaninternal.server.query.STreePropertyAssocMany; +import io.ebeaninternal.server.query.STreePropertyAssocOne; +import io.ebeaninternal.server.query.STreeType; +import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.text.json.ReadJson; @@ -100,7 +106,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * Describes Beans including their deployment information. */ -public class BeanDescriptor implements BeanType { +public class BeanDescriptor implements BeanType, STreeType { private static final Logger logger = LoggerFactory.getLogger(BeanDescriptor.class); @@ -114,7 +120,7 @@ public class BeanDescriptor implements BeanType { private final ConcurrentHashMap> comparatorCache = new ConcurrentHashMap<>(); - private final ConcurrentHashMap dynamicProperty = new ConcurrentHashMap<>(); + private final ConcurrentHashMap dynamicProperty = new ConcurrentHashMap<>(); private final Map namedRawSql; @@ -239,7 +245,7 @@ public class BeanDescriptor implements BeanType { private final BeanDescriptorMap owner; - private final String[] properties; + final String[] properties; /** * Intercept pre post on insert,update, and delete . @@ -601,7 +607,7 @@ public class BeanDescriptor implements BeanType { /** * Create an entity bean that is used as a prototype/factory to create new instances. */ - private EntityBean createPrototypeEntityBean(Class beanType) { + protected EntityBean createPrototypeEntityBean(Class beanType) { if (Modifier.isAbstract(beanType.getModifiers())) { return null; } @@ -662,21 +668,19 @@ public class BeanDescriptor implements BeanType { * These properties need to be initialised prior to the association properties * as they are used to get the imported and exported properties. *

    - * - * @param withHistoryTables map populated if @History is supported on this entity bean */ - public void initialiseId(Map withHistoryTables, Map draftTables) { + public void initialiseId(BeanDescriptorInitContext initContext) { if (logger.isTraceEnabled()) { logger.trace("BeanDescriptor initialise " + fullName); } if (draftable) { - draftTables.put(baseTable, draftTable); + initContext.addDraft(baseTable, draftTable); } if (historySupport) { // add mapping (used to swap out baseTable for asOf queries) - withHistoryTables.put(baseTable, baseTableAsOf); + initContext.addHistory(baseTable, baseTableAsOf); } if (inheritInfo != null) { @@ -686,28 +690,24 @@ public class BeanDescriptor implements BeanType { if (isEmbedded()) { // initialise all the properties for (BeanProperty prop : propertiesAll()) { - prop.initialise(); + prop.initialise(initContext); } } else { // initialise just the Id properties if (idProperty != null) { - idProperty.initialise(); + idProperty.initialise(initContext); } } } /** * Initialise the exported and imported parts for associated properties. - * - * @param asOfTableMap the map of base tables to associated 'with history' tables - * @param asOfViewSuffix the suffix added to the table name to derive the 'with history' view name - * @param draftTableMap the map of base tables to associated 'draft' tables. */ - public void initialiseOther(Map asOfTableMap, String asOfViewSuffix, Map draftTableMap) { + public void initialiseOther(BeanDescriptorInitContext initContext) { - for (BeanPropertyAssocMany aPropertiesManyToMany1 : propertiesManyToMany) { + for (BeanPropertyAssocMany many : propertiesManyToMany) { // register associated draft table for M2M intersection - aPropertiesManyToMany1.registerDraftIntersectionTable(draftTableMap); + many.registerDraftIntersectionTable(initContext); } if (historySupport) { @@ -717,8 +717,7 @@ public class BeanDescriptor implements BeanType { // register associated history table for M2M intersection if (!aPropertiesManyToMany.isExcludedFromHistory()) { TableJoin intersectionTableJoin = aPropertiesManyToMany.getIntersectionTableJoin(); - String intersectionTableName = intersectionTableJoin.getTable(); - asOfTableMap.put(intersectionTableName, intersectionTableName + asOfViewSuffix); + initContext.addHistoryIntersection(intersectionTableJoin.getTable()); } } } @@ -727,14 +726,14 @@ public class BeanDescriptor implements BeanType { // initialise all the non-id properties for (BeanProperty prop : propertiesAll()) { if (!prop.isId()) { - prop.initialise(); + prop.initialise(initContext); } prop.registerColumn(this, null); } } if (unidirectional != null) { - unidirectional.initialise(); + unidirectional.initialise(initContext); } idBinder.initialise(); @@ -799,7 +798,7 @@ public class BeanDescriptor implements BeanType { if (propName == null) { return; } - props[i] = findBeanProperty(propName); + props[i] = findProperty(propName); } if (props.length == 1) { for (BeanProperty[] inserted : propertiesUnique) { @@ -1639,6 +1638,7 @@ public class BeanDescriptor implements BeanType { /** * Execute the postLoad if a BeanPostLoad exists for this bean. */ + @Override public void postLoad(Object bean) { if (beanPostLoad != null) { beanPostLoad.postLoad(bean); @@ -1787,6 +1787,11 @@ public class BeanDescriptor implements BeanType { return idBinder instanceof IdBinderSimple; } + @Override + public boolean hasId() { + return idProperty != null; + } + /** * Return true if this type has a simple Id and the platform supports mutli-value binding. */ @@ -1951,7 +1956,8 @@ public class BeanDescriptor implements BeanType { * Return the bean property traversing the object graph and taking into * account inheritance. */ - public BeanProperty getBeanPropertyFromPath(String path) { + @Override + public BeanProperty findPropertyFromPath(String path) { BeanDescriptor other = this; while (true) { @@ -1983,7 +1989,7 @@ public class BeanDescriptor implements BeanType { } String[] splitBegin = SplitName.splitBegin(path); - BeanProperty beanProperty = result.findBeanProperty(splitBegin[0]); + BeanProperty beanProperty = result.findProperty(splitBegin[0]); if (beanProperty instanceof BeanPropertyAssoc) { BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; path = splitBegin[1]; @@ -2224,7 +2230,7 @@ public class BeanDescriptor implements BeanType { @Override public Property getProperty(String propName) { - return findBeanProperty(propName); + return findProperty(propName); } /** @@ -2458,7 +2464,7 @@ public class BeanDescriptor implements BeanType { /** * Return a 'dynamic property' used to read a formula. */ - private SqlTreeProperty findSqlTreeFormula(String formulaExpression) { + private STreeProperty findSqlTreeFormula(String formulaExpression) { return dynamicProperty.computeIfAbsent(formulaExpression, (formula) -> new FormulaPropertyPath(this, formula).build()); } @@ -2468,7 +2474,8 @@ public class BeanDescriptor implements BeanType { * * The property can be a dynamic formula or a well known bean property. */ - public SqlTreeProperty findSqlTreeProperty(String propName) { + @Override + public STreeProperty findPropertyWithDynamic(String propName) { if (propName.indexOf('(') > -1) { return findSqlTreeFormula(propName); } @@ -2482,7 +2489,8 @@ public class BeanDescriptor implements BeanType { * inheritance tree (not up). *

    */ - public BeanProperty findBeanProperty(String propName) { + @Override + public BeanProperty findProperty(String propName) { int basePos = propName.indexOf('.'); if (basePos > -1) { // embedded property @@ -2540,6 +2548,10 @@ public class BeanDescriptor implements BeanType { return autoTunable; } + public boolean isElementType() { + return false; + } + /** * Returns the Inheritance mapping information. This will be null if this type * of bean is not involved in any ORM inheritance mapping. @@ -2809,6 +2821,41 @@ public class BeanDescriptor implements BeanType { return draftableElement; } + @Override + public boolean isEmbeddedPath(String propertyPath) { + ElPropertyDeploy elProp = getElPropertyDeploy(propertyPath); + if (elProp == null) { + throw new PersistenceException("Invalid path " + propertyPath + " from " + getFullName()); + } + return elProp.getBeanProperty().isEmbedded(); + } + + @Override + public ExtraJoin extraJoin(String propertyPath) { + + ElPropertyValue elGetValue = getElGetValue(propertyPath); + if (elGetValue != null) { + BeanProperty beanProperty = elGetValue.getBeanProperty(); + if (beanProperty instanceof BeanPropertyAssoc) { + BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; + if (!assocProp.isEmbedded()) { + return new ExtraJoin(assocProp, elGetValue.containsMany()); + } + } + } + return null; + } + + @Override + public void inheritanceLoad(SqlBeanLoad sqlBeanLoad, STreeProperty property, DbReadContext ctx) { + BeanProperty p = getBeanProperty(property.getName()); + if (p != null) { + p.load(sqlBeanLoad); + } else { + property.loadIgnore(ctx); + } + } + public void setUnmappedJson(EntityBean bean, Map unmappedProperties) { if (unmappedJson != null) { unmappedJson.setValueIntercept(bean, unmappedProperties); @@ -2933,16 +2980,6 @@ public class BeanDescriptor implements BeanType { return selectLastInsertedId; } - /** - * Return the TableJoins. - *

    - * For properties mapped to secondary tables rather than the base table. - *

    - */ - public TableJoin[] tableJoins() { - return derivedTableJoins; - } - @Override public Collection allProperties() { return propertiesAll(); @@ -3131,6 +3168,26 @@ public class BeanDescriptor implements BeanType { } } + @Override + public STreeProperty[] propsBaseScalar() { + return propertiesBaseScalar; + } + + @Override + public STreePropertyAssoc[] propsEmbedded() { + return propertiesEmbedded; + } + + @Override + public STreePropertyAssocOne[] propsOne() { + return propertiesOne; + } + + @Override + public STreePropertyAssocMany[] propsMany() { + return propertiesMany; + } + /** * All the BeanPropertyAssocOne that are not embedded. These are effectively * joined beans. For ManyToOne and OneToOne associations. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java new file mode 100644 index 000000000..dd793505c --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java @@ -0,0 +1,24 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; + +/** + * Bean descriptor used with ElementCollection (where we don't have a mapped type/class). + */ +public class BeanDescriptorElement extends BeanDescriptor { + + public BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor deploy) { + super(owner, deploy); + } + + public boolean isElementType() { + return true; + } + + @Override + protected EntityBean createPrototypeEntityBean(Class beanType) { + return new ElementEntityBean(properties); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorInitContext.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorInitContext.java new file mode 100644 index 000000000..ef367199d --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorInitContext.java @@ -0,0 +1,32 @@ +package io.ebeaninternal.server.deploy; + +import java.util.Map; + +class BeanDescriptorInitContext { + + private final Map withHistoryTables; + private final Map draftTables; + private final String asOfViewSuffix; + + BeanDescriptorInitContext(Map withHistoryTables, Map draftTables, String asOfViewSuffix) { + this.withHistoryTables = withHistoryTables; + this.draftTables = draftTables; + this.asOfViewSuffix = asOfViewSuffix; + } + + void addDraft(String baseTable, String draftTable) { + draftTables.put(baseTable, draftTable); + } + + void addHistory(String baseTable, String baseTableAsOf) { + withHistoryTables.put(baseTable, baseTableAsOf); + } + + void addHistoryIntersection(String intersectionTableName) { + withHistoryTables.put(intersectionTableName, intersectionTableName + asOfViewSuffix); + } + + void addDraftIntersection(String intersectionPublishTable, String intersectionDraftTable) { + draftTables.put(intersectionPublishTable, intersectionDraftTable); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 6bd12fda2..5824612bd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -184,8 +184,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private final BeanLifecycleAdapterFactory beanLifecycleAdapterFactory; - private final boolean eagerFetchLobs; - private final String asOfViewSuffix; /** @@ -215,12 +213,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap { this.databasePlatform = serverConfig.getDatabasePlatform(); this.multiValueBind = config.getMultiValueBind(); this.idBinderFactory = new IdBinderFactory(databasePlatform.isIdInExpandedForm(), multiValueBind); - this.eagerFetchLobs = serverConfig.isEagerFetchLobs(); this.queryPlanTTLSeconds = serverConfig.getQueryPlanTTLSeconds(); this.asOfViewSuffix = getAsOfViewSuffix(databasePlatform, serverConfig); String versionsBetweenSuffix = getVersionsBetweenSuffix(databasePlatform, serverConfig); - this.readAnnotations = new ReadAnnotations(config.getGeneratedPropertyFactory(), asOfViewSuffix, versionsBetweenSuffix, serverConfig.isDisableL2Cache()); + this.readAnnotations = new ReadAnnotations(config.getGeneratedPropertyFactory(), asOfViewSuffix, versionsBetweenSuffix, serverConfig); this.bootupClasses = config.getBootupClasses(); this.createProperties = config.getDeployCreateProperties(); this.namingConvention = serverConfig.getNamingConvention(); @@ -575,12 +572,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // we can initialise them which sorts out circular // dependencies for OneToMany and ManyToOne etc + BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix); + // PASS 1: // initialise the ID properties of all the beans // first (as they are needed to initialise the // associated properties in the second pass). for (BeanDescriptor d : descMap.values()) { - d.initialiseId(asOfTableMap, draftTableMap); + d.initialiseId(initContext); } // PASS 2: @@ -595,7 +594,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // also look for intersection tables with // associated history support and register them // into the asOfTableMap - d.initialiseOther(asOfTableMap, asOfViewSuffix, draftTableMap); + d.initialiseOther(initContext); } // PASS 4: @@ -656,6 +655,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return beanTableMap.get(type); } + /** + * Return a BeanTable for an ElementCollection. + */ + public BeanTable getCollectionBeanTable(String fullTableName, Class targetType) { + return new BeanTable(this, fullTableName, targetType); + } + @SuppressWarnings("unchecked") public BeanManager getBeanManager(Class entityType) { @@ -1025,7 +1031,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { *

    */ @SuppressWarnings({"unchecked", "rawtypes"}) - private void makeUnidirectional(DeployBeanInfo info, DeployBeanPropertyAssocMany oneToMany) { + private void makeUnidirectional(DeployBeanPropertyAssocMany oneToMany) { DeployBeanDescriptor targetDesc = getTargetDescriptor(oneToMany); @@ -1045,34 +1051,36 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // mark this property as unidirectional oneToMany.setUnidirectional(); - // create the 'shadow' unidirectional property - // which is put on the target descriptor - DeployBeanPropertyAssocOne unidirectional = new DeployBeanPropertyAssocOne(targetDesc, owningType); - unidirectional.setUndirectionalShadow(); - unidirectional.setNullable(false); - unidirectional.setDbRead(true); - unidirectional.setDbInsertable(true); - unidirectional.setDbUpdateable(false); - - targetDesc.setUnidirectional(unidirectional); - // specify table and table alias... BeanTable beanTable = getBeanTable(owningType); - unidirectional.setBeanTable(beanTable); - unidirectional.setName(beanTable.getBaseTable()); - - info.setBeanJoinType(unidirectional, true); // define the TableJoin DeployTableJoin oneToManyJoin = oneToMany.getTableJoin(); if (!oneToManyJoin.hasJoinColumns()) { throw new RuntimeException("No join columns"); } + createUnidirectional(targetDesc, owningType, beanTable, oneToManyJoin); + } - // inverse of the oneToManyJoin - DeployTableJoin unidirectionalJoin = unidirectional.getTableJoin(); - unidirectionalJoin.setColumns(oneToManyJoin.columns(), true); + /** + * Create and add a Unidirectional property (for ElementCollection) which maps to the foreign key. + */ + public void createUnidirectional(DeployBeanDescriptor targetDesc, Class targetType, BeanTable beanTable, DeployTableJoin oneToManyJoin) { + // create the 'shadow' unidirectional property + // which is put on the target descriptor + DeployBeanPropertyAssocOne unidirectional = new DeployBeanPropertyAssocOne<>(targetDesc, targetType); + unidirectional.setUndirectionalShadow(); + unidirectional.setNullable(false); + unidirectional.setDbRead(true); + unidirectional.setDbInsertable(true); + unidirectional.setDbUpdateable(false); + unidirectional.setBeanTable(beanTable); + unidirectional.setName(beanTable.getBaseTable()); + unidirectional.setJoinType(true); + unidirectional.setJoinColumns(oneToManyJoin.columns(), true); + + targetDesc.setUnidirectional(unidirectional); } private void checkMappedByOneToOne(DeployBeanPropertyAssocOne prop) { @@ -1137,6 +1145,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ private void checkMappedByOneToMany(DeployBeanInfo info, DeployBeanPropertyAssocMany prop) { + if (prop.isElementCollection()) { + // skip mapping check + return; + } DeployBeanDescriptor targetDesc = getTargetDescriptor(prop); if (targetDesc.isDraftableElement()) { @@ -1159,7 +1171,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { if (!findMappedBy(prop)) { if (!prop.isO2mJoinTable()) { - makeUnidirectional(info, prop); + makeUnidirectional(prop); } return; } @@ -1311,7 +1323,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { DeployBeanInfo info = new DeployBeanInfo<>(deployUtil, desc); - readAnnotations.readInitial(info, eagerFetchLobs); + readAnnotations.readInitial(info); return info; } @@ -1636,6 +1648,20 @@ public class BeanDescriptorManager implements BeanDescriptorMap { target.setPrimaryKeyJoin(inverseJoin); } + /** + * Create a DeployBeanDescriptor for an ElementCollection target. + */ + public DeployBeanDescriptor createDeployDescriptor(Class targetType) { + return new DeployBeanDescriptor<>(this, targetType, serverConfig); + } + + /** + * Create a BeanDescriptor for an ElementCollection target. + */ + public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor) { + return new BeanDescriptorElement<>(this, elementDescriptor); + } + public void visitMetrics(MetricVisitor visitor) { for (BeanDescriptor desc : immutableDescriptorList) { desc.visitMetrics(visitor); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java index df5429233..338bfb5a9 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java @@ -5,7 +5,6 @@ import io.ebean.Query; import io.ebean.Transaction; import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; -import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; import io.ebean.common.BeanList; import io.ebeaninternal.server.text.json.SpiJsonWriter; @@ -17,48 +16,20 @@ import java.util.List; /** * Helper object for dealing with Lists. */ -public final class BeanListHelp extends BaseCollectionHelp { +public class BeanListHelp extends BaseCollectionHelp { - private final BeanPropertyAssocMany many; - private final BeanDescriptor targetDescriptor; - private final String propertyName; - - private BeanCollectionLoader loader; - - public BeanListHelp(BeanPropertyAssocMany many) { - this.many = many; - this.targetDescriptor = many.getTargetDescriptor(); - this.propertyName = many.getName(); + BeanListHelp(BeanPropertyAssocMany many) { + super(many); } - public BeanListHelp() { - this.many = null; - this.targetDescriptor = null; - this.propertyName = null; - } - - @Override - public void setLoader(BeanCollectionLoader loader) { - this.loader = loader; - } - - /** - * Internal add bypassing any modify listening. - */ - @Override - public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { - if (withCheck) { - collection.internalAddWithCheck(bean); - } else { - collection.internalAdd(bean); - } + BeanListHelp() { + super(); } @Override public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) { if (bc instanceof BeanList) { - BeanList bl = (BeanList) bc; if (bl.getActualList() == null) { bl.setActualList(new ArrayList<>()); @@ -144,13 +115,7 @@ public final class BeanListHelp extends BaseCollectionHelp { list = (List) collection; } - if (!list.isEmpty() || ctx.isIncludeEmpty()) { - ctx.beginAssocMany(name); - for (Object aList : list) { - targetDescriptor.jsonWrite(ctx, (EntityBean) aList); - } - ctx.endAssocMany(); - } + jsonWriteCollection(ctx, name, list); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java new file mode 100644 index 000000000..2a0b4de96 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java @@ -0,0 +1,37 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.BeanCollectionAdd; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.text.json.SpiJsonWriter; + +/** + * Helper for element collection List. + */ +public class BeanListHelpElement extends BeanListHelp { + + BeanListHelpElement(BeanPropertyAssocMany many) { + super(many); + } + + @Override + public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { + Object elementValue = bean._ebean_getField(0); + if (withCheck) { + collection.internalAddWithCheck(elementValue); + } else { + collection.internalAdd(elementValue); + } + } + + @Override + public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) { + return super.getBeanCollectionAdd(bc, mapKey); + } + + @Override + void jsonWriteElement(SpiJsonWriter ctx, Object element) { + many.jsonWriteValue(ctx, element); + //targetDescriptor.jsonWrite(ctx, (EntityBean) element); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java index e3b42bea7..4c4e76190 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java @@ -5,7 +5,6 @@ import io.ebean.Query; import io.ebean.Transaction; import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; -import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; import io.ebean.common.BeanMap; import io.ebeaninternal.server.text.json.SpiJsonWriter; @@ -24,12 +23,11 @@ public final class BeanMapHelp extends BaseCollectionHelp { private final BeanDescriptor targetDescriptor; private final String propertyName; private final BeanProperty beanProperty; - private BeanCollectionLoader loader; /** * When created for a given query that will return a map. */ - public BeanMapHelp(BeanDescriptor targetDescriptor, String mapKey) { + BeanMapHelp(BeanDescriptor targetDescriptor, String mapKey) { this.targetDescriptor = targetDescriptor; this.beanProperty = targetDescriptor.getBeanProperty(mapKey); this.many = null; @@ -39,18 +37,13 @@ public final class BeanMapHelp extends BaseCollectionHelp { /** * When help is attached to a specific many property. */ - public BeanMapHelp(BeanPropertyAssocMany many) { + BeanMapHelp(BeanPropertyAssocMany many) { this.many = many; this.targetDescriptor = many.getTargetDescriptor(); this.propertyName = many.getName(); this.beanProperty = targetDescriptor.getBeanProperty(many.getMapKey()); } - @Override - public void setLoader(BeanCollectionLoader loader) { - this.loader = loader; - } - @Override @SuppressWarnings("unchecked") public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index a7260f269..5ea987763 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -22,9 +22,9 @@ import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.properties.BeanPropertyGetter; import io.ebeaninternal.server.properties.BeanPropertySetter; +import io.ebeaninternal.server.query.STreeProperty; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; -import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.DataBind; @@ -56,7 +56,7 @@ import java.util.Set; * Description of a property of a bean. Includes its deployment information such * as database column mapping information. */ -public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty { +public class BeanProperty implements ElPropertyValue, Property, STreeProperty { private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class); @@ -455,11 +455,10 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty * initialise variables that can't be done in construction due to recursive * issues. */ - public void initialise() { + public void initialise(BeanDescriptorInitContext initContext) { // do nothing for normal BeanProperty if (!isTransient && scalarType == null) { - String msg = "No ScalarType assigned to " + descriptor.getFullName() + "." + getName(); - throw new RuntimeException(msg); + throw new RuntimeException("No ScalarType assigned to " + descriptor.getFullName() + "." + getName()); } } @@ -505,6 +504,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty /** * Return true if this property is based on a formula. */ + @Override public boolean isFormula() { return formula; } @@ -530,6 +530,11 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty return descriptor.getEncryptKey(this); } + @Override + public String getEncryptKeyAsString() { + return getEncryptKey().getStringValue(); + } + public String getDecryptProperty(String propertyName) { return dbEncryptFunction.getDecryptSql(propertyName); } @@ -552,6 +557,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty * Add any extra joins required to support this property. Generally a no * operation except for a OneToOne exported. */ + @Override public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { if (formula && sqlFormulaJoin != null) { ctx.appendFormulaJoin(sqlFormulaJoin, joinType); @@ -576,6 +582,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty return aggregation != null; } + @Override public void appendSelect(DbSqlContext ctx, boolean subQuery) { if (aggregation != null) { @@ -586,8 +593,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty } else if (!isTransient && !ignoreDraftOnlyProperty(ctx.isDraftQuery())) { if (secondaryTableJoin != null) { - String relativePrefix = ctx.getRelativePrefix(secondaryTableJoinPrefix); - ctx.pushTableAlias(relativePrefix); + ctx.pushTableAlias(ctx.getRelativePrefix(secondaryTableJoinPrefix)); } if (dbEncrypted) { @@ -614,14 +620,17 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty return owningType.isAssignableFrom(type); } + @Override public void loadIgnore(DbReadContext ctx) { scalarType.loadIgnore(ctx.getDataReader()); } + @Override public void load(SqlBeanLoad sqlBeanLoad) { sqlBeanLoad.load(this); } + @Override public void buildRawSqlSelectChain(String prefix, List selectChain) { if (prefix == null) { selectChain.add(name); @@ -808,13 +817,6 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty setValue(bean, cacheData); } - /** - * Get the property value from a compound value type. - */ - public Object getValueObject(Object bean) { - throw new RuntimeException("Expected to be called only on BeanPropertyCompoundScalar"); - } - @Override public Object getVal(Object bean) { return getValue((EntityBean) bean); @@ -1368,6 +1370,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty /** * Return true if this is included in the unique id. */ + @Override public boolean isId() { return id; } @@ -1376,6 +1379,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty * Return true if this is an Embedded property. In this case it shares the * table and primary key of its owner object. */ + @Override public boolean isEmbedded() { return embedded; } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java index 656f5d0bc..cbe81bcbb 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java @@ -1,10 +1,11 @@ package io.ebeaninternal.server.deploy; -import io.ebean.EbeanServer; import io.ebean.Query; import io.ebean.bean.EntityBean; import io.ebean.text.PathProperties; import io.ebean.util.SplitName; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.DefaultSqlUpdate; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.id.IdBinder; @@ -15,7 +16,10 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc; import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.MultiValueWrapper; +import io.ebeaninternal.server.query.STreePropertyAssoc; +import io.ebeaninternal.server.query.STreeType; import io.ebeaninternal.server.query.SqlJoinType; +import io.ebeaninternal.server.querydefn.DefaultOrmQuery; import io.ebeanservice.docstore.api.mapping.DocMappingBuilder; import io.ebeanservice.docstore.api.mapping.DocPropertyMapping; import io.ebeanservice.docstore.api.mapping.DocPropertyType; @@ -30,7 +34,7 @@ import java.util.List; /** * Abstract base for properties mapped to an associated bean, list, set or map. */ -public abstract class BeanPropertyAssoc extends BeanProperty { +public abstract class BeanPropertyAssoc extends BeanProperty implements STreePropertyAssoc { private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssoc.class); @@ -101,15 +105,18 @@ public abstract class BeanPropertyAssoc extends BeanProperty { * Initialise post construction. */ @Override - public void initialise() { + public void initialise(BeanDescriptorInitContext initContext) { // this *MUST* execute after the BeanDescriptor is // put into the map to stop infinite recursion + initialiseTargetDescriptor(initContext); + } + + void initialiseTargetDescriptor(BeanDescriptorInitContext initContext) { targetDescriptor = descriptor.getBeanDescriptor(targetType); if (!isTransient) { targetIdBinder = targetDescriptor.getIdBinder(); targetInheritInfo = targetDescriptor.getInheritInfo(); saveRecurseSkippable = targetDescriptor.isSaveRecurseSkippable(); - if (!targetIdBinder.isComplexId()) { targetIdProperty = targetIdBinder.getIdProperty(); } @@ -142,6 +149,7 @@ public abstract class BeanPropertyAssoc extends BeanProperty { /** * Add table join with table alias based on prefix. */ + @Override public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) { return tableJoin.addJoin(joinType, prefix, ctx); } @@ -149,6 +157,7 @@ public abstract class BeanPropertyAssoc extends BeanProperty { /** * Add table join with explicit table alias. */ + @Override public SqlJoinType addJoin(SqlJoinType joinType, String a1, String a2, DbSqlContext ctx) { return tableJoin.addJoin(joinType, a1, a2, ctx); } @@ -186,6 +195,29 @@ public abstract class BeanPropertyAssoc extends BeanProperty { return targetDescriptor; } + SpiEbeanServer server() { + return descriptor.getEbeanServer(); + } + + /** + * Create a new query for the target type. + * + * We use target descriptor rather than target property type to support ElementCollection. + */ + public SpiQuery newQuery(SpiEbeanServer server) { + return new DefaultOrmQuery<>(targetDescriptor, server, server.getExpressionFactory()); + } + + @Override + public IdBinder getIdBinder() { + return descriptor.getIdBinder(); + } + + @Override + public STreeType target() { + return targetDescriptor; + } + /** * Return true if the target side has soft delete. */ @@ -325,6 +357,13 @@ public abstract class BeanPropertyAssoc extends BeanProperty { return tableJoin.columns().length <= 0 || tableJoin.columns()[0].isInsertable(); } + /** + * Return the underlying BeanTable for this property. + */ + public BeanTable getBeanTable() { + return beanTable; + } + /** * return the join to use for the bean. */ @@ -440,10 +479,6 @@ public abstract class BeanPropertyAssoc extends BeanProperty { } } - EbeanServer server() { - return getBeanDescriptor().getEbeanServer(); - } - void bindParentIds(DefaultSqlUpdate delete, List parentIds) { if (isExportedSimple()) { @@ -492,4 +527,26 @@ public abstract class BeanPropertyAssoc extends BeanProperty { private boolean isExportedSimple() { return exportedProperties.length == 1; } + + /** + * Find and return the exported property matching to this property. + */ + ExportedProperty findMatch(boolean embedded, BeanProperty prop, String matchColumn, TableJoin tableJoin) { + + String searchTable = tableJoin.getTable(); + + for (TableJoinColumn column : tableJoin.columns()) { + String matchTo = column.getLocalDbColumn(); + + if (matchColumn.equalsIgnoreCase(matchTo)) { + String foreignCol = column.getForeignDbColumn(); + return new ExportedProperty(embedded, foreignCol, prop); + } + } + + String msg = "Error with the Join on [" + getFullBeanName() + + "]. Could not find the matching foreign key for [" + matchColumn + "] in table[" + searchTable + "]?" + + " Perhaps using a @JoinColumn with the name/referencedColumnName attributes swapped?"; + throw new PersistenceException(msg); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index f193624b0..42d3e0667 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -1,7 +1,5 @@ package io.ebeaninternal.server.deploy; -import io.ebean.EbeanServer; -import io.ebean.Query; import io.ebean.SqlUpdate; import io.ebean.Transaction; import io.ebean.bean.BeanCollection; @@ -12,11 +10,11 @@ import io.ebean.bean.EntityBean; import io.ebean.text.PathProperties; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.core.DefaultSqlUpdate; import io.ebeaninternal.server.deploy.id.ImportedId; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; +import io.ebeaninternal.server.query.STreePropertyAssocMany; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; @@ -35,7 +33,7 @@ import java.util.Map; /** * Property mapped to a List Set or Map. */ -public class BeanPropertyAssocMany extends BeanPropertyAssoc { +public class BeanPropertyAssocMany extends BeanPropertyAssoc implements STreePropertyAssocMany { private static final Logger logger = LoggerFactory.getLogger(BeanPropertyAssocMany.class); @@ -51,7 +49,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { /** * For ManyToMany this is the Inverse join used to build reference queries. */ - private final TableJoin inverseJoin; + final TableJoin inverseJoin; /** * Flag to indicate that this is a unidirectional relationship. @@ -70,6 +68,8 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ private final boolean manyToMany; + private final boolean elementCollection; + /** * Order by used when fetch joining the associated many. */ @@ -91,8 +91,6 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { private BeanProperty mapKeyProperty; - private String exportedPropertyBindProto = "?"; - /** * Property on the 'child' bean that links back to the 'master'. */ @@ -106,9 +104,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { private ImportedId importedId; - private String deleteByParentIdSql; - - private String deleteByParentIdInSql; + private BeanPropertyAssocManySqlHelp sqlHelp; /** * Create this property. @@ -119,6 +115,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { this.o2mJoinTable = deploy.isO2mJoinTable(); this.hasOrderColumn = deploy.hasOrderColumn(); this.manyToMany = deploy.isManyToMany(); + this.elementCollection = deploy.isElementCollection(); this.manyType = deploy.getManyType(); this.mapKey = deploy.getMapKey(); this.fetchOrderBy = deploy.getFetchOrderBy(); @@ -136,13 +133,15 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } @Override - public void initialise() { - super.initialise(); + public void initialise(BeanDescriptorInitContext initContext) { + super.initialise(initContext); + initialiseAssocMany(); + } + private void initialiseAssocMany() { if (!isTransient) { this.help = BeanCollectionHelpFactory.create(this); - - if (hasJoinTable()) { + if (hasJoinTable() || elementCollection) { importedId = createImportedId(this, targetDescriptor, tableJoin); } else { @@ -159,37 +158,21 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } exportedProperties = createExported(); + this.sqlHelp = new BeanPropertyAssocManySqlHelp<>(this, exportedProperties); + if (exportedProperties.length > 0) { embeddedExportedProperties = exportedProperties[0].isEmbedded(); - exportedPropertyBindProto = deriveExportedPropertyBindProto(); - if (fetchOrderBy != null) { - // derive lazyFetchOrderBy - StringBuilder sb = new StringBuilder(50); - for (int i = 0; i < exportedProperties.length; i++) { - if (i > 0) { - sb.append(", "); - } - // these fk columns are either on the intersection (int_) or base table (t0) - String fkTableAlias = hasJoinTable() ? "int_" : "t0"; - sb.append(fkTableAlias).append(".").append(exportedProperties[i].getForeignDbColumn()); - } - sb.append(", ").append(fetchOrderBy); - lazyFetchOrderBy = sb.toString().trim(); + lazyFetchOrderBy = sqlHelp.lazyFetchOrderBy(fetchOrderBy); } } - - String delStmt; - if (hasJoinTable()) { - delStmt = "delete from " + inverseJoin.getTable() + " where "; - } else { - delStmt = "delete from " + targetDescriptor.getBaseTable() + " where "; - } - deleteByParentIdSql = delStmt + deriveWhereParentIdSql(false, ""); - deleteByParentIdInSql = delStmt + deriveWhereParentIdSql(true, ""); } } + String targetTable() { + return targetDescriptor.getBaseTable(); + } + /** * Initialise after the target bean descriptors have been all set. */ @@ -295,44 +278,23 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { public SqlUpdate deleteByParentId(Object parentId, List parentIdist) { if (parentId != null) { - return deleteByParentId(parentId); + return sqlHelp.deleteByParentId(parentId); } else { - return deleteByParentIdList(parentIdist); + return sqlHelp.deleteByParentIdList(parentIdist); } } - private SqlUpdate deleteByParentId(Object parentId) { - DefaultSqlUpdate sqlDelete = new DefaultSqlUpdate(deleteByParentIdSql); - bindParentId(sqlDelete, parentId); - return sqlDelete; - } - /** * Find the Id's of detail beans given a parent Id or list of parent Id's. */ public List findIdsByParentId(Object parentId, List parentIdList, Transaction t, List excludeDetailIds) { if (parentId != null) { - return findIdsByParentId(parentId, t, excludeDetailIds); + return sqlHelp.findIdsByParentId(parentId, t, excludeDetailIds); } else { - return findIdsByParentIdList(parentIdList, t, excludeDetailIds); + return sqlHelp.findIdsByParentIdList(parentIdList, t, excludeDetailIds); } } - private List findIdsByParentId(Object parentId, Transaction t, List excludeDetailIds) { - - String rawWhere = deriveWhereParentIdSql(false, ""); - - EbeanServer server = server(); - Query q = server.find(getPropertyType()); - bindParentIdEq(rawWhere, parentId, q); - - if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { - q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); - } - - return server.findIds(q, t); - } - /** * Exclude many properties from bean cache data. */ @@ -359,88 +321,10 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { // assumes the ManyToOne property is included query.where().in(childMasterIdProperty, parentIds); } else { - addWhereParentIdIn(query, parentIds); + sqlHelp.addWhereParentIdIn(query, parentIds); } } - /** - * Add a where clause to the query for a given list of parent Id's. - */ - private void addWhereParentIdIn(SpiQuery query, List parentIds) { - - String tableAlias = hasJoinTable() ? "int_." : "t0."; - if (hasJoinTable()) { - query.setM2MIncludeJoin(inverseJoin); - } - String rawWhere = deriveWhereParentIdSql(true, tableAlias); - String expr = descriptor.getParentIdInExpr(parentIds.size(), rawWhere); - - bindParentIdsIn(expr, parentIds, query); - } - - private List findIdsByParentIdList(List parentIds, Transaction t, List excludeDetailIds) { - - String rawWhere = deriveWhereParentIdSql(true, ""); - String inClause = buildInClauseBinding(parentIds.size(), exportedPropertyBindProto); - - String expr = rawWhere + inClause; - - EbeanServer server = descriptor.getEbeanServer(); - Query q = server.find(propertyType); - bindParentIdsIn(expr, parentIds, q); - - if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { - q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); - } - - return server.findIds(q, t); - } - - private SqlUpdate deleteByParentIdList(List parentIds) { - - StringBuilder sb = new StringBuilder(100); - sb.append(deleteByParentIdInSql); - sb.append(buildInClauseBinding(parentIds.size(), exportedPropertyBindProto)); - - DefaultSqlUpdate delete = new DefaultSqlUpdate(sb.toString()); - bindParentIds(delete, parentIds); - return delete; - } - - private String deriveExportedPropertyBindProto() { - if (exportedProperties.length == 1) { - return "?"; - } - StringBuilder sb = new StringBuilder(); - sb.append("("); - for (int i = 0; i < exportedProperties.length; i++) { - if (i > 0) { - sb.append(","); - } - sb.append("?"); - } - sb.append(")"); - return sb.toString(); - } - - private String buildInClauseBinding(int size, String bindProto) { - - if (descriptor.isSimpleId()) { - return descriptor.getIdBinder().getIdInValueExpr(false, size); - } - StringBuilder sb = new StringBuilder(10 + (size * (bindProto.length() + 1))); - sb.append(" in"); - sb.append(" ("); - for (int i = 0; i < size; i++) { - if (i > 0) { - sb.append(","); - } - sb.append(bindProto); - } - sb.append(") "); - return sb.toString(); - } - /** * Set the lazy load server to help create reference collections (that lazy * load on demand). @@ -476,7 +360,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } @Override - public Object readSet(DbReadContext ctx, EntityBean bean) throws SQLException { + public Object readSet(DbReadContext ctx, EntityBean bean) { return null; } @@ -616,6 +500,10 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { return manyToMany; } + public boolean isElementCollection() { + return elementCollection; + } + /** * ManyToMany only, join from local table to intersection table. */ @@ -705,30 +593,6 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } } - private String deriveWhereParentIdSql(boolean inClause, String tableAlias) { - - StringBuilder sb = new StringBuilder(); - - if (inClause) { - sb.append("("); - } - for (int i = 0; i < exportedProperties.length; i++) { - String fkColumn = exportedProperties[i].getForeignDbColumn(); - if (i > 0) { - String s = inClause ? "," : " and "; - sb.append(s); - } - sb.append(tableAlias).append(fkColumn); - if (!inClause) { - sb.append("=? "); - } - } - if (inClause) { - sb.append(")"); - } - return sb.toString(); - } - /** * Create the array of ExportedProperty used to build reference objects. */ @@ -741,12 +605,9 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { if (idProp != null && idProp.isEmbedded()) { BeanPropertyAssocOne one = (BeanPropertyAssocOne) idProp; - BeanDescriptor targetDesc = one.getTargetDescriptor(); - BeanProperty[] emIds = targetDesc.propertiesBaseScalar(); try { - for (BeanProperty emId : emIds) { - ExportedProperty expProp = findMatch(true, emId); - list.add(expProp); + for (BeanProperty emId : one.getTargetDescriptor().propertiesBaseScalar()) { + list.add(findMatch(true, emId)); } } catch (PersistenceException e) { // not found as individual scalar properties @@ -755,8 +616,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { } else { if (idProp != null) { - ExportedProperty expProp = findMatch(false, idProp); - list.add(expProp); + list.add(findMatch(false, idProp)); } } @@ -768,32 +628,12 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { */ private ExportedProperty findMatch(boolean embedded, BeanProperty prop) { - String matchColumn = prop.getDbColumn(); - - String searchTable; - TableJoinColumn[] columns; if (hasJoinTable()) { // look for column going to intersection - columns = intersectionJoin.columns(); - searchTable = intersectionJoin.getTable(); - + return findMatch(embedded, prop, prop.getDbColumn(), intersectionJoin); } else { - columns = tableJoin.columns(); - searchTable = tableJoin.getTable(); + return findMatch(embedded, prop, prop.getDbColumn(), tableJoin); } - for (TableJoinColumn column : columns) { - String matchTo = column.getLocalDbColumn(); - - if (matchColumn.equalsIgnoreCase(matchTo)) { - String foreignCol = column.getForeignDbColumn(); - return new ExportedProperty(embedded, foreignCol, prop); - } - } - - String msg = "Error with the Join on [" + getFullBeanName() - + "]. Could not find the matching foreign key for [" + matchColumn + "] in table[" + searchTable + "]?" - + " Perhaps using a @JoinColumn with the name/referencedColumnName attributes swapped?"; - throw new PersistenceException(msg); } /** @@ -813,8 +653,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { Class beanType = descriptor.getBeanType(); BeanDescriptor targetDesc = getTargetDescriptor(); - BeanPropertyAssocOne[] ones = targetDesc.propertiesOne(); - for (BeanPropertyAssocOne prop : ones) { + for (BeanPropertyAssocOne prop : targetDesc.propertiesOne()) { if (mappedBy != null) { // match using mappedBy as property name if (mappedBy.equalsIgnoreCase(prop.getName())) { @@ -880,9 +719,9 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { /** * Register the mapping of intersection table to associated draft table. */ - public void registerDraftIntersectionTable(Map draftTableMap) { + public void registerDraftIntersectionTable(BeanDescriptorInitContext initContext) { if (hasDraftIntersection()) { - draftTableMap.put(intersectionPublishTable, intersectionDraftTable); + initContext.addDraftIntersection(intersectionPublishTable, intersectionDraftTable); } } @@ -928,7 +767,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { * Skip JSON write value for ToMany property. */ @Override - public void jsonWriteValue(SpiJsonWriter writeJson, Object value) throws IOException { + public void jsonWriteValue(SpiJsonWriter writeJson, Object value) { // do nothing, exclude ToMany properties } @@ -1030,4 +869,16 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc { public boolean isIncludeCascadeDelete() { return cascadeInfo.isDelete() || o2mJoinTable || ModifyListenMode.REMOVALS == modifyListenMode; } + + public String insertElementCollection() { + return sqlHelp.insertElementCollection(); + } + + public boolean isTargetDocStoreMapped() { + return targetDescriptor.isDocStoreMapped(); + } + + public BeanCollectionHelp getHelp() { + return help; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java index 258f74ae5..faa77fb49 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java @@ -13,7 +13,7 @@ import java.io.IOException; /** * Help BeanPropertyAssocMany with JSON processing. */ -public class BeanPropertyAssocManyJsonHelp { +class BeanPropertyAssocManyJsonHelp { /** * The associated many property. @@ -28,7 +28,7 @@ public class BeanPropertyAssocManyJsonHelp { /** * Construct for the owning many property. */ - public BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany many) { + BeanPropertyAssocManyJsonHelp(BeanPropertyAssocMany many) { this.many = many; boolean objectMapperPresent = many.getBeanDescriptor().getServerConfig().getClassLoadConfig().isJacksonObjectMapperPresent(); this.jsonTransient = !objectMapperPresent ? null : new BeanPropertyAssocManyJsonTransient(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java index e00215e6c..fd1b9fe1d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java @@ -14,12 +14,12 @@ import java.util.LinkedHashMap; /** * Helper used to read transient many properties using Jackson ObjectMapper. */ -public class BeanPropertyAssocManyJsonTransient { +class BeanPropertyAssocManyJsonTransient { /** * Use Jackson ObjectMapper to read the transient 'many' property. */ - public void jsonReadUsingObjectMapper(BeanPropertyAssocMany many, ReadJson readJson, EntityBean parentBean) throws IOException { + void jsonReadUsingObjectMapper(BeanPropertyAssocMany many, ReadJson readJson, EntityBean parentBean) throws IOException { ObjectMapper mapper = readJson.getObjectMapper(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java new file mode 100644 index 000000000..3b3426aa3 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java @@ -0,0 +1,258 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.SqlUpdate; +import io.ebean.Transaction; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.dbmigration.model.visitor.BaseTablePropertyVisitor; +import io.ebeaninternal.dbmigration.model.visitor.VisitAllUsing; +import io.ebeaninternal.server.core.DefaultSqlUpdate; + +import java.util.List; + +class BeanPropertyAssocManySqlHelp { + + private final BeanPropertyAssocMany many; + private final ExportedProperty[] exportedProperties; + private final boolean hasJoinTable; + private final BeanDescriptor descriptor; + private final String exportedPropertyBindProto; + private final String deleteByParentIdSql; + private final String deleteByParentIdInSql; + private final String elementCollectionInsertSql; + + BeanPropertyAssocManySqlHelp(BeanPropertyAssocMany many, ExportedProperty[] exportedProperties) { + this.many = many; + this.exportedProperties = exportedProperties; + this.hasJoinTable = many.hasJoinTable(); + this.descriptor = many.getBeanDescriptor(); + this.exportedPropertyBindProto = deriveExportedPropertyBindProto(); + + String delStmt; + if (hasJoinTable) { + delStmt = "delete from " + many.inverseJoin.getTable() + " where "; + } else { + delStmt = "delete from " + many.targetTable() + " where "; + } + deleteByParentIdSql = delStmt + deriveWhereParentIdSql(false, ""); + deleteByParentIdInSql = delStmt + deriveWhereParentIdSql(true, ""); + if (many.isElementCollection()) { + elementCollectionInsertSql = elementCollectionInsert(); + } else { + elementCollectionInsertSql = null; + } + } + + private String elementCollectionInsert() { + + StringBuilder sb = new StringBuilder(200); + sb.append("insert into ").append(many.targetTable()).append(" ("); + append(sb, "", ",", ""); + + Cols cols = new Cols(sb); + VisitAllUsing.visitOne(many.targetDescriptor, cols); + sb.append(") values ("); + appendBind(sb, exportedProperties.length, true); + appendBind(sb, cols.colCount, false); + sb.append(")"); + + return sb.toString(); + } + + public String insertElementCollection() { + return elementCollectionInsertSql; + } + + private static class Cols extends BaseTablePropertyVisitor { + + int colCount; + + private final StringBuilder sb; + + private Cols(StringBuilder sb) { + this.sb = sb; + } + + @Override + public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne embedded) { + sb.append(",").append(p.getDbColumn()); + colCount++; + } + + @Override + public void visitOneImported(BeanPropertyAssocOne p) { + + } + + @Override + public void visitScalar(BeanProperty p) { + sb.append(",").append(p.getDbColumn()); + colCount++; + } + + @Override + public void visitEnd() { + + } + } + + String lazyFetchOrderBy(String fetchOrderBy) { + + // derive lazyFetchOrderBy + StringBuilder sb = new StringBuilder(50); + for (int i = 0; i < exportedProperties.length; i++) { + if (i > 0) { + sb.append(", "); + } + // these fk columns are either on the intersection (int_) or base table (t0) + String fkTableAlias = hasJoinTable ? "int_" : "t0"; + sb.append(fkTableAlias).append(".").append(exportedProperties[i].getForeignDbColumn()); + } + sb.append(", ").append(fetchOrderBy); + return sb.toString().trim(); + } + + /** + * Add a where clause to the query for a given list of parent Id's. + */ + void addWhereParentIdIn(SpiQuery query, List parentIds) { + + String tableAlias = hasJoinTable ? "int_." : "t0."; + if (hasJoinTable) { + query.setM2MIncludeJoin(many.inverseJoin); + } + String rawWhere = deriveWhereParentIdSql(true, tableAlias); + String expr = descriptor.getParentIdInExpr(parentIds.size(), rawWhere); + + many.bindParentIdsIn(expr, parentIds, query); + } + + List findIdsByParentId(Object parentId, Transaction t, List excludeDetailIds) { + + String rawWhere = deriveWhereParentIdSql(false, ""); + + SpiEbeanServer server = descriptor.getEbeanServer(); + SpiQuery q = many.newQuery(server); + many.bindParentIdEq(rawWhere, parentId, q); + + if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { + q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); + } + + return server.findIds(q, t); + } + + List findIdsByParentIdList(List parentIds, Transaction t, List excludeDetailIds) { + + String rawWhere = deriveWhereParentIdSql(true, ""); + String inClause = buildInClauseBinding(parentIds.size(), exportedPropertyBindProto); + + String expr = rawWhere + inClause; + + SpiEbeanServer server = descriptor.getEbeanServer(); + SpiQuery q = many.newQuery(server); + //Query q = server.find(propertyType); + many.bindParentIdsIn(expr, parentIds, q); + + if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { + q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); + } + + return server.findIds(q, t); + } + + SqlUpdate deleteByParentId(Object parentId) { + DefaultSqlUpdate sqlDelete = new DefaultSqlUpdate(deleteByParentIdSql); + many.bindParentId(sqlDelete, parentId); + return sqlDelete; + } + + SqlUpdate deleteByParentIdList(List parentIds) { + + StringBuilder sb = new StringBuilder(100); + sb.append(deleteByParentIdInSql); + sb.append(buildInClauseBinding(parentIds.size(), exportedPropertyBindProto)); + + DefaultSqlUpdate delete = new DefaultSqlUpdate(sb.toString()); + many.bindParentIds(delete, parentIds); + return delete; + } + + private void appendBind(StringBuilder sb, int count, boolean skipComma) { + for (int i = 0; i < count; i++) { + if (!skipComma || i > 0) { + sb.append(","); + } + sb.append("?"); + } + } + + private void append(StringBuilder sb, String tableAlias, String prefix, String suffix) { + for (int i = 0; i < exportedProperties.length; i++) { + String fkColumn = exportedProperties[i].getForeignDbColumn(); + if (i > 0) { + sb.append(prefix); + } + sb.append(tableAlias).append(fkColumn); + sb.append(suffix); + } + } + private String deriveWhereParentIdSql(boolean inClause, String tableAlias) { + + StringBuilder sb = new StringBuilder(); + + if (inClause) { + sb.append("("); + } + for (int i = 0; i < exportedProperties.length; i++) { + String fkColumn = exportedProperties[i].getForeignDbColumn(); + if (i > 0) { + String s = inClause ? "," : " and "; + sb.append(s); + } + sb.append(tableAlias).append(fkColumn); + if (!inClause) { + sb.append("=? "); + } + } + if (inClause) { + sb.append(")"); + } + return sb.toString(); + } + + private String buildInClauseBinding(int size, String bindProto) { + + if (descriptor.isSimpleId()) { + return descriptor.getIdBinder().getIdInValueExpr(false, size); + } + StringBuilder sb = new StringBuilder(10 + (size * (bindProto.length() + 1))); + sb.append(" in"); + sb.append(" ("); + for (int i = 0; i < size; i++) { + if (i > 0) { + sb.append(","); + } + sb.append(bindProto); + } + sb.append(") "); + return sb.toString(); + } + + private String deriveExportedPropertyBindProto() { + if (exportedProperties.length == 1) { + return "?"; + } + StringBuilder sb = new StringBuilder(); + sb.append("("); + for (int i = 0; i < exportedProperties.length; i++) { + if (i > 0) { + sb.append(","); + } + sb.append("?"); + } + sb.append(")"); + return sb.toString(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 2d34242b1..c4f28fd60 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -16,10 +16,12 @@ import io.ebeaninternal.server.deploy.id.ImportedId; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; +import io.ebeaninternal.server.query.STreePropertyAssocOne; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; import javax.persistence.PersistenceException; import java.io.IOException; @@ -32,7 +34,7 @@ import java.util.Map; /** * Property mapped to a joined bean. */ -public class BeanPropertyAssocOne extends BeanPropertyAssoc { +public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STreePropertyAssocOne { private final boolean oneToOne; @@ -94,8 +96,12 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } @Override - public void initialise() { - super.initialise(); + public void initialise(BeanDescriptorInitContext initContext) { + super.initialise(initContext); + initialiseAssocOne(); + } + + private void initialiseAssocOne() { localHelp = createHelp(embedded, oneToOneExported); if (!isTransient) { @@ -417,6 +423,11 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } + @Override + public ScalarType getIdScalarType() { + return targetDescriptor.getIdProperty().getScalarType(); + } + /** * Return the Id values from the given bean. */ @@ -539,24 +550,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { */ private ExportedProperty findMatch(boolean embeddedProp, BeanProperty prop) { - String matchColumn = prop.getDbColumn(); - - String searchTable = tableJoin.getTable(); - TableJoinColumn[] columns = tableJoin.columns(); - - for (TableJoinColumn column : columns) { - String matchTo = column.getLocalDbColumn(); - - if (matchColumn.equalsIgnoreCase(matchTo)) { - String foreignCol = column.getForeignDbColumn(); - return new ExportedProperty(embeddedProp, foreignCol, prop); - } - } - - String msg = "Error with the Join on [" + getFullBeanName() - + "]. Could not find the matching foreign key for [" + matchColumn + "] in table[" + searchTable + "]?" - + " Perhaps using a @JoinColumn with the name/referencedColumnName attributes swapped?"; - throw new PersistenceException(msg); + return findMatch(embeddedProp, prop, prop.getDbColumn(), tableJoin); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java index c3d7fc6a2..69f79bd1c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java @@ -4,8 +4,27 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection; public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { + private BeanDescriptor elementDescriptor; + public BeanPropertySimpleCollection(BeanDescriptor descriptor, DeployBeanPropertySimpleCollection deploy) { super(descriptor, deploy); + this.elementDescriptor = deploy.getElementDescriptor(); } + @Override + public void initialise(BeanDescriptorInitContext initContext) { + super.initialise(initContext); + if (isElementCollection()) { + // initialise all non-id properties (we don't have an Id property) + elementDescriptor.initialiseOther(initContext); + } + } + + void initialiseTargetDescriptor(BeanDescriptorInitContext initContext) { + if (isElementCollection()) { + targetDescriptor = elementDescriptor; + } else { + targetDescriptor = descriptor.getBeanDescriptor(targetType); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java index 0dfdf40af..450ed659a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java @@ -5,7 +5,6 @@ import io.ebean.Query; import io.ebean.Transaction; import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; -import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; import io.ebean.common.BeanSet; import io.ebeaninternal.server.text.json.SpiJsonWriter; @@ -19,32 +18,18 @@ import java.util.Set; */ public final class BeanSetHelp extends BaseCollectionHelp { - private final BeanPropertyAssocMany many; - private final BeanDescriptor targetDescriptor; - private final String propertyName; - private BeanCollectionLoader loader; - /** * When attached to a specific many property. */ - public BeanSetHelp(BeanPropertyAssocMany many) { - this.many = many; - this.targetDescriptor = many.getTargetDescriptor(); - this.propertyName = many.getName(); + BeanSetHelp(BeanPropertyAssocMany many) { + super(many); } /** * For a query that returns a set. */ - public BeanSetHelp() { - this.many = null; - this.targetDescriptor = null; - this.propertyName = null; - } - - @Override - public void setLoader(BeanCollectionLoader loader) { - this.loader = loader; + BeanSetHelp() { + super(); } @Override @@ -61,15 +46,6 @@ public final class BeanSetHelp extends BaseCollectionHelp { } } - @Override - public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { - if (withCheck) { - collection.internalAddWithCheck(bean); - } else { - collection.internalAdd(bean); - } - } - @Override public BeanCollection createEmptyNoParent() { return new BeanSet<>(); @@ -142,13 +118,6 @@ public final class BeanSetHelp extends BaseCollectionHelp { } else { set = (Set) collection; } - - if (!set.isEmpty() || ctx.isIncludeEmpty()) { - ctx.beginAssocMany(name); - for (Object bean : set) { - targetDescriptor.jsonWrite(ctx, (EntityBean) bean); - } - ctx.endAssocMany(); - } + jsonWriteCollection(ctx, name, set); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java index c481660e8..f2cc09e78 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanTable.java @@ -42,6 +42,16 @@ public class BeanTable { this.idProperty = mutable.createIdProperty(owner); } + /** + * Construct for element collection. + */ + public BeanTable(BeanDescriptorMap owner, String tableName, Class beanType) { + this.owner = owner; + this.beanType = beanType; + this.baseTable = tableName; + this.idProperty = null; + } + @Override public String toString() { return baseTable; diff --git a/src/main/java/io/ebeaninternal/server/deploy/DbReadContext.java b/src/main/java/io/ebeaninternal/server/deploy/DbReadContext.java index b7f346313..c282eca47 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DbReadContext.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DbReadContext.java @@ -5,6 +5,7 @@ import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBeanIntercept; import io.ebean.bean.PersistenceContext; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.server.query.STreePropertyAssocMany; import io.ebeaninternal.server.type.DataReader; import java.util.Map; @@ -68,7 +69,7 @@ public interface DbReadContext { * Return the property that is associated with the many. There can only be * one. This can be null. */ - BeanPropertyAssocMany getManyProperty(); + STreePropertyAssocMany getManyProperty(); /** * Set back the bean that has just been loaded with its id. diff --git a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java index e0fae9d19..194f4eb47 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyBase.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.deploy; +import io.ebeaninternal.server.query.STreeProperty; import io.ebeaninternal.server.query.SqlJoinType; -import io.ebeaninternal.server.query.SqlTreeProperty; import io.ebeaninternal.server.type.ScalarType; import java.util.List; @@ -9,14 +9,14 @@ import java.util.List; /** * Abstract base for dynamic properties. */ -abstract class DynamicPropertyBase implements SqlTreeProperty { +abstract class DynamicPropertyBase implements STreeProperty { final String name; final String fullName; final String elPrefix; final ScalarType scalarType; - public DynamicPropertyBase(String name, String fullName, String elPrefix, ScalarType scalarType) { + DynamicPropertyBase(String name, String fullName, String elPrefix, ScalarType scalarType) { this.name = name; this.fullName = fullName; this.elPrefix = elPrefix; @@ -43,6 +43,11 @@ abstract class DynamicPropertyBase implements SqlTreeProperty { return false; } + @Override + public boolean isFormula() { + return false; + } + @Override public String getElPrefix() { return elPrefix; @@ -67,4 +72,9 @@ abstract class DynamicPropertyBase implements SqlTreeProperty { public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { // do not add to from usually } + + @Override + public String getEncryptKeyAsString() { + return null; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementEntityBean.java b/src/main/java/io/ebeaninternal/server/deploy/ElementEntityBean.java new file mode 100644 index 000000000..3724cac99 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementEntityBean.java @@ -0,0 +1,81 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; + +class ElementEntityBean implements EntityBean { + + private final String[] properties; + + private Object[] data; + + private EntityBeanIntercept intercept; + + ElementEntityBean(String[] properties) { + this.properties = properties; + this.intercept = new EntityBeanIntercept(this); + } + + @Override + public String[] _ebean_getPropertyNames() { + return properties; + } + + @Override + public String _ebean_getPropertyName(int pos) { + return properties[pos]; + } + + @Override + public String _ebean_getMarker() { + return null; + } + + @Override + public Object _ebean_newInstance() { + return new ElementEntityBean(properties); + } + + @Override + public void _ebean_setEmbeddedLoaded() { + + } + + @Override + public boolean _ebean_isEmbeddedNewOrDirty() { + return false; + } + + @Override + public EntityBeanIntercept _ebean_getIntercept() { + return intercept; + } + + @Override + public EntityBeanIntercept _ebean_intercept() { + return intercept; + } + + @Override + public void _ebean_setField(int fieldIndex, Object value) { + if (data == null) { + data = new Object[properties.length]; + } + data[fieldIndex] = value; + } + + @Override + public void _ebean_setFieldIntercept(int fieldIndex, Object value) { + _ebean_setField(fieldIndex, value); + } + + @Override + public Object _ebean_getField(int fieldIndex) { + return data == null ? null : data[fieldIndex]; + } + + @Override + public Object _ebean_getFieldIntercept(int fieldIndex) { + return _ebean_getField(fieldIndex); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java index 817868cd5..c63d39b3e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java +++ b/src/main/java/io/ebeaninternal/server/deploy/FormulaPropertyPath.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.deploy; import io.ebeaninternal.server.el.ElPropertyDeploy; -import io.ebeaninternal.server.query.SqlTreeProperty; +import io.ebeaninternal.server.query.STreeProperty; import io.ebeaninternal.server.type.ScalarType; import java.sql.Types; @@ -89,7 +89,7 @@ class FormulaPropertyPath { return alias; } - SqlTreeProperty build() { + STreeProperty build() { DeployPropertyParser parser = descriptor.parser().setCatchFirst(true); diff --git a/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java b/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java index 0e045c4e2..d93d74fdc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java +++ b/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java @@ -184,7 +184,7 @@ public class InheritInfo { for (InheritInfo childInfo : children) { // recursively search this child bean descriptor - prop = childInfo.desc().findBeanProperty(propertyName); + prop = childInfo.desc().findProperty(propertyName); if (prop != null) { return prop; } diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java index 766f9eb60..d3a018e10 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java +++ b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinder.java @@ -6,6 +6,7 @@ import io.ebeaninternal.server.core.DefaultSqlUpdate; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; +import io.ebeaninternal.server.query.STreeProperty; import io.ebeaninternal.server.type.DataBind; import java.io.DataInput; @@ -52,7 +53,7 @@ public interface IdBinder { /** * Return the Id BeanProperty. */ - BeanProperty getBeanProperty(); + STreeProperty getBeanProperty(); /** * Find a BeanProperty that is mapped to the database column. diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/BeanPropertyElementSetter.java b/src/main/java/io/ebeaninternal/server/deploy/meta/BeanPropertyElementSetter.java new file mode 100644 index 000000000..f20ee47cf --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/BeanPropertyElementSetter.java @@ -0,0 +1,26 @@ +package io.ebeaninternal.server.deploy.meta; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.properties.BeanPropertySetter; + +/** + * Setter used for "element beans" with ElementCollection. + */ +class BeanPropertyElementSetter implements BeanPropertySetter { + + private final int pos; + + BeanPropertyElementSetter(int pos) { + this.pos = pos; + } + + @Override + public void set(EntityBean bean, Object value) { + bean._ebean_setField(pos, value); + } + + @Override + public void setIntercept(EntityBean bean, Object value) { + set(bean, value); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index ce091b2ec..f2ae582ee 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -210,6 +210,8 @@ public class DeployBeanProperty { private boolean undirectionalShadow; + private boolean elementProperty; + private int sortOrder; private boolean excludedFromHistory; @@ -444,7 +446,11 @@ public class DeployBeanProperty { } public BeanPropertySetter getSetter() { - return setter; + if (elementProperty) { + return new BeanPropertyElementSetter(sortOrder); + } else { + return setter; + } } /** @@ -1081,4 +1087,10 @@ public class DeployBeanProperty { return dbMigrationInfos; } + /** + * Set when this property is part of a 'element bean' used with ElementCollection. + */ + public void setElementProperty() { + this.elementProperty = true; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java index 112223110..4e6d7d7d8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.deploy.meta; import io.ebean.bean.BeanCollection.ModifyListenMode; +import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.ManyType; import io.ebeaninternal.server.deploy.TableJoin; @@ -23,6 +24,8 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { private boolean o2mJoinTable; + private boolean elementCollection; + /** * Flag to indicate this is a unidirectional relationship. */ @@ -46,6 +49,11 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { private DeployOrderColumn orderColumn; + /** + * Effectively the dynamically created target descriptor (that doesn't have a mapped type/class per say). + */ + private BeanDescriptor elementDescriptor; + /** * Create this property. */ @@ -231,5 +239,24 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { this.o2mJoinTable = true; setModifyListenMode(ModifyListenMode.ALL); } + + public void setElementCollection() { + elementCollection = true; + cascadeInfo.setSaveDelete(true, true); + setModifyListenMode(ModifyListenMode.ALL); + } + + public boolean isElementCollection() { + return elementCollection; + } + + public void setElementDescriptor(BeanDescriptor elementDescriptor) { + this.elementDescriptor = elementDescriptor; + } + + @SuppressWarnings("unchecked") + public BeanDescriptor getElementDescriptor() { + return (BeanDescriptor)elementDescriptor; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index ed26cc045..920d0141e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.deploy.meta; import io.ebeaninternal.server.deploy.PropertyForeignKey; +import io.ebeaninternal.server.query.SqlJoinType; import javax.persistence.CascadeType; @@ -162,4 +163,12 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { public boolean isOrphanRemoval() { return orphanRemoval; } + + public void setJoinType(boolean outerJoin) { + tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER); + } + + public void setJoinColumns(DeployTableJoinColumn[] columns, boolean reverse) { + tableJoin.setColumns(columns, reverse); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index dce5962c1..460901474 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -7,18 +7,24 @@ import io.ebean.annotation.Where; import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebean.config.NamingConvention; import io.ebean.config.TableName; +import io.ebean.util.CamelCaseHelper; import io.ebean.util.StringHelper; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanTable; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; import io.ebeaninternal.server.deploy.meta.DeployOrderColumn; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; import io.ebeaninternal.server.query.SqlJoinType; +import io.ebeaninternal.server.type.ScalarType; import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; @@ -38,8 +44,8 @@ class AnnotationAssocManys extends AnnotationParser { /** * Create with the DeployInfo. */ - AnnotationAssocManys(DeployBeanInfo info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) { - super(info, javaxValidationAnnotations); + AnnotationAssocManys(DeployBeanInfo info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) { + super(info, readConfig); this.factory = factory; } @@ -82,6 +88,10 @@ class AnnotationAssocManys extends AnnotationParser { if (manyToMany != null) { readToMany(manyToMany, prop); } + ElementCollection elementCollection = get(prop, ElementCollection.class); + if (elementCollection != null) { + readElementCollection(prop, elementCollection); + } if (get(prop, HistoryExclude.class) != null) { prop.setExcludedFromHistory(); @@ -160,6 +170,59 @@ class AnnotationAssocManys extends AnnotationParser { } } + private void readElementCollection(DeployBeanPropertyAssocMany prop, ElementCollection elementCollection) { + + prop.setElementCollection(); + if (!elementCollection.targetClass().equals(void.class)) { + prop.setTargetType(elementCollection.targetClass()); + } + Column column = get(prop, Column.class); + if (column != null) { + prop.setDbColumn(column.name()); + prop.setDbLength(column.length()); + prop.setDbScale(column.scale()); + } + + CollectionTable collectionTable = get(prop, CollectionTable.class); + + String fullTableName = getFullTableName(collectionTable); + if (fullTableName == null) { + fullTableName = descriptor.getBaseTable()+"_"+ CamelCaseHelper.toUnderscoreFromCamel(prop.getName()); + } + //namingConvention. + BeanTable beanTable = factory.getCollectionBeanTable(fullTableName, prop.getTargetType()); + prop.setBeanTable(beanTable); + + if (collectionTable != null) { + prop.getTableJoin().addJoinColumn(true, collectionTable.joinColumns(), beanTable); + } + + Class elementType = prop.getTargetType(); + + DeployBeanDescriptor elementDescriptor = factory.createDeployDescriptor(elementType); + elementDescriptor.setBaseTable(new TableName(fullTableName), readConfig.getAsOfViewSuffix(), readConfig.getVersionsBetweenSuffix()); + + ScalarType scalarType = util.getTypeManager().getScalarType(elementType); + DeployBeanProperty elementProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); + + elementProp.setName("value"); + elementProp.setDbColumn(prop.getDbColumn()); + elementProp.setNullable(false); + elementProp.setDbInsertable(true); + elementProp.setDbUpdateable(true); + elementProp.setDbRead(true); + elementProp.setElementProperty(); + + elementDescriptor.addBeanProperty(elementProp); + elementDescriptor.setProperties(new String[]{"value"}); + elementDescriptor.setName(prop.getFullBeanName()); + + Class owningType = prop.getOwningType(); + + factory.createUnidirectional(elementDescriptor, owningType, beanTable, prop.getTableJoin()); + prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor)); + } + /** * Define the joins for a ManyToMany relationship. *

    @@ -204,6 +267,24 @@ class AnnotationAssocManys extends AnnotationParser { return sb.toString(); } + /** + * Return the full table name + */ + private String getFullTableName(CollectionTable collectionTable) { + if (collectionTable == null) { + return null; + } + StringBuilder sb = new StringBuilder(); + if (!StringHelper.isNull(collectionTable.catalog())) { + sb.append(collectionTable.catalog()).append("."); + } + if (!StringHelper.isNull(collectionTable.schema())) { + sb.append(collectionTable.schema()).append("."); + } + sb.append(collectionTable.name()); + return sb.toString(); + } + /** * Define intersection table and foreign key columns for ManyToMany. *

    diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index cd53cd350..4be0a3ad1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -41,8 +41,8 @@ public class AnnotationAssocOnes extends AnnotationParser { /** * Create with the deploy Info. */ - AnnotationAssocOnes(DeployBeanInfo info, boolean javaxValidationAnnotations, BeanDescriptorManager factory) { - super(info, javaxValidationAnnotations); + AnnotationAssocOnes(DeployBeanInfo info, ReadAnnotationConfig readConfig, BeanDescriptorManager factory) { + super(info, readConfig); this.factory = factory; } @@ -152,7 +152,7 @@ public class AnnotationAssocOnes extends AnnotationParser { } } - info.setBeanJoinType(prop, prop.isNullable()); + prop.setJoinType(prop.isNullable()); if (!prop.getTableJoin().hasJoinColumns() && beanTable != null) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java index c5cb0b810..208b0bdf3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationClass.java @@ -42,25 +42,15 @@ public class AnnotationClass extends AnnotationParser { private final boolean disableL2Cache; - /** - * Create for normal early parse of class level annotations. - */ - public AnnotationClass(DeployBeanInfo info, boolean validationAnnotations, String asOfViewSuffix, String versionsBetweenSuffix, boolean disableL2Cache) { - super(info, validationAnnotations); - this.asOfViewSuffix = asOfViewSuffix; - this.versionsBetweenSuffix = versionsBetweenSuffix; - this.disableL2Cache = disableL2Cache; - } - /** * Create to parse AttributeOverride annotations which is run last * after all the properties/fields have been parsed fully. */ - public AnnotationClass(DeployBeanInfo info) { - super(info, false); - this.asOfViewSuffix = null; - this.versionsBetweenSuffix = null; - this.disableL2Cache = false; + public AnnotationClass(DeployBeanInfo info, ReadAnnotationConfig readConfig) { + super(info, readConfig); + this.asOfViewSuffix = readConfig.getAsOfViewSuffix(); + this.versionsBetweenSuffix = readConfig.getVersionsBetweenSuffix(); + this.disableL2Cache = readConfig.isDisableL2Cache(); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java index a84af1f0c..4be082b93 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationFields.java @@ -91,14 +91,11 @@ public class AnnotationFields extends AnnotationParser { */ private FetchType defaultLobFetchType = FetchType.LAZY; - AnnotationFields(GeneratedPropertyFactory generatedPropFactory, DeployBeanInfo info, - boolean javaxValidationAnnotations, boolean jacksonAnnotationsPresent, boolean eagerFetchLobs) { - - super(info, javaxValidationAnnotations); - this.jacksonAnnotationsPresent = jacksonAnnotationsPresent; - this.generatedPropFactory = generatedPropFactory; - - if (eagerFetchLobs) { + AnnotationFields(DeployBeanInfo info, ReadAnnotationConfig readConfig) { + super(info, readConfig); + this.jacksonAnnotationsPresent = readConfig.isJacksonAnnotations(); + this.generatedPropFactory = readConfig.getGeneratedPropFactory(); + if (readConfig.isEagerFetchLobs()) { defaultLobFetchType = FetchType.EAGER; } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java index 034caa595..1bcb1faf3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationParser.java @@ -27,9 +27,12 @@ public abstract class AnnotationParser extends AnnotationBase { protected final boolean validationAnnotations; - public AnnotationParser(DeployBeanInfo info, boolean validationAnnotations) { + protected final ReadAnnotationConfig readConfig; + + public AnnotationParser(DeployBeanInfo info, ReadAnnotationConfig readConfig) { super(info.getUtil()); - this.validationAnnotations = validationAnnotations; + this.readConfig = readConfig; + this.validationAnnotations = readConfig.isJavaxValidationAnnotations(); this.info = info; this.beanType = info.getDescriptor().getBeanType(); this.descriptor = info.getDescriptor(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationSql.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationSql.java index d488e933c..df9622b02 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationSql.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationSql.java @@ -7,10 +7,10 @@ import io.ebeaninternal.server.deploy.BeanDescriptor; /** * Read the class level deployment annotations. */ -public class AnnotationSql extends AnnotationParser { +class AnnotationSql extends AnnotationParser { - public AnnotationSql(DeployBeanInfo info, boolean javaxValidationAnnotations) { - super(info, javaxValidationAnnotations); + AnnotationSql(DeployBeanInfo info, ReadAnnotationConfig readConfig) { + super(info, readConfig); } @Override diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java index 553e263c8..d683578bc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployBeanInfo.java @@ -3,7 +3,6 @@ package io.ebeaninternal.server.deploy.parse; import io.ebean.RawSql; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.query.SqlJoinType; import io.ebeaninternal.server.rawsql.SpiRawSql; @@ -70,15 +69,6 @@ public class DeployBeanInfo { return tableJoin; } - /** - * Set a the join alias for a assoc one property. - */ - public void setBeanJoinType(DeployBeanPropertyAssocOne beanProp, boolean outerJoin) { - - DeployTableJoin tableJoin = beanProp.getTableJoin(); - tableJoin.setType(outerJoin ? SqlJoinType.OUTER : SqlJoinType.INNER); - } - /** * Add named RawSql from ebean.xml. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotationConfig.java b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotationConfig.java new file mode 100644 index 000000000..4b3bf96d0 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotationConfig.java @@ -0,0 +1,58 @@ +package io.ebeaninternal.server.deploy.parse; + +import io.ebean.config.ServerConfig; +import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory; + +/** + * Configuration used when reading the deployment annotations. + */ +class ReadAnnotationConfig { + + private final GeneratedPropertyFactory generatedPropFactory; + private final String asOfViewSuffix; + private final String versionsBetweenSuffix; + private final boolean disableL2Cache; + private final boolean eagerFetchLobs; + private final boolean javaxValidationAnnotations; + private final boolean jacksonAnnotations; + + ReadAnnotationConfig(GeneratedPropertyFactory generatedPropFactory, String asOfViewSuffix, String versionsBetweenSuffix, ServerConfig serverConfig) { + + this.generatedPropFactory = generatedPropFactory; + this.asOfViewSuffix = asOfViewSuffix; + this.versionsBetweenSuffix = versionsBetweenSuffix; + this.disableL2Cache = serverConfig.isDisableL2Cache(); + this.eagerFetchLobs = serverConfig.isEagerFetchLobs(); + + this.javaxValidationAnnotations = generatedPropFactory.getClassLoadConfig().isJavaxValidationAnnotationsPresent(); + this.jacksonAnnotations = generatedPropFactory.getClassLoadConfig().isJacksonAnnotationsPresent(); + } + + GeneratedPropertyFactory getGeneratedPropFactory() { + return generatedPropFactory; + } + + String getAsOfViewSuffix() { + return asOfViewSuffix; + } + + String getVersionsBetweenSuffix() { + return versionsBetweenSuffix; + } + + boolean isDisableL2Cache() { + return disableL2Cache; + } + + boolean isEagerFetchLobs() { + return eagerFetchLobs; + } + + boolean isJavaxValidationAnnotations() { + return javaxValidationAnnotations; + } + + boolean isJacksonAnnotations() { + return jacksonAnnotations; + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java index 6af425828..534e9cb82 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/ReadAnnotations.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.deploy.parse; +import io.ebean.config.ServerConfig; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory; @@ -9,38 +10,10 @@ import io.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory */ public class ReadAnnotations { - /** - * Creates appropriate generated properties - WhenXXX, WhoXXX, Version etc. - */ - private final GeneratedPropertyFactory generatedPropFactory; + private final ReadAnnotationConfig readConfig; - /** - * Typically _with_history and when appended to the base table derives the name of - * the view that unions the base table with the history table to support asOf queries. - */ - private final String asOfViewSuffix; - - private final String versionsBetweenSuffix; - - /** - * True if the javax validation annotations are present in the classpath. - */ - private final boolean javaxValidationAnnotations; - - /** - * True if the jackson annotations are present in the classpath. - */ - private final boolean jacksonAnnotations; - - private final boolean disableL2Cache; - - public ReadAnnotations(GeneratedPropertyFactory generatedPropFactory, String asOfViewSuffix, String versionsBetweenSuffix, boolean disableL2Cache) { - this.generatedPropFactory = generatedPropFactory; - this.asOfViewSuffix = asOfViewSuffix; - this.versionsBetweenSuffix = versionsBetweenSuffix; - this.javaxValidationAnnotations = generatedPropFactory.getClassLoadConfig().isJavaxValidationAnnotationsPresent(); - this.jacksonAnnotations = generatedPropFactory.getClassLoadConfig().isJacksonAnnotationsPresent(); - this.disableL2Cache = disableL2Cache; + public ReadAnnotations(GeneratedPropertyFactory generatedPropFactory, String asOfViewSuffix, String versionsBetweenSuffix, ServerConfig serverConfig) { + this.readConfig = new ReadAnnotationConfig(generatedPropFactory, asOfViewSuffix, versionsBetweenSuffix, serverConfig); } /** @@ -50,12 +23,10 @@ public class ReadAnnotations { * to resolve the relationships etc. *

    */ - public void readInitial(DeployBeanInfo info, boolean eagerFetchLobs) { - + public void readInitial(DeployBeanInfo info) { try { - new AnnotationClass(info, javaxValidationAnnotations, asOfViewSuffix, versionsBetweenSuffix, disableL2Cache).parse(); - new AnnotationFields(generatedPropFactory, info, javaxValidationAnnotations, jacksonAnnotations, eagerFetchLobs).parse(); - + new AnnotationClass(info, readConfig).parse(); + new AnnotationFields(info, readConfig).parse(); } catch (RuntimeException e) { throw new RuntimeException("Error reading annotations for " + info, e); } @@ -75,14 +46,14 @@ public class ReadAnnotations { try { - new AnnotationAssocOnes(info, javaxValidationAnnotations, factory).parse(); - new AnnotationAssocManys(info, javaxValidationAnnotations, factory).parse(); + new AnnotationAssocOnes(info, readConfig, factory).parse(); + new AnnotationAssocManys(info, readConfig, factory).parse(); // read the Sql annotations last because they may be // dependent on field level annotations - new AnnotationSql(info, javaxValidationAnnotations).parse(); + new AnnotationSql(info, readConfig).parse(); - new AnnotationClass(info).parseAttributeOverride(); + new AnnotationClass(info, readConfig).parseAttributeOverride(); info.getDescriptor().postAnnotations(); } catch (RuntimeException e) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/TransientProperties.java b/src/main/java/io/ebeaninternal/server/deploy/parse/TransientProperties.java index 4be75b3b3..e7896b96a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/TransientProperties.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/TransientProperties.java @@ -5,8 +5,6 @@ import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; -import java.util.List; - /** * Mark transient properties. */ @@ -20,29 +18,22 @@ public class TransientProperties { */ public void process(DeployBeanDescriptor desc) { - List props = desc.propertiesBase(); - for (DeployBeanProperty prop : props) { + for (DeployBeanProperty prop : desc.propertiesBase()) { if (!prop.isDbRead() && !prop.isDbInsertable() && !prop.isDbUpdateable()) { - // non-transient... prop.setTransient(); } } - List> ones = desc.propertiesAssocOne(); - for (DeployBeanPropertyAssocOne prop : ones) { - if (prop.getBeanTable() == null) { - if (!prop.isEmbedded()) { - prop.setTransient(); - } - } - } - - List> manys = desc.propertiesAssocMany(); - for (DeployBeanPropertyAssocMany prop : manys) { - if (prop.getBeanTable() == null) { + for (DeployBeanPropertyAssocOne prop : desc.propertiesAssocOne()) { + if (prop.getBeanTable() == null && !prop.isEmbedded()) { prop.setTransient(); } } + for (DeployBeanPropertyAssocMany prop : desc.propertiesAssocMany()) { + if (prop.getBeanTable() == null) { + prop.setTransient(); + } + } } } diff --git a/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java b/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java index 5300979ac..7a04f3bb7 100644 --- a/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/src/main/java/io/ebeaninternal/server/loadcontext/DLoadContext.java @@ -327,7 +327,7 @@ public class DLoadContext implements LoadContext { } private BeanProperty getBeanProperty(BeanDescriptor desc, String path) { - return desc.getBeanPropertyFromPath(path); + return desc.findPropertyFromPath(path); } /** diff --git a/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java b/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java index a1fb38a39..d98a62039 100644 --- a/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java +++ b/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java @@ -33,7 +33,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps); this.property = property; - this.docStoreMapped = property.getTargetDescriptor().isDocStoreMapped(); + this.docStoreMapped = property.isTargetDocStoreMapped(); // bufferList only required when using query joins (queryFetch) this.bufferList = (!queryFetch) ? null : new ArrayList<>(); this.currentBuffer = createBuffer(firstBatchSize); diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 0b3d20e1a..7a9748649 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -29,6 +29,7 @@ import io.ebeaninternal.server.deploy.BeanManager; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; +import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection; import io.ebeaninternal.server.deploy.IntersectionRow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -869,8 +870,7 @@ public final class DefaultPersister implements Persister { SpiTransaction t = request.getTransaction(); // exported ones with cascade save - BeanPropertyAssocOne[] expOnes = desc.propertiesOneExportedSave(); - for (BeanPropertyAssocOne prop : expOnes) { + for (BeanPropertyAssocOne prop : desc.propertiesOneExportedSave()) { // check for partial beans if (request.isLoadedProperty(prop)) { EntityBean detailBean = prop.getValueAsEntityBean(parentBean); @@ -886,12 +886,11 @@ public final class DefaultPersister implements Persister { } // many's with cascade save - BeanPropertyAssocMany[] manys = desc.propertiesManySave(); boolean insertedParent = request.isInsertedParent(); - for (BeanPropertyAssocMany many : manys) { + for (BeanPropertyAssocMany many : desc.propertiesManySave()) { // check that property is loaded and collection should be cascaded to if (request.isLoadedProperty(many) && !many.isSkipSaveBeanCollection(parentBean, insertedParent)) { - saveMany(new SaveManyPropRequest(insertedParent, many, parentBean, request)); + saveMany2(insertedParent, many, parentBean, request); if (!insertedParent) { request.addUpdatedManyProperty(many); } @@ -899,6 +898,18 @@ public final class DefaultPersister implements Persister { } } + private void saveMany2(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + saveMany(saveManyRequest(insertedParent, many, parentBean, request)); + } + + private SaveManyPropRequest saveManyRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + if (many instanceof BeanPropertySimpleCollection) { + return new SaveManySimpleCollection(insertedParent, many, parentBean, request); + } else { + return new SaveManyPropRequest(insertedParent, many, parentBean, request); + } + } + private void saveMany(SaveManyPropRequest saveMany) { if (saveMany.getMany().hasJoinTable()) { @@ -1131,8 +1142,7 @@ public final class DefaultPersister implements Persister { } // Many's with delete cascade - BeanPropertyAssocMany[] manys = desc.propertiesManyDelete(); - for (BeanPropertyAssocMany many : manys) { + for (BeanPropertyAssocMany many : desc.propertiesManyDelete()) { if (many.hasJoinTable()) { if (!softDelete) { // delete associated rows from intersection table (but not during soft delete) diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java index 97f9d1131..dbd643d2f 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java @@ -21,11 +21,11 @@ import java.util.Map; */ class SaveManyPropRequest { - private final PersistRequestBean request; + final PersistRequestBean request; private final boolean insertedParent; - private final BeanPropertyAssocMany many; - private final EntityBean parentBean; - private final SpiTransaction transaction; + final BeanPropertyAssocMany many; + final EntityBean parentBean; + final SpiTransaction transaction; private final boolean cascade; private final boolean deleteMissingChildren; private final boolean publish; @@ -35,8 +35,8 @@ class SaveManyPropRequest { private final boolean isMap; private final boolean saveRecurseSkippable; - private Collection collection; - private DefaultPersister persister; + Collection collection; + DefaultPersister persister; private boolean deleteMissing; private int sortOrder; @@ -127,7 +127,7 @@ class SaveManyPropRequest { } } - private void processDetails() { + void processDetails() { BeanProperty orderColumn = null; boolean hasOrderColumn = many.hasOrderColumn(); diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java new file mode 100644 index 000000000..62faf73e3 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java @@ -0,0 +1,39 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.SqlUpdate; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; + +class SaveManySimpleCollection extends SaveManyPropRequest { + + SaveManySimpleCollection(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + super(insertedParent, many, parentBean, request); + } + + @Override + void processDetails() { + + Object parentId = request.getBeanId(); + + SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); + + SpiEbeanServer server = request.getServer(); + server.execute(sqlDelete, transaction); + + transaction.depth(+1); + + String insert = many.insertElementCollection(); + SqlUpdate sqlInsert = server.createSqlUpdate(insert); + + for (Object value : collection) { + + sqlInsert.setParameter(1, parentId); + sqlInsert.setParameter(2, value); + server.execute(sqlInsert, transaction); + } + + transaction.depth(-1); + } +} diff --git a/src/main/java/io/ebeaninternal/server/query/CQuery.java b/src/main/java/io/ebeaninternal/server/query/CQuery.java index da7bdd090..9a40afaaf 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/io/ebeaninternal/server/query/CQuery.java @@ -35,7 +35,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -56,6 +55,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran private static final Logger logger = LoggerFactory.getLogger(CQuery.class); + private static final CQueryCollectionAddNoop NOOP_ADD = new CQueryCollectionAddNoop(); + /** * The resultSet rows read. */ @@ -99,7 +100,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran /** * The help for the 'master' collection. */ - private final BeanCollectionHelp help; + private final CQueryCollectionAdd help; /** * The overall find request wrapper object. @@ -147,7 +148,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran /** * For master detail query. */ - private final BeanPropertyAssocMany manyProperty; + private final STreePropertyAssocMany manyProperty; private DataReader dataReader; @@ -180,20 +181,26 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran private long executionTimeMicros; /** - * Flag set when findIterate is being read audited. + * Flag set when read auditing. + */ + private boolean audit; + + /** + * Flag set when findIterate is being read audited meaning we log in batches. */ private boolean auditFindIterate; /** * A buffer of Ids collected for findIterate auditing. */ - private List auditFindIterateIds; + private List auditIds; /** * Create the Sql select based on the request. */ public CQuery(OrmQueryRequest request, CQueryPredicates predicates, CQueryPlan queryPlan) { this.request = request; + this.audit = request.isAuditReads(); this.queryPlan = queryPlan; this.query = request.getQuery(); this.queryMode = query.getMode(); @@ -220,7 +227,11 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran this.logWhereSql = queryPlan.getLogWhereSql(); this.desc = request.getBeanDescriptor(); this.predicates = predicates; - this.help = createHelp(request); + if (lazyLoadManyProperty != null) { + this.help = NOOP_ADD; + } else { + this.help = createHelp(request); + } this.collection = (help != null ? help.createEmptyNoParent() : null); } @@ -233,7 +244,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran // subQuery compiled for InQueryExpression return null; } - return BeanCollectionHelpFactory.create(request); + return BeanCollectionHelpFactory.create(manyType, request); } } @@ -374,7 +385,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran */ public void close() { try { - if (auditFindIterateIds != null && !auditFindIterateIds.isEmpty()) { + if (auditFindIterate && auditIds != null && !auditIds.isEmpty()) { auditIterateLogMessage(); } } catch (Throwable e) { @@ -510,8 +521,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran } protected EntityBean next() { - if (auditFindIterate) { - auditIterateNextBean(); + if (audit) { + auditNextBean(); } hasNextCache = false; if (nextBean == null) { @@ -656,7 +667,7 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran * per SqlSelect. This can be null. */ @Override - public BeanPropertyAssocMany getManyProperty() { + public STreePropertyAssocMany getManyProperty() { return manyProperty; } @@ -747,30 +758,25 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran */ void auditFindMany() { - if (!collection.isEmpty()) { + if (auditIds != null && !auditIds.isEmpty()) { // get the id values of the underlying collection - List ids = new ArrayList<>(collection.size()); - Collection underlyingBeans = collection.getActualDetails(); - for (T underlyingBean : underlyingBeans) { - ids.add(desc.getIdForJson(underlyingBean)); - } ReadEvent futureReadEvent = query.getFutureFetchAudit(); if (futureReadEvent == null) { // normal query execution - desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, ids); + desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditIds); } else { // this query was executed via findFutureList() and the prepare() // has already been called so set the details and log futureReadEvent.setQueryKey(queryPlan.getAuditQueryKey()); futureReadEvent.setBindLog(bindLog); - futureReadEvent.setIds(ids); + futureReadEvent.setIds(auditIds); desc.readAuditFutureMany(futureReadEvent); } } } /** - * Indicate that read auditing is occurring on a this findIterate query. + * Indicate that read auditing is occurring on this findIterate query. */ void auditFindIterate() { auditFindIterate = true; @@ -780,21 +786,21 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran * Send the current buffer of findIterate collected ids to the audit log. */ private void auditIterateLogMessage() { - desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditFindIterateIds); + desc.readAuditMany(queryPlan.getAuditQueryKey(), bindLog, auditIds); // create a new list on demand with the next bean/id - auditFindIterateIds = null; + auditIds = null; } /** * Add the id to the audit id buffer and flush if needed in batches of 100. */ - private void auditIterateNextBean() { + private void auditNextBean() { - if (auditFindIterateIds == null) { - auditFindIterateIds = new ArrayList<>(100); + if (auditIds == null) { + auditIds = new ArrayList<>(100); } - auditFindIterateIds.add(desc.getIdForJson(nextBean)); - if (auditFindIterateIds.size() >= 100) { + auditIds.add(desc.getIdForJson(nextBean)); + if (auditFindIterate && auditIds.size() >= 100) { auditIterateLogMessage(); } } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 1d95f7517..43706cd79 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -18,7 +18,6 @@ import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.Binder; @@ -524,20 +523,15 @@ class CQueryBuilder { return rawSqlHandler.buildSql(request, predicates, query.getRawSql().getSql()); } - BeanPropertyAssocMany manyProp = select.getManyProperty(); - boolean useSqlLimiter = false; - StringBuilder sb = new StringBuilder(500); - String dbOrderBy = predicates.getDbOrderBy(); if (selectClause != null) { sb.append(selectClause); } else { - - useSqlLimiter = (query.hasMaxRowsOrFirstRow() && manyProp == null); + useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null); if (!useSqlLimiter) { sb.append("select "); @@ -686,7 +680,7 @@ class CQueryBuilder { throw new IllegalArgumentException("Illegal enum: "+ orderBy); } } - + /** * Append where or and based on the hasWhere flag. */ diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAdd.java b/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAdd.java new file mode 100644 index 000000000..85079b309 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAdd.java @@ -0,0 +1,21 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; + +/** + * Defines interface for adding beans to the collection which might be a List, Set or Map. + */ +public interface CQueryCollectionAdd { + + /** + * Create an empty collection. + */ + BeanCollection createEmptyNoParent(); + + /** + * Add a bean to the List Set or Map. + */ + void add(BeanCollection collection, EntityBean bean, boolean withCheck); + +} diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAddNoop.java b/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAddNoop.java new file mode 100644 index 000000000..ac4230999 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/CQueryCollectionAddNoop.java @@ -0,0 +1,27 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; + +/** + * A NOOP based CQueryCollectionAdd for use with lazy loading many queries where the + * beans loaded into the collection are added to the collection(s) of the parent(s). + */ +class CQueryCollectionAddNoop implements CQueryCollectionAdd { + + /** + * Return null as we are not collecting the beans. + */ + @Override + public BeanCollection createEmptyNoParent() { + return null; + } + + /** + * Do nothing for this case. + */ + @Override + public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { + // do nothing + } +} diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java index a9f7921cd..a0d9a46b1 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryPlan.java @@ -11,7 +11,6 @@ import io.ebeaninternal.metric.MetricFactory; import io.ebeaninternal.metric.TimedMetric; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.core.timezone.DataTimeZone; -import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot; import io.ebeaninternal.server.type.DataBind; import io.ebeaninternal.server.type.DataReader; @@ -74,7 +73,7 @@ public class CQueryPlan { /** * Encrypted properties required additional binding. */ - private final BeanProperty[] encryptedProps; + private final STreeProperty[] encryptedProps; private final CQueryPlanStats stats; @@ -177,9 +176,8 @@ public class CQueryPlan { DataBind bindEncryptedProperties(PreparedStatement stmt, Connection conn) throws SQLException { DataBind dataBind = new DataBind(dataTimeZone, stmt, conn); if (encryptedProps != null) { - for (BeanProperty encryptedProp : encryptedProps) { - String key = encryptedProp.getEncryptKey().getStringValue(); - dataBind.setString(key); + for (STreeProperty encryptedProp : encryptedProps) { + dataBind.setString(encryptedProp.getEncryptKeyAsString()); } } return dataBind; diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java index 98fe40941..5df1633c0 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryPredicates.java @@ -231,7 +231,7 @@ public class CQueryPredicates { } } - BeanPropertyAssocMany manyProperty = request.getManyProperty(); + BeanPropertyAssocMany manyProperty = request.determineMany(); if (manyProperty != null) { OrmQueryProperties chunk = query.getDetail().getChunk(manyProperty.getName(), false); SpiExpressionList filterManyExpr = chunk.getFilterMany(); diff --git a/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java new file mode 100644 index 000000000..c246c651d --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/ExtraJoin.java @@ -0,0 +1,20 @@ +package io.ebeaninternal.server.query; + +public class ExtraJoin { + + private final STreePropertyAssoc property; + private final boolean containsMany; + + public ExtraJoin(STreePropertyAssoc property, boolean containsMany) { + this.property = property; + this.containsMany = containsMany; + } + + public STreePropertyAssoc getProperty() { + return property; + } + + public boolean isContainsMany() { + return containsMany; + } +} diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java b/src/main/java/io/ebeaninternal/server/query/STreeProperty.java similarity index 85% rename from src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java rename to src/main/java/io/ebeaninternal/server/query/STreeProperty.java index 2543cc825..340766e9a 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperty.java +++ b/src/main/java/io/ebeaninternal/server/query/STreeProperty.java @@ -8,10 +8,10 @@ import java.util.List; /** * A property in the SQL Tree. - * + *

    * A BeanProperty or a dynamically created property based on formula. */ -public interface SqlTreeProperty { +public interface STreeProperty { /** * Return the property name. @@ -38,6 +38,16 @@ public interface SqlTreeProperty { */ boolean isAggregation(); + /** + * Return true if the property is a formula. + */ + boolean isFormula(); + + /** + * Return the encryption key as a string value (when the property is encrypted). + */ + String getEncryptKeyAsString(); + /** * Return the Expression language prefix (join path). */ diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java new file mode 100644 index 000000000..1213d0b55 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssoc.java @@ -0,0 +1,39 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbSqlContext; +import io.ebeaninternal.server.deploy.id.IdBinder; + +public interface STreePropertyAssoc extends STreeProperty { + + /** + * Return the extra where clause if set. + */ + String getExtraWhere(); + + /** + * Return the type of the target (other side). + */ + STreeType target(); + + /** + * Return the IdBinder of the underlying type. + */ + IdBinder getIdBinder(); + + /** + * Add a Join with the given alias. + */ + SqlJoinType addJoin(SqlJoinType joinType, String alias2, String alias, DbSqlContext ctx); + + /** + * Add a Join with the given prefix (determining the alias). + */ + SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx); + + /** + * Add a bean to the parent. + */ + void setValue(EntityBean parentBean, Object contextBean); + +} diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java new file mode 100644 index 000000000..9b6791e2f --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocMany.java @@ -0,0 +1,45 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.DbSqlContext; +import io.ebeaninternal.server.deploy.TableJoin; + +public interface STreePropertyAssocMany extends STreePropertyAssoc { + + /** + * Append exported columns to the select. + */ + void addSelectExported(DbSqlContext ctx, String prefix); + + /** + * Return true if this is a ManyToMany with history. + */ + boolean isManyToManyWithHistory(); + + /** + * Return a reference collection. + */ + BeanCollection createReferenceIfNull(EntityBean localBean); + + /** + * Return true if the property has a join table. + */ + boolean hasJoinTable(); + + /** + * Return the intersection table join. + */ + TableJoin getIntersectionTableJoin(); + + /** + * Add a bean to the collection. + */ + void addBeanToCollectionWithCreate(EntityBean contextParent, EntityBean detailBean, boolean withCheck); + + /** + * Return true if the property is excluded from history. + */ + boolean isExcludedFromHistory(); + +} diff --git a/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java new file mode 100644 index 000000000..722a43a02 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/STreePropertyAssocOne.java @@ -0,0 +1,16 @@ +package io.ebeaninternal.server.query; + +import io.ebeaninternal.server.type.ScalarType; + +public interface STreePropertyAssocOne extends STreePropertyAssoc { + + /** + * Return true if the property is an Id. + */ + boolean isAssocId(); + + /** + * Return the scalar type of the associated id property. + */ + ScalarType getIdScalarType(); +} diff --git a/src/main/java/io/ebeaninternal/server/query/STreeType.java b/src/main/java/io/ebeaninternal/server/query/STreeType.java new file mode 100644 index 000000000..e824272c0 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/query/STreeType.java @@ -0,0 +1,136 @@ +package io.ebeaninternal.server.query; + +import io.ebean.bean.EntityBean; +import io.ebean.bean.PersistenceContext; +import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.server.deploy.DbReadContext; +import io.ebeaninternal.server.deploy.InheritInfo; +import io.ebeaninternal.server.deploy.id.IdBinder; + +/** + * Bean type interface for Sql query tree. + */ +public interface STreeType { + + /** + * Return the bean short name. + */ + String getName(); + + /** + * Return true if the underlying type has an Id property. + */ + boolean hasId(); + + /** + * Return true if the type is for ElementCollection (not mapped to an entity type/class). + */ + boolean isElementType(); + + /** + * Return true if the type uses soft delete. + */ + boolean isSoftDelete(); + + /** + * Return true if the type uses history. + */ + boolean isHistorySupport(); + + /** + * Return true if the type is RawSql based. + */ + boolean isRawSqlBased(); + + /** + * Return the soft delete predicate using the given table alias. + */ + String getSoftDeletePredicate(String baseTableAlias); + + /** + * Return the scalar properties. + */ + STreeProperty[] propsBaseScalar(); + + /** + * Return the embedded bean properties. + */ + STreePropertyAssoc[] propsEmbedded(); + + /** + * Return the associated one properties. + */ + STreePropertyAssocOne[] propsOne(); + + /** + * Return the associated many properties. + */ + STreePropertyAssocMany[] propsMany(); + + /** + * Return the inheritance information for this type. + */ + InheritInfo getInheritInfo(); + + /** + * Return the IdBinder for this type. + */ + IdBinder getIdBinder(); + + /** + * Create a new entity bean instance. + */ + EntityBean createEntityBean(); + + /** + * Put the entity bean into the persistence context. + */ + Object contextPutIfAbsent(PersistenceContext persistenceContext, Object id, EntityBean localBean); + + /** + * Set draft status on the entity bean. + */ + void setDraft(EntityBean localBean); + + /** + * Invoke any post load listeners. + */ + void postLoad(Object localBean); + + /** + * Return the base table to use given the temporalMode. + */ + String getBaseTable(SpiQuery.TemporalMode temporalMode); + + /** + * Return true if the given path is an embedded bean. + */ + boolean isEmbeddedPath(String propertyPath); + + /** + * Return the bean property traversing the object graph and taking into account inheritance. + */ + STreeProperty findPropertyFromPath(String property); + + /** + * Find a known property. + */ + STreeProperty findProperty(String propName); + + /** + * Find and return property allowing for dynamic formula properties. + */ + STreeProperty findPropertyWithDynamic(String baseName); + + /** + * Return an extra join if the property path requires it. + */ + ExtraJoin extraJoin(String propertyPath); + + /** + * Load the property taking into account inheritance. + */ + void inheritanceLoad(SqlBeanLoad sqlBeanLoad, STreeProperty property, DbReadContext ctx); + + +} diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTree.java b/src/main/java/io/ebeaninternal/server/query/SqlTree.java index 8e7d1a2ee..d4207a9e8 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTree.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTree.java @@ -1,8 +1,6 @@ package io.ebeaninternal.server.query; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import java.util.ArrayList; import java.util.List; @@ -18,7 +16,7 @@ class SqlTree { /** * Property if resultSet contains master and detail rows. */ - private final BeanPropertyAssocMany manyProperty; + private final STreePropertyAssocMany manyProperty; private final Set includes; @@ -38,7 +36,7 @@ class SqlTree { /** * Encrypted Properties require additional binding. */ - private final BeanProperty[] encryptedProps; + private final STreeProperty[] encryptedProps; /** * Where clause for inheritance. @@ -51,7 +49,7 @@ class SqlTree { * Create the SqlSelectClause. */ SqlTree(String summary, SqlTreeNode rootNode, String distinctOn, String selectSql, String fromSql, String groupBy, String inheritanceWhereSql, - BeanProperty[] encryptedProps, BeanPropertyAssocMany manyProperty, Set includes, boolean includeJoins) { + STreeProperty[] encryptedProps, STreePropertyAssocMany manyProperty, Set includes, boolean includeJoins) { this.summary = summary; this.rootNode = rootNode; @@ -147,11 +145,11 @@ class SqlTree { * Return the property that is associated with the many. There can only be one * per SqlSelect. This can be null. */ - BeanPropertyAssocMany getManyProperty() { + STreePropertyAssocMany getManyProperty() { return manyProperty; } - BeanProperty[] getEncryptedProps() { + STreeProperty[] getEncryptedProps() { return encryptedProps; } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java index 5e8319a1e..ea583c833 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java @@ -1,17 +1,14 @@ package io.ebeaninternal.server.query; import io.ebean.util.SplitName; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.el.ElPropertyDeploy; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.persistence.PersistenceException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Special Map of the logical property joins to table alias. @@ -61,16 +58,11 @@ class SqlTreeAlias { /** * Add joins. */ - public void addJoin(Set propJoins, BeanDescriptor desc) { + public void addJoin(Set propJoins, STreeType desc) { if (propJoins != null) { for (String propJoin : propJoins) { - ElPropertyDeploy elProp = desc.getElPropertyDeploy(propJoin); - if (elProp == null) { - throw new PersistenceException("Invalid path " + propJoin + " from " + desc.getFullName()); - - } else if (elProp.getBeanProperty().isEmbedded()) { + if (desc.isEmbeddedPath(propJoin)) { addEmbeddedPropertyJoin(propJoin); - } else { addPropertyJoin(propJoin, joinProps); } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 8811096eb..9cfaad7e8 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -6,14 +6,8 @@ import io.ebeaninternal.api.PropertyJoin; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery.Type; import io.ebeaninternal.server.core.OrmQueryRequest; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.InheritInfo; import io.ebeaninternal.server.deploy.TableJoin; -import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.querydefn.OrmQueryProperties; import org.slf4j.Logger; @@ -37,7 +31,7 @@ public final class SqlTreeBuilder { private final SpiQuery query; - private final BeanDescriptor desc; + private final STreeType desc; private final OrmQueryDetail queryDetail; @@ -51,7 +45,7 @@ public final class SqlTreeBuilder { /** * Property if resultSet contains master and detail rows. */ - private BeanPropertyAssocMany manyProperty; + private STreePropertyAssocMany manyProperty; private final SqlTreeAlias alias; @@ -141,7 +135,7 @@ public final class SqlTreeBuilder { String fromSql = null; String inheritanceWhereSql = null; String groupBy = null; - BeanProperty[] encryptedProps = null; + STreeProperty[] encryptedProps = null; if (!rawSql) { selectSql = buildSelectClause(); fromSql = buildFromClause(); @@ -233,7 +227,7 @@ public final class SqlTreeBuilder { return ctx.getContent(); } - private void buildRoot(BeanDescriptor desc) { + private void buildRoot(STreeType desc) { rootNode = buildSelectChain(null, null, desc, null); @@ -253,26 +247,24 @@ public final class SqlTreeBuilder { * Recursively build the query tree depending on what leaves in the tree * should be included. */ - private SqlTreeNode buildSelectChain(String prefix, BeanPropertyAssoc prop, - BeanDescriptor desc, List joinList) { + private SqlTreeNode buildSelectChain(String prefix, STreePropertyAssoc prop, + STreeType desc, List joinList) { List myJoinList = new ArrayList<>(); - BeanPropertyAssocOne[] ones = desc.propertiesOne(); - for (BeanPropertyAssocOne one : ones) { + for (STreePropertyAssocOne one : desc.propsOne()) { String propPrefix = SplitName.add(prefix, one.getName()); if (isIncludeBean(propPrefix)) { selectIncludes.add(propPrefix); - buildSelectChain(propPrefix, one, one.getTargetDescriptor(), myJoinList); + buildSelectChain(propPrefix, one, one.target(), myJoinList); } } - BeanPropertyAssocMany[] manys = desc.propertiesMany(); - for (BeanPropertyAssocMany many : manys) { + for (STreePropertyAssocMany many : desc.propsMany()) { String propPrefix = SplitName.add(prefix, many.getName()); if (isIncludeMany(propPrefix, many)) { selectIncludes.add(propPrefix); - buildSelectChain(propPrefix, many, many.getTargetDescriptor(), myJoinList); + buildSelectChain(propPrefix, many, many.target(), myJoinList); } } @@ -304,24 +296,24 @@ public final class SqlTreeBuilder { Collection includes = manyWhereJoins.getPropertyJoins(); for (PropertyJoin joinProp : includes) { - BeanPropertyAssoc beanProperty = (BeanPropertyAssoc) desc.getBeanPropertyFromPath(joinProp.getProperty()); + STreePropertyAssoc beanProperty = (STreePropertyAssoc) desc.findPropertyFromPath(joinProp.getProperty()); SqlTreeNodeManyWhereJoin nodeJoin = new SqlTreeNodeManyWhereJoin(joinProp.getProperty(), beanProperty, joinProp.getSqlJoinType()); myJoinList.add(nodeJoin); } } - private SqlTreeNode buildNode(String prefix, BeanPropertyAssoc prop, BeanDescriptor desc, List myList, SqlTreeProperties props) { + private SqlTreeNode buildNode(String prefix, STreePropertyAssoc prop, STreeType desc, List myList, SqlTreeProperties props) { if (prefix == null) { buildExtraJoins(desc, myList); // Optional many property for lazy loading query - BeanPropertyAssocMany lazyLoadMany = (query == null) ? null : query.getLazyLoadMany(); + STreePropertyAssocMany lazyLoadMany = (query == null) ? null : query.getLazyLoadMany(); boolean withId = !rawNoId && !subQuery && (query == null || query.isWithId()); return new SqlTreeNodeRoot(desc, props, myList, withId, includeJoin, lazyLoadMany, temporalMode, disableLazyLoad); - } else if (prop instanceof BeanPropertyAssocMany) { - return new SqlTreeNodeManyRoot(prefix, (BeanPropertyAssocMany) prop, props, myList, temporalMode, disableLazyLoad); + } else if (prop instanceof STreePropertyAssocMany) { + return new SqlTreeNodeManyRoot(prefix, (STreePropertyAssocMany) prop, props, myList, temporalMode, disableLazyLoad); } else { // do not read Id on child beans (e.g. when used with fetch()) @@ -334,7 +326,7 @@ public final class SqlTreeBuilder { * Build extra joins to support properties used in where clause but not * already in select clause. */ - private void buildExtraJoins(BeanDescriptor desc, List myList) { + private void buildExtraJoins(STreeType desc, List myList) { if (rawSql) { return; @@ -383,25 +375,25 @@ public final class SqlTreeBuilder { * This means it can included individual properties of an embedded bean. *

    */ - private void addPropertyToSubQuery(SqlTreeProperties selectProps, BeanDescriptor desc, String propName) { + private void addPropertyToSubQuery(SqlTreeProperties selectProps, STreeType desc, String propName) { - BeanProperty p = desc.findBeanProperty(propName); + STreeProperty p = desc.findProperty(propName); if (p == null) { logger.error("property [" + propName + "]not found on " + desc + " for query - excluding it."); - } else if (p instanceof BeanPropertyAssoc && p.isEmbedded()) { + } else if (p instanceof STreePropertyAssoc && p.isEmbedded()) { // if the property is embedded we need to lookup the real column name int pos = propName.indexOf('.'); if (pos > -1) { String name = propName.substring(pos + 1); - p = ((BeanPropertyAssoc) p).getTargetDescriptor().findBeanProperty(name); + p = ((STreePropertyAssoc) p).target().findProperty(name); } } selectProps.add(p); } - private void addProperty(SqlTreeProperties selectProps, BeanDescriptor desc, + private void addProperty(SqlTreeProperties selectProps, STreeType desc, OrmQueryProperties queryProps, String propName) { if (subQuery) { @@ -418,7 +410,7 @@ public final class SqlTreeBuilder { // make sure we only included the base/embedded bean once if (!selectProps.containsProperty(baseName)) { - SqlTreeProperty p = desc.findSqlTreeProperty(baseName); + STreeProperty p = desc.findPropertyWithDynamic(baseName); if (p == null) { logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it."); @@ -436,17 +428,17 @@ public final class SqlTreeBuilder { } else { // find the property including searching the // sub class hierarchy if required - SqlTreeProperty p = desc.findSqlTreeProperty(propName); + STreeProperty p = desc.findPropertyWithDynamic(propName); if (p == null) { logger.error("property [" + propName + "] not found on " + desc + " for query - excluding it."); - p = desc.findBeanProperty("id"); + p = desc.findProperty("id"); selectProps.add(p); } else if (p.isId() && excludeIdProperty()) { // do not bother to include id for normal queries as the // id is always added (except for subQueries) - } else if (p instanceof BeanPropertyAssoc) { + } else if (p instanceof STreePropertyAssoc) { // need to check if this property should be // excluded. This occurs when this property is // included as a bean join. With a bean join @@ -463,7 +455,7 @@ public final class SqlTreeBuilder { } } - private SqlTreeProperties getBaseSelectPartial(BeanDescriptor desc, OrmQueryProperties queryProps) { + private SqlTreeProperties getBaseSelectPartial(STreeType desc, OrmQueryProperties queryProps) { SqlTreeProperties selectProps = new SqlTreeProperties(); selectProps.setReadOnly(queryProps.isReadOnly()); @@ -484,7 +476,7 @@ public final class SqlTreeBuilder { return selectProps; } - private SqlTreeProperties getBaseSelect(BeanDescriptor desc, OrmQueryProperties queryProps) { + private SqlTreeProperties getBaseSelect(STreeType desc, OrmQueryProperties queryProps) { boolean partial = queryProps != null && !queryProps.allProperties(); if (partial) { @@ -495,17 +487,16 @@ public final class SqlTreeBuilder { selectProps.setAllProperties(); // normal simple properties of the bean - selectProps.add(desc.propertiesBaseScalar()); - selectProps.add(desc.propertiesEmbedded()); + selectProps.add(desc.propsBaseScalar()); + selectProps.add(desc.propsEmbedded()); - BeanPropertyAssocOne[] propertiesOne = desc.propertiesOne(); - for (BeanPropertyAssocOne aPropertiesOne : propertiesOne) { + for (STreePropertyAssocOne propertyAssocOne : desc.propsOne()) { //noinspection StatementWithEmptyBody - if (queryProps != null && queryProps.isIncludedBeanJoin(aPropertiesOne.getName())) { + if (queryProps != null && queryProps.isIncludedBeanJoin(propertyAssocOne.getName())) { // if it is a joined bean... then don't add the property // as it will have its own entire Node in the SqlTree } else { - selectProps.add(aPropertiesOne); + selectProps.add(propertyAssocOne); } } @@ -521,7 +512,7 @@ public final class SqlTreeBuilder { /** * Return true if this many node should be included in the query. */ - private boolean isIncludeMany(String propName, BeanPropertyAssocMany manyProp) { + private boolean isIncludeMany(String propName, STreePropertyAssocMany manyProp) { if (queryDetail.isJoinsEmpty()) { return false; @@ -588,9 +579,9 @@ public final class SqlTreeBuilder { */ private final Map rootRegister = new HashMap<>(); - private final BeanDescriptor desc; + private final STreeType desc; - private IncludesDistiller(BeanDescriptor desc, Set selectIncludes, + private IncludesDistiller(STreeType desc, Set selectIncludes, Set predicateIncludes) { this.desc = desc; this.selectIncludes = selectIncludes; @@ -645,25 +636,14 @@ public final class SqlTreeBuilder { */ private SqlTreeNodeExtraJoin createJoinLeaf(String propertyName) { - ElPropertyValue elGetValue = desc.getElGetValue(propertyName); - - if (elGetValue == null) { - // this can occur for master detail queries - // with concatenated keys (so not an error now) + ExtraJoin extra = desc.extraJoin(propertyName); + if (extra == null) { return null; - } - BeanProperty beanProperty = elGetValue.getBeanProperty(); - if (beanProperty instanceof BeanPropertyAssoc) { - BeanPropertyAssoc assocProp = (BeanPropertyAssoc) beanProperty; - if (assocProp.isEmbedded()) { - // no extra join required for embedded beans - return null; - } - SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, assocProp, elGetValue.containsMany()); + } else { + SqlTreeNodeExtraJoin extraJoin = new SqlTreeNodeExtraJoin(propertyName, extra.getProperty(), extra.isContainsMany()); joinRegister.put(propertyName, extraJoin); return extraJoin; } - return null; } /** @@ -674,10 +654,8 @@ public final class SqlTreeBuilder { * not specified and is implicitly created. *

    */ - private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, - SqlTreeNodeExtraJoin childJoin) { + private SqlTreeNodeExtraJoin findExtraJoinRoot(String includeProp, SqlTreeNodeExtraJoin childJoin) { while (true) { - int dotPos = includeProp.lastIndexOf('.'); if (dotPos == -1) { // no parent possible(parent is root) diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 806e64adb..96fd09d05 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -9,11 +9,6 @@ import io.ebean.util.SplitName; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiQuery.Mode; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.InheritInfo; @@ -34,7 +29,7 @@ class SqlTreeNodeBean implements SqlTreeNode { private static final SqlTreeNode[] NO_CHILDREN = new SqlTreeNode[0]; - protected final BeanDescriptor desc; + protected final STreeType desc; protected final IdBinder idBinder; @@ -48,14 +43,14 @@ class SqlTreeNodeBean implements SqlTreeNode { */ private final boolean partialObject; - protected final SqlTreeProperty[] properties; + protected final STreeProperty[] properties; /** * Extra where clause added by Where annotation on associated many. */ private final String extraWhere; - private final BeanPropertyAssoc nodeBeanProp; + private final STreePropertyAssoc nodeBeanProp; /** * False if report bean and has no id property. @@ -70,7 +65,7 @@ class SqlTreeNodeBean implements SqlTreeNode { private final Map pathMap; - final BeanPropertyAssocMany lazyLoadParent; + final STreePropertyAssocMany lazyLoadParent; final SpiQuery.TemporalMode temporalMode; @@ -92,29 +87,29 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * Construct for leaf node. */ - SqlTreeNodeBean(String prefix, BeanPropertyAssoc beanProp, SqlTreeProperties props, + SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, SqlTreeProperties props, List myChildren, boolean withId, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { - this(prefix, beanProp, beanProp.getTargetDescriptor(), props, myChildren, withId, null, temporalMode, disableLazyLoad); + this(prefix, beanProp, beanProp.target(), props, myChildren, withId, null, temporalMode, disableLazyLoad); } /** * Construct for root node. */ - SqlTreeNodeBean(BeanDescriptor desc, SqlTreeProperties props, List myList, boolean withId, - BeanPropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { + SqlTreeNodeBean(STreeType desc, SqlTreeProperties props, List myList, boolean withId, + STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { this(null, null, desc, props, myList, withId, many, temporalMode, disableLazyLoad); } /** * Create with the appropriate node. */ - private SqlTreeNodeBean(String prefix, BeanPropertyAssoc beanProp, BeanDescriptor desc, SqlTreeProperties props, - List myChildren, boolean withId, BeanPropertyAssocMany lazyLoadParent, + private SqlTreeNodeBean(String prefix, STreePropertyAssoc beanProp, STreeType desc, SqlTreeProperties props, + List myChildren, boolean withId, STreePropertyAssocMany lazyLoadParent, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { this.lazyLoadParent = lazyLoadParent; - this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getBeanDescriptor().getIdBinder(); + this.lazyLoadParentIdBinder = (lazyLoadParent == null) ? null : lazyLoadParent.getIdBinder(); this.prefix = prefix; this.desc = desc; this.inheritInfo = desc.getInheritInfo(); @@ -129,7 +124,7 @@ class SqlTreeNodeBean implements SqlTreeNode { this.aggregationRoot = props.isAggregationRoot(); // the bean has an Id property and we want to use it - this.readId = !aggregationRoot && withId && (desc.getIdProperty() != null); + this.readId = !aggregationRoot && withId && desc.hasId(); this.disableLazyLoad = disableLazyLoad || !readId || desc.isRawSqlBased() || temporalVersions; this.partialObject = props.isPartialObject(); @@ -150,25 +145,22 @@ class SqlTreeNodeBean implements SqlTreeNode { // if we have also no children, NPE happens anyway. return children[0].getSingleAttributeScalarType(); } - if (properties[0] instanceof BeanPropertyAssocOne) { - BeanPropertyAssocOne assocOne = (BeanPropertyAssocOne)properties[0]; + if (properties[0] instanceof STreePropertyAssocOne) { + STreePropertyAssocOne assocOne = (STreePropertyAssocOne)properties[0]; if (assocOne.isAssocId()) { - return assocOne.getTargetDescriptor().getIdProperty().getScalarType(); + return assocOne.getIdScalarType(); } } return properties[0].getScalarType(); } - private Map createPathMap(String prefix, BeanDescriptor desc) { - - BeanPropertyAssocMany[] manys = desc.propertiesMany(); + private Map createPathMap(String prefix, STreeType desc) { HashMap m = new HashMap<>(); - for (BeanPropertyAssocMany many : manys) { + for (STreePropertyAssocMany many : desc.propsMany()) { String name = many.getName(); m.put(name, getPath(prefix, name)); } - return m; } @@ -189,7 +181,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } idBinder.buildRawSqlSelectChain(prefix, selectChain); } - for (SqlTreeProperty property : properties) { + for (STreeProperty property : properties) { property.buildRawSqlSelectChain(prefix, selectChain); } // recursively continue reading... @@ -228,7 +220,7 @@ class SqlTreeNodeBean implements SqlTreeNode { } Class localType; - BeanDescriptor localDesc; + STreeType localDesc; IdBinder localIdBinder; EntityBean localBean; @@ -292,21 +284,16 @@ class SqlTreeNodeBean implements SqlTreeNode { if (inheritInfo == null) { // normal behavior with no inheritance - for (SqlTreeProperty property : properties) { + for (STreeProperty property : properties) { property.load(sqlBeanLoad); } } else { // take account of inheritance and due to subclassing approach // need to get a 'local' version of the property - for (SqlTreeProperty property : properties) { + for (STreeProperty property : properties) { // get a local version of the BeanProperty - BeanProperty p = localDesc.getBeanProperty(property.getName()); - if (p != null) { - p.load(sqlBeanLoad); - } else { - property.loadIgnore(ctx); - } + localDesc.inheritanceLoad(sqlBeanLoad, property, ctx); } } @@ -374,6 +361,9 @@ class SqlTreeNodeBean implements SqlTreeNode { if (!readId || temporalVersions) { // a bean with no Id (never found in context) + if (lazyLoadParentId != null && desc.isElementType()) { + ctx.setLazyLoadedChildBean(localBean, lazyLoadParentId); + } return localBean; } else { @@ -388,13 +378,12 @@ class SqlTreeNodeBean implements SqlTreeNode { * Create lazy loading proxies for the Many's except for the one that is * included in the actual query. */ - private void createListProxies(BeanDescriptor localDesc, DbReadContext ctx, EntityBean localBean, boolean disableLazyLoad) { + private void createListProxies(STreeType localDesc, DbReadContext ctx, EntityBean localBean, boolean disableLazyLoad) { - BeanPropertyAssocMany fetchedMany = ctx.getManyProperty(); + STreePropertyAssocMany fetchedMany = ctx.getManyProperty(); // load the List/Set/Map proxy objects (deferred fetching of lists) - BeanPropertyAssocMany[] manys = localDesc.propertiesMany(); - for (BeanPropertyAssocMany many : manys) { + for (STreePropertyAssocMany many : localDesc.propsMany()) { if (fetchedMany == null || !fetchedMany.equals(many)) { // create a proxy for the many (deferred fetching) @@ -419,7 +408,7 @@ class SqlTreeNodeBean implements SqlTreeNode { if (readId) { appendSelectId(ctx, idBinder.getBeanProperty()); } - for (SqlTreeProperty property : properties) { + for (STreeProperty property : properties) { if (!property.isAggregation()) { property.appendSelect(ctx, subQuery); } @@ -486,14 +475,13 @@ class SqlTreeNodeBean implements SqlTreeNode { /** * Append the properties to the buffer. */ - private void appendSelect(DbSqlContext ctx, boolean subQuery, SqlTreeProperty[] props) { - - for (SqlTreeProperty prop : props) { + private void appendSelect(DbSqlContext ctx, boolean subQuery, STreeProperty[] props) { + for (STreeProperty prop : props) { prop.appendSelect(ctx, subQuery); } } - protected void appendSelectId(DbSqlContext ctx, BeanProperty prop) { + protected void appendSelectId(DbSqlContext ctx, STreeProperty prop) { if (prop != null) { prop.appendSelect(ctx, false); } @@ -546,7 +534,7 @@ class SqlTreeNodeBean implements SqlTreeNode { // join and return SqlJoinType to use for child joins joinType = appendFromBaseTable(ctx, joinType); - for (SqlTreeProperty property : properties) { + for (STreeProperty property : properties) { // usually nothing... except for 1-1 Exported property.appendFrom(ctx, joinType); } @@ -601,8 +589,8 @@ class SqlTreeNodeBean implements SqlTreeNode { private SqlJoinType appendFromAsJoin(DbSqlContext ctx, SqlJoinType joinType) { - if (nodeBeanProp instanceof BeanPropertyAssocMany) { - BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) nodeBeanProp; + if (nodeBeanProp instanceof STreePropertyAssocMany) { + STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp; if (manyProp.hasJoinTable()) { String alias = ctx.getTableAlias(prefix); @@ -619,7 +607,6 @@ class SqlTreeNodeBean implements SqlTreeNode { return nodeBeanProp.addJoin(joinType, alias2, alias, ctx); } - } return nodeBeanProp.addJoin(joinType, prefix, ctx); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java index ba83d4ced..17943ddd1 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeExtraJoin.java @@ -4,14 +4,11 @@ import io.ebean.Version; import io.ebean.bean.EntityBean; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.type.ScalarType; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -25,7 +22,7 @@ import java.util.List; */ class SqlTreeNodeExtraJoin implements SqlTreeNode { - private final BeanPropertyAssoc assocBeanProperty; + private final STreePropertyAssoc assocBeanProperty; private final String prefix; @@ -35,11 +32,11 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { private List children; - SqlTreeNodeExtraJoin(String prefix, BeanPropertyAssoc assocBeanProperty, boolean pathContainsMany) { + SqlTreeNodeExtraJoin(String prefix, STreePropertyAssoc assocBeanProperty, boolean pathContainsMany) { this.prefix = prefix; this.assocBeanProperty = assocBeanProperty; this.pathContainsMany = pathContainsMany; - this.manyJoin = assocBeanProperty instanceof BeanPropertyAssocMany; + this.manyJoin = assocBeanProperty instanceof STreePropertyAssocMany; } @Override @@ -103,8 +100,8 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { boolean manyToMany = false; - if (assocBeanProperty instanceof BeanPropertyAssocMany) { - BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) assocBeanProperty; + if (assocBeanProperty instanceof STreePropertyAssocMany) { + STreePropertyAssocMany manyProp = (STreePropertyAssocMany) assocBeanProperty; if (manyProp.hasJoinTable()) { manyToMany = true; @@ -127,7 +124,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { } if (!manyToMany) { if (assocBeanProperty.isFormula()) { - // add joins for formula beans + // add joins for formula beans assocBeanProperty.appendFrom(ctx, joinType); } joinType = assocBeanProperty.addJoin(joinType, prefix, ctx); @@ -164,7 +161,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { * Does nothing. */ @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException { + public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { return null; } @@ -172,7 +169,7 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode { * Does nothing. */ @Override - public Version loadVersion(DbReadContext ctx) throws SQLException { + public Version loadVersion(DbReadContext ctx) { return null; } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java index 835d201b3..edeff9fce 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyRoot.java @@ -2,7 +2,6 @@ package io.ebeaninternal.server.query; import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; @@ -11,9 +10,9 @@ import java.util.List; final class SqlTreeNodeManyRoot extends SqlTreeNodeBean { - private final BeanPropertyAssocMany manyProp; + private final STreePropertyAssocMany manyProp; - SqlTreeNodeManyRoot(String prefix, BeanPropertyAssocMany prop, SqlTreeProperties props, List myList, + SqlTreeNodeManyRoot(String prefix, STreePropertyAssocMany prop, SqlTreeProperties props, List myList, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { super(prefix, prop, props, myList, true, temporalMode, disableLazyLoad); this.manyProp = prop; diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java index 07ab86398..ae0a810ab 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeManyWhereJoin.java @@ -4,15 +4,11 @@ import io.ebean.Version; import io.ebean.bean.EntityBean; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.BeanPropertyAssoc; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.DbReadContext; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; import io.ebeaninternal.server.type.ScalarType; -import java.sql.SQLException; import java.util.List; /** @@ -24,15 +20,14 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode { private final String prefix; - private final BeanPropertyAssoc nodeBeanProp; + private final STreePropertyAssoc nodeBeanProp; /** * The many where join which is either INNER or OUTER. */ private final SqlJoinType manyJoinType; - SqlTreeNodeManyWhereJoin(String prefix, BeanPropertyAssoc prop, SqlJoinType manyJoinType) { - + SqlTreeNodeManyWhereJoin(String prefix, STreePropertyAssoc prop, SqlJoinType manyJoinType) { this.nodeBeanProp = prop; this.prefix = prefix; this.manyJoinType = manyJoinType; @@ -86,16 +81,16 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode { * Join to base table for this node. This includes a join to the * intersection table if this is a ManyToMany node. */ - void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) { + private void appendFromBaseTable(DbSqlContext ctx, SqlJoinType joinType) { String alias = ctx.getTableAliasManyWhere(prefix); String parentAlias = ctx.getTableAliasManyWhere(parentPrefix); - if (nodeBeanProp instanceof BeanPropertyAssocOne) { + if (nodeBeanProp instanceof STreePropertyAssocOne) { nodeBeanProp.addJoin(joinType, parentAlias, alias, ctx); } else { - BeanPropertyAssocMany manyProp = (BeanPropertyAssocMany) nodeBeanProp; + STreePropertyAssocMany manyProp = (STreePropertyAssocMany) nodeBeanProp; if (!manyProp.hasJoinTable()) { manyProp.addJoin(joinType, parentAlias, alias, ctx); @@ -125,13 +120,13 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode { } @Override - public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) throws SQLException { + public EntityBean load(DbReadContext ctx, EntityBean localBean, EntityBean parentBean) { // nothing to do here return null; } @Override - public Version loadVersion(DbReadContext ctx) throws SQLException { + public Version loadVersion(DbReadContext ctx) { // nothing to do here return null; } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java index bb93b25e1..74be7c415 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeRoot.java @@ -1,8 +1,6 @@ package io.ebeaninternal.server.query; import io.ebeaninternal.api.SpiQuery; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.DbSqlContext; import io.ebeaninternal.server.deploy.TableJoin; @@ -18,8 +16,8 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean { /** * Specify for SqlSelect to include an Id property or not. */ - SqlTreeNodeRoot(BeanDescriptor desc, SqlTreeProperties props, List myList, boolean withId, - TableJoin includeJoin, BeanPropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { + SqlTreeNodeRoot(STreeType desc, SqlTreeProperties props, List myList, boolean withId, + TableJoin includeJoin, STreePropertyAssocMany many, SpiQuery.TemporalMode temporalMode, boolean disableLazyLoad) { super(desc, props, myList, withId, many, temporalMode, disableLazyLoad); this.includeJoin = includeJoin; diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java index 9c717173e..5ec9b286d 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeProperties.java @@ -20,7 +20,7 @@ public class SqlTreeProperties { /** * The bean properties in order. */ - private final List propsList = new ArrayList<>(); + private final List propsList = new ArrayList<>(); /** * Maintain a list of property names to detect embedded bean additions. @@ -40,17 +40,17 @@ public class SqlTreeProperties { return propNames.contains(propName); } - public void add(SqlTreeProperty[] props) { + public void add(STreeProperty[] props) { propsList.addAll(Arrays.asList(props)); } - public void add(SqlTreeProperty prop) { + public void add(STreeProperty prop) { propsList.add(prop); propNames.add(prop.getName()); } - public SqlTreeProperty[] getProps() { - return propsList.toArray(new SqlTreeProperty[propsList.size()]); + public STreeProperty[] getProps() { + return propsList.toArray(new STreeProperty[propsList.size()]); } boolean isPartialObject() { @@ -97,7 +97,7 @@ public class SqlTreeProperties { */ private String aggregationJoin() { if (!allProperties) { - for (SqlTreeProperty beanProperty : propsList) { + for (STreeProperty beanProperty : propsList) { if (beanProperty.isAggregation()) { aggregation = true; aggregationPath = beanProperty.getElPrefix(); diff --git a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java index 6bdc89fd2..e7fa731b3 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/OrmQueryDetail.java @@ -1,11 +1,11 @@ package io.ebeaninternal.server.querydefn; import io.ebean.FetchConfig; +import io.ebean.util.SplitName; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanPropertyAssoc; import io.ebeaninternal.server.el.ElPropertyDeploy; import io.ebeaninternal.server.el.ElPropertyValue; -import io.ebean.util.SplitName; import javax.persistence.PersistenceException; import java.io.Serializable; @@ -427,7 +427,7 @@ public class OrmQueryDetail implements Serializable { for (OrmQueryProperties joinProps : fetchPaths.values()) { if (!joinProps.hasSelectClause()) { BeanDescriptor assocDesc = desc.getBeanDescriptor(joinProps.getPath()); - if (assocDesc.hasDefaultSelectClause()) { + if (assocDesc != null && assocDesc.hasDefaultSelectClause()) { fetch(joinProps.getPath(), assocDesc.getDefaultSelectClause(), joinProps.getFetchConfig()); } } diff --git a/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java b/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java index cad53baf2..e67e473f3 100644 --- a/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java +++ b/src/main/java/io/ebeanservice/docstore/api/support/DocStructure.java @@ -72,7 +72,7 @@ public class DocStructure { public void prepareMany(BeanDescriptor desc) { Set strings = embedded.keySet(); for (String prop : strings) { - BeanPropertyAssoc embProp = (BeanPropertyAssoc) desc.findBeanProperty(prop); + BeanPropertyAssoc embProp = (BeanPropertyAssoc) desc.findProperty(prop); if (embProp.isMany()) { prepare(prop, embProp); } diff --git a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java index 9526619c9..d20581c0b 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/FormulaPropertyPathTest.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; -import io.ebeaninternal.server.query.SqlTreeProperty; +import io.ebeaninternal.server.query.STreeProperty; import org.junit.Test; import org.tests.model.basic.Customer; @@ -76,7 +76,7 @@ public class FormulaPropertyPathTest extends BaseTestCase { assertThat(propertyPath.alias()).isNull(); } - SqlTreeProperty treeProperty = propertyPath.build(); + STreeProperty treeProperty = propertyPath.build(); assertThat(treeProperty).isNotNull(); } diff --git a/src/test/java/org/tests/basic/TestAnnotationBase.java b/src/test/java/org/tests/basic/TestAnnotationBase.java index e40c36cd9..f84ec99ab 100644 --- a/src/test/java/org/tests/basic/TestAnnotationBase.java +++ b/src/test/java/org/tests/basic/TestAnnotationBase.java @@ -1,13 +1,13 @@ package org.tests.basic; import io.ebean.BaseTestCase; +import io.ebean.annotation.Platform; import io.ebean.annotation.Where; import io.ebean.util.AnnotationUtil; -import io.ebean.annotation.Platform; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; -import org.tests.model.basic.ValidationGroupSomething; import org.junit.Test; +import org.tests.model.basic.ValidationGroupSomething; import javax.persistence.Entity; import javax.validation.constraints.NotNull; @@ -125,23 +125,23 @@ public class TestAnnotationBase extends BaseTestCase { @Test - public void testFindMaxSize() throws NoSuchFieldException, SecurityException { + public void testFindMaxSize() throws SecurityException { BeanDescriptor descriptor = spiEbeanServer().getBeanDescriptor(TestAnnotationBaseEntity.class); - BeanProperty bp = descriptor.findBeanProperty("constraintAnnotation"); + BeanProperty bp = descriptor.findProperty("constraintAnnotation"); assertEquals(40, bp.getDbLength()); } @Test - public void testNotNullWithGroup() throws NoSuchFieldException, SecurityException { + public void testNotNullWithGroup() throws SecurityException { BeanDescriptor descriptor = spiEbeanServer().getBeanDescriptor(TestAnnotationBaseEntity.class); - BeanProperty bp = descriptor.findBeanProperty("null1"); + BeanProperty bp = descriptor.findProperty("null1"); assertFalse(bp.isNullable()); - bp = descriptor.findBeanProperty("null2"); + bp = descriptor.findProperty("null2"); assertTrue(bp.isNullable()); - bp = descriptor.findBeanProperty("null3"); + bp = descriptor.findProperty("null3"); assertTrue(bp.isNullable()); } diff --git a/src/test/java/org/tests/model/elementcollection/EcPerson.java b/src/test/java/org/tests/model/elementcollection/EcPerson.java new file mode 100644 index 000000000..00550b5c6 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcPerson.java @@ -0,0 +1,69 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Version; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class EcPerson { + + @Id + long id; + + String name; + + @ElementCollection + @CollectionTable(name = "ec_person_phone", joinColumns = @JoinColumn(name = "owner_id", referencedColumnName = "id")) + @Column(name = "phone") + List phoneNumbers = new ArrayList<>(); + + @Version + long version; + + public EcPerson(String name) { + this.name = name; + } + + @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/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java new file mode 100644 index 000000000..dd5ea2bc3 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -0,0 +1,51 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionBasic extends BaseTestCase { + + @Test + public void test() { + + EcPerson person = new EcPerson("Fiona021"); + person.getPhoneNumbers().add("021 1234"); + person.getPhoneNumbers().add("021 4321"); + Ebean.save(person); + + + EcPerson person1 = new EcPerson("Fiona09"); + person1.getPhoneNumbers().add("09 1234"); + person1.getPhoneNumbers().add("09 4321"); + Ebean.save(person1); + + List found = + Ebean.find(EcPerson.class).where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + List phoneNumbers0 = found.get(0).getPhoneNumbers(); + List phoneNumbers1 = found.get(1).getPhoneNumbers(); + phoneNumbers0.size(); + + assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); + assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321"); + + + List found2 = + Ebean.find(EcPerson.class) + .fetch("phoneNumbers") + .where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + System.out.println(found2); + } +} From 85c43854985c1ec3e4b4e5526e58506f696a52c5 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 20 Mar 2018 17:24:35 +1300 Subject: [PATCH 0195/1036] #115 - Mapping - Add support for @ElementCollection enhancement Initial support - add simple Set support and Json support for simple List and Set. --- .../deploy/BeanCollectionHelpFactory.java | 13 ++-- .../server/deploy/BeanDescriptor.java | 10 ++- .../server/deploy/BeanDescriptorElement.java | 47 ++++++++++++- .../server/deploy/BeanDescriptorManager.java | 15 +++- .../server/deploy/BeanListHelpElement.java | 9 +-- .../server/deploy/BeanPropertyAssocMany.java | 27 ++++++++ .../deploy/BeanPropertyAssocManyJsonHelp.java | 20 +----- .../deploy/BeanPropertySimpleCollection.java | 27 ++++++++ .../server/deploy/BeanSetHelp.java | 2 +- .../server/deploy/BeanSetHelpElement.java | 30 ++++++++ .../server/deploy/ElementCollector.java | 17 +++++ .../server/deploy/ElementHelp.java | 13 ++++ .../server/deploy/ElementHelpList.java | 27 ++++++++ .../server/deploy/ElementHelpMap.java | 28 ++++++++ .../server/deploy/ElementHelpSet.java | 27 ++++++++ .../deploy/parse/AnnotationAssocManys.java | 21 ++++-- .../model/elementcollection/EcsPerson.java | 68 +++++++++++++++++++ .../TestElementCollectionBasic.java | 10 ++- .../TestElementCollectionBasicSet.java | 59 ++++++++++++++++ 19 files changed, 422 insertions(+), 48 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementHelp.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java create mode 100644 src/test/java/org/tests/model/elementcollection/EcsPerson.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java index f74a67243..86dd30126 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java @@ -18,18 +18,17 @@ public class BeanCollectionHelpFactory { /** * Create the helper based on the many property. */ - public static BeanCollectionHelp create(BeanPropertyAssocMany manyProperty) { + public static BeanCollectionHelp create(BeanPropertyAssocMany many) { - boolean elementCollection = manyProperty.isElementCollection(); - - ManyType manyType = manyProperty.getManyType(); + boolean elementCollection = many.isElementCollection(); + ManyType manyType = many.getManyType(); switch (manyType) { case LIST: - return elementCollection ? new BeanListHelpElement<>(manyProperty) : new BeanListHelp<>(manyProperty); + return elementCollection ? new BeanListHelpElement<>(many) : new BeanListHelp<>(many); case SET: - return new BeanSetHelp<>(manyProperty); + return elementCollection ? new BeanSetHelpElement<>(many) : new BeanSetHelp<>(many); case MAP: - return new BeanMapHelp<>(manyProperty); + return new BeanMapHelp<>(many); default: throw new RuntimeException("Invalid type " + manyType); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index a7614cbba..6f31713a0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -406,7 +406,7 @@ public class BeanDescriptor implements BeanType, STreeType { private final BeanDescriptorDraftHelp draftHelp; private final BeanDescriptorCacheHelp cacheHelp; - private final BeanDescriptorJsonHelp jsonHelp; + final BeanDescriptorJsonHelp jsonHelp; private DocStoreBeanAdapter docStoreAdapter; private DocumentMapping docMapping; private boolean docStoreEmbeddedInvalidation; @@ -3330,6 +3330,14 @@ public class BeanDescriptor implements BeanType, STreeType { jsonHelp.jsonWriteDirtyProperties(writeJson, bean, dirtyProps); } + public void jsonWriteElement(SpiJsonWriter ctx, Object element) { + throw new IllegalStateException("Unexpected - expect Element override"); + } + + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + throw new IllegalStateException("Unexpected - expect Element override"); + } + public void jsonWrite(SpiJsonWriter writeJson, EntityBean bean) throws IOException { jsonHelp.jsonWrite(writeJson, bean, null); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java index dd793505c..a9c6fa057 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java @@ -1,15 +1,34 @@ package io.ebeaninternal.server.deploy; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import io.ebean.PersistenceIOException; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; + +import java.io.IOException; /** * Bean descriptor used with ElementCollection (where we don't have a mapped type/class). */ -public class BeanDescriptorElement extends BeanDescriptor { +class BeanDescriptorElement extends BeanDescriptor { - public BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor deploy) { + private final ScalarType scalarType; + private final ElementHelp elementHelp; + + BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { super(owner, deploy); + this.elementHelp = elementHelp; + + BeanProperty[] props = propertiesNonTransient(); + if (props.length == 1) { + this.scalarType = props[0].getScalarType(); + } else { + this.scalarType = null; + } } public boolean isElementType() { @@ -21,4 +40,28 @@ public class BeanDescriptorElement extends BeanDescriptor { return new ElementEntityBean(properties); } + public void jsonWriteElement(SpiJsonWriter ctx, Object element) { + try { + scalarType.jsonWrite(ctx.gen(), element); + } catch (IOException e) { + throw new PersistenceIOException(e); + } + } + + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + JsonParser parser = readJson.getParser(); + ElementCollector add = elementHelp.createCollector(); + do { + JsonToken token = parser.nextToken(); + if (JsonToken.VALUE_NULL == token || JsonToken.END_ARRAY == token) { + break; + } + Object element = scalarType.jsonRead(parser); + add.addElement(element); + } while (true); + + return add.collection(); + } + } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 5824612bd..1fbb6a15c 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1658,8 +1658,19 @@ public class BeanDescriptorManager implements BeanDescriptorMap { /** * Create a BeanDescriptor for an ElementCollection target. */ - public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor) { - return new BeanDescriptorElement<>(this, elementDescriptor); + public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor, ManyType manyType) { + + return new BeanDescriptorElement<>(this, elementDescriptor, elementHelper(manyType)); + } + + private ElementHelp elementHelper(ManyType manyType) { + switch (manyType) { + case LIST: return new ElementHelpList(); + case SET: return new ElementHelpSet(); + case MAP: return new ElementHelpMap(); + default: + throw new IllegalStateException("manyType unexpected "+manyType); + } } public void visitMetrics(MetricVisitor visitor) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java index 2a0b4de96..8191bd0c6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java @@ -1,7 +1,6 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; -import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.text.json.SpiJsonWriter; @@ -24,14 +23,8 @@ public class BeanListHelpElement extends BeanListHelp { } } - @Override - public BeanCollectionAdd getBeanCollectionAdd(Object bc, String mapKey) { - return super.getBeanCollectionAdd(bc, mapKey); - } - @Override void jsonWriteElement(SpiJsonWriter ctx, Object element) { - many.jsonWriteValue(ctx, element); - //targetDescriptor.jsonWrite(ctx, (EntityBean) element); + many.jsonWriteElementValue(ctx, element); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 42d3e0667..392e24e33 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -881,4 +881,31 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST public BeanCollectionHelp getHelp() { return help; } + + public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { + throw new IllegalStateException("Never Expected"); + } + + /** + * Read the collection (JSON Array) containing entity beans. + */ + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + BeanCollection collection = createEmpty(parentBean); + BeanCollectionAdd add = getBeanCollectionAdd(collection, null); + do { + EntityBean detailBean = (EntityBean) targetDescriptor.jsonRead(readJson, name); + if (detailBean == null) { + // read the entire array + break; + } + add.addEntityBean(detailBean); + + if (parentBean != null && childMasterProperty != null) { + // bind detail bean back to master via mappedBy property + childMasterProperty.setValue(detailBean, parentBean); + } + } while (true); + + return collection; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java index faa77fb49..b4962a9e6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java @@ -3,8 +3,6 @@ package io.ebeaninternal.server.deploy; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import io.ebean.bean.BeanCollection; -import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.text.json.ReadJson; @@ -57,23 +55,7 @@ class BeanPropertyAssocManyJsonHelp { return; } - BeanCollection collection = many.createEmpty(parentBean); - BeanCollectionAdd add = many.getBeanCollectionAdd(collection, null); - do { - EntityBean detailBean = (EntityBean) many.targetDescriptor.jsonRead(readJson, many.name); - if (detailBean == null) { - // read the entire array - break; - } - add.addEntityBean(detailBean); - - if (parentBean != null && many.childMasterProperty != null) { - // bind detail bean back to master via mappedBy property - many.childMasterProperty.setValue(detailBean, parentBean); - } - } while (true); - - many.setValue(parentBean, collection); + many.setValue(parentBean, many.jsonReadCollection(readJson, parentBean)); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java index 69f79bd1c..639f6782a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java @@ -1,6 +1,12 @@ package io.ebeaninternal.server.deploy; +import io.ebean.PersistenceIOException; +import io.ebean.bean.EntityBean; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; + +import java.io.IOException; public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { @@ -27,4 +33,25 @@ public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { targetDescriptor = descriptor.getBeanDescriptor(targetType); } } + + /** + * Json write scalar value. + */ + @Override + public void jsonWriteValue(SpiJsonWriter writeJson, Object value) { + try { + scalarType.jsonWrite(writeJson.gen(), value); + } catch (IOException e) { + throw new PersistenceIOException(e); + } + } + + public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { + elementDescriptor.jsonWriteElement(ctx, element); + } + + @Override + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + return elementDescriptor.jsonReadCollection(readJson, parentBean); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java index 450ed659a..197cbae0a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java @@ -16,7 +16,7 @@ import java.util.Set; /** * Helper specifically for dealing with Sets. */ -public final class BeanSetHelp extends BaseCollectionHelp { +public class BeanSetHelp extends BaseCollectionHelp { /** * When attached to a specific many property. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java new file mode 100644 index 000000000..c490c76e1 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java @@ -0,0 +1,30 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.text.json.SpiJsonWriter; + +/** + * Helper for element collection List. + */ +public class BeanSetHelpElement extends BeanSetHelp { + + BeanSetHelpElement(BeanPropertyAssocMany many) { + super(many); + } + + @Override + public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { + Object elementValue = bean._ebean_getField(0); + if (withCheck) { + collection.internalAddWithCheck(elementValue); + } else { + collection.internalAdd(elementValue); + } + } + + @Override + void jsonWriteElement(SpiJsonWriter ctx, Object element) { + many.jsonWriteElementValue(ctx, element); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java b/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java new file mode 100644 index 000000000..c75cfff80 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java @@ -0,0 +1,17 @@ +package io.ebeaninternal.server.deploy; + +/** + * Collects (List/Set/Map) of elements. + */ +public interface ElementCollector { + + /** + * Add an element. + */ + void addElement(Object element); + + /** + * Return the populated collection/map. + */ + Object collection(); +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelp.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelp.java new file mode 100644 index 000000000..e73a2eb89 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelp.java @@ -0,0 +1,13 @@ +package io.ebeaninternal.server.deploy; + +/** + * Helper for handling ElementCollection. + */ +interface ElementHelp { + + /** + * Return a new collector. + */ + ElementCollector createCollector(); + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java new file mode 100644 index 000000000..6e3f46c34 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java @@ -0,0 +1,27 @@ +package io.ebeaninternal.server.deploy; + +import java.util.ArrayList; +import java.util.List; + +class ElementHelpList implements ElementHelp { + + @Override + public ElementCollector createCollector() { + return new Collector(); + } + + private static class Collector implements ElementCollector { + + private List list = new ArrayList<>(); + + @Override + public void addElement(Object element) { + list.add(element); + } + + @Override + public Object collection() { + return list; + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java new file mode 100644 index 000000000..1d8869cfd --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java @@ -0,0 +1,28 @@ +package io.ebeaninternal.server.deploy; + +import java.util.LinkedHashMap; +import java.util.Map; + +class ElementHelpMap implements ElementHelp { + + @Override + public ElementCollector createCollector() { + return new Collector(); + } + + private static class Collector implements ElementCollector { + + private Map map = new LinkedHashMap<>(); + + @Override + public void addElement(Object element) { + throw new RuntimeException("asd"); + //map.put() + } + + @Override + public Object collection() { + return map; + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java new file mode 100644 index 000000000..d104b1d31 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java @@ -0,0 +1,27 @@ +package io.ebeaninternal.server.deploy; + +import java.util.LinkedHashSet; +import java.util.Set; + +class ElementHelpSet implements ElementHelp { + + @Override + public ElementCollector createCollector() { + return new Collector(); + } + + private static class Collector implements ElementCollector { + + private Set set = new LinkedHashSet<>(); + + @Override + public void addElement(Object element) { + set.add(element); + } + + @Override + public Object collection() { + return set; + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 460901474..eba9a4fbb 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -189,14 +189,23 @@ class AnnotationAssocManys extends AnnotationParser { if (fullTableName == null) { fullTableName = descriptor.getBaseTable()+"_"+ CamelCaseHelper.toUnderscoreFromCamel(prop.getName()); } - //namingConvention. + + BeanTable localTable = factory.getBeanTable(descriptor.getBeanType()); + if (collectionTable != null) { + prop.getTableJoin().addJoinColumn(true, collectionTable.joinColumns(), localTable); + } + if (!prop.getTableJoin().hasJoinColumns()) { + BeanProperty localId = localTable.getIdProperty(); + if (localId != null) { + // add foreign key based on convention + String fkColName = namingConvention.getForeignKey(descriptor.getBaseTable(), localId.getName()); + prop.getTableJoin().addJoinColumn(new DeployTableJoinColumn(localId.getDbColumn(), fkColName)); + } + } + BeanTable beanTable = factory.getCollectionBeanTable(fullTableName, prop.getTargetType()); prop.setBeanTable(beanTable); - if (collectionTable != null) { - prop.getTableJoin().addJoinColumn(true, collectionTable.joinColumns(), beanTable); - } - Class elementType = prop.getTargetType(); DeployBeanDescriptor elementDescriptor = factory.createDeployDescriptor(elementType); @@ -220,7 +229,7 @@ class AnnotationAssocManys extends AnnotationParser { Class owningType = prop.getOwningType(); factory.createUnidirectional(elementDescriptor, owningType, beanTable, prop.getTableJoin()); - prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor)); + prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor, prop.getManyType())); } /** diff --git a/src/test/java/org/tests/model/elementcollection/EcsPerson.java b/src/test/java/org/tests/model/elementcollection/EcsPerson.java new file mode 100644 index 000000000..f0c854db7 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcsPerson.java @@ -0,0 +1,68 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; +import java.util.LinkedHashSet; +import java.util.Set; + +@Entity +public class EcsPerson { + + @Id + long id; + + String name; + + @ElementCollection + @CollectionTable(name = "ecs_person_phone") + @Column(name = "phone") + Set phoneNumbers = new LinkedHashSet<>(); + + @Version + long version; + + public EcsPerson(String name) { + this.name = name; + } + + @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 Set getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(Set phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java index dd5ea2bc3..54ef094cb 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -28,7 +28,7 @@ public class TestElementCollectionBasic extends BaseTestCase { Ebean.find(EcPerson.class).where() .startsWith("name", "Fiona0") .order().asc("id") - .findList(); + .findList(); List phoneNumbers0 = found.get(0).getPhoneNumbers(); List phoneNumbers1 = found.get(1).getPhoneNumbers(); @@ -46,6 +46,12 @@ public class TestElementCollectionBasic extends BaseTestCase { .order().asc("id") .findList(); - System.out.println(found2); + assertThat(found2).hasSize(2); + EcPerson foundFirst = found2.get(0); + String asJson = Ebean.json().toJson(foundFirst); + + EcPerson fromJson = Ebean.json().toBean(EcPerson.class, asJson); + + assertThat(fromJson.getPhoneNumbers()).containsAll(foundFirst.getPhoneNumbers()); } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java new file mode 100644 index 000000000..946e273f7 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java @@ -0,0 +1,59 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import java.util.List; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionBasicSet extends BaseTestCase { + + @Test + public void test() { + + EcsPerson person = new EcsPerson("Fiona021"); + person.getPhoneNumbers().add("021 1234"); + person.getPhoneNumbers().add("021 4321"); + Ebean.save(person); + + + EcsPerson person1 = new EcsPerson("Fiona09"); + person1.getPhoneNumbers().add("09 1234"); + person1.getPhoneNumbers().add("09 4321"); + person1.getPhoneNumbers().add("09 9876"); + Ebean.save(person1); + + List found = + Ebean.find(EcsPerson.class).where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + Set phoneNumbers0 = found.get(0).getPhoneNumbers(); + Set phoneNumbers1 = found.get(1).getPhoneNumbers(); + phoneNumbers0.size(); + + assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); + assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321", "09 9876"); + + + List found2 = + Ebean.find(EcsPerson.class) + .fetch("phoneNumbers") + .where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + assertThat(found2).hasSize(2); + EcsPerson foundFirst = found2.get(0); + String asJson = Ebean.json().toJson(foundFirst); + + EcsPerson fromJson = Ebean.json().toBean(EcsPerson.class, asJson); + + assertThat(fromJson.getPhoneNumbers()).containsAll(foundFirst.getPhoneNumbers()); + } +} From 057d7480b0bff080b15ae41f788b590da68ee7d2 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 21 Mar 2018 00:15:40 +1300 Subject: [PATCH 0196/1036] #115 - Mapping - Add support for @ElementCollection enhancement Add simple Map support with Json --- .../deploy/BeanCollectionHelpFactory.java | 2 +- .../server/deploy/BeanDescriptor.java | 4 + .../server/deploy/BeanDescriptorElement.java | 3 + .../deploy/BeanDescriptorElementMap.java | 97 +++++ .../server/deploy/BeanDescriptorManager.java | 6 +- .../server/deploy/BeanMapHelp.java | 5 +- .../server/deploy/BeanMapHelpElement.java | 31 ++ .../server/deploy/BeanPropertyAssocMany.java | 7 +- .../deploy/BeanPropertySimpleCollection.java | 14 +- .../server/deploy/ElementCollector.java | 5 + .../server/deploy/ElementHelpList.java | 5 + .../server/deploy/ElementHelpMap.java | 8 +- .../server/deploy/ElementHelpSet.java | 5 + .../deploy/parse/AnnotationAssocManys.java | 51 ++- .../deploy/parse/DeployCreateProperties.java | 1 - .../server/persist/DefaultPersister.java | 217 +--------- .../server/persist/SaveManyBase.java | 37 ++ .../server/persist/SaveManyBeans.java | 381 ++++++++++++++++++ .../server/persist/SaveManyPropRequest.java | 251 ------------ .../persist/SaveManySimpleCollection.java | 15 +- .../server/persist/SaveManySimpleMap.java | 52 +++ .../model/elementcollection/EcmPerson.java | 68 ++++ .../TestElementCollectionBasicMap.java | 63 +++ 23 files changed, 844 insertions(+), 484 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java delete mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java create mode 100644 src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java create mode 100644 src/test/java/org/tests/model/elementcollection/EcmPerson.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java index 86dd30126..d57b622b1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelpFactory.java @@ -28,7 +28,7 @@ public class BeanCollectionHelpFactory { case SET: return elementCollection ? new BeanSetHelpElement<>(many) : new BeanSetHelp<>(many); case MAP: - return new BeanMapHelp<>(many); + return elementCollection ? new BeanMapHelpElement<>(many) :new BeanMapHelp<>(many); default: throw new RuntimeException("Invalid type " + manyType); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 6f31713a0..8a9d0fa4b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -3330,6 +3330,10 @@ public class BeanDescriptor implements BeanType, STreeType { jsonHelp.jsonWriteDirtyProperties(writeJson, bean, dirtyProps); } + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + throw new IllegalStateException("Unexpected - expect Element override"); + } + public void jsonWriteElement(SpiJsonWriter ctx, Object element) { throw new IllegalStateException("Unexpected - expect Element override"); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java index a9c6fa057..a1c23603a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java @@ -31,6 +31,7 @@ class BeanDescriptorElement extends BeanDescriptor { } } + @Override public boolean isElementType() { return true; } @@ -40,6 +41,7 @@ class BeanDescriptorElement extends BeanDescriptor { return new ElementEntityBean(properties); } + @Override public void jsonWriteElement(SpiJsonWriter ctx, Object element) { try { scalarType.jsonWrite(ctx.gen(), element); @@ -48,6 +50,7 @@ class BeanDescriptorElement extends BeanDescriptor { } } + @Override public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { JsonParser parser = readJson.getParser(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java new file mode 100644 index 000000000..3319ba8fc --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java @@ -0,0 +1,97 @@ +package io.ebeaninternal.server.deploy; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; + +import java.io.IOException; +import java.util.Map; + +/** + * Bean descriptor used with ElementCollection (where we don't have a mapped type/class). + */ +class BeanDescriptorElementMap extends BeanDescriptor { + + private final ScalarType[] scalarTypes; + private final ElementHelp elementHelp; + private final boolean stringKey; + + BeanDescriptorElementMap(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { + super(owner, deploy); + this.elementHelp = elementHelp; + BeanProperty[] props = propertiesNonTransient(); + this.scalarTypes = new ScalarType[props.length]; + for (int i = 0; i < props.length; i++) { + scalarTypes[i] = props[i].getScalarType(); + } + this.stringKey = String.class.equals(scalarTypes[0].getType()); + } + + @Override + public boolean isElementType() { + return true; + } + + @Override + protected EntityBean createPrototypeEntityBean(Class beanType) { + return new ElementEntityBean(properties); + } + + @Override + @SuppressWarnings("unchecked") + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + ctx.writeStartObject(); + if (stringKey) { + Object key = entry.getKey(); + String keyName = (key == null) ? "null" : key.toString(); + ctx.writeFieldName(keyName); + scalarTypes[1].jsonWrite(ctx.gen(), entry.getValue()); + } else { + ctx.writeFieldName("key"); + scalarTypes[0].jsonWrite(ctx.gen(), entry.getKey()); + ctx.writeFieldName("value"); + scalarTypes[1].jsonWrite(ctx.gen(), entry.getValue()); + } + ctx.writeEndObject(); + } + + @Override + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + JsonParser parser = readJson.getParser(); + ElementCollector add = elementHelp.createCollector(); + do { + JsonToken token = parser.nextToken(); + if (token != JsonToken.START_OBJECT) { + break; + } + if (stringKey) { + String key = parser.nextFieldName(); + parser.nextToken(); + Object val = scalarTypes[0].jsonRead(parser); + add.addKeyValue(key, val); + + } else { + parser.nextFieldName(); + Object key= scalarTypes[0].jsonRead(parser); + + parser.nextFieldName(); + Object val = scalarTypes[0].jsonRead(parser); + add.addKeyValue(key, val); + } + + token = parser.nextToken(); + if (token != JsonToken.END_OBJECT) { + break; + } + + } while (true); + + return add.collection(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 1fbb6a15c..190322d07 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1660,7 +1660,11 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor, ManyType manyType) { - return new BeanDescriptorElement<>(this, elementDescriptor, elementHelper(manyType)); + ElementHelp elementHelp = elementHelper(manyType); + if (manyType.isMap()) { + return new BeanDescriptorElementMap<>(this, elementDescriptor, elementHelp); + } + return new BeanDescriptorElement<>(this, elementDescriptor, elementHelp); } private ElementHelp elementHelper(ManyType manyType) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java index 4c4e76190..b45bbc98b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java @@ -17,7 +17,7 @@ import java.util.Map.Entry; /** * Helper specifically for dealing with Maps. */ -public final class BeanMapHelp extends BaseCollectionHelp { +public class BeanMapHelp extends BaseCollectionHelp { private final BeanPropertyAssocMany many; private final BeanDescriptor targetDescriptor; @@ -175,8 +175,7 @@ public final class BeanMapHelp extends BaseCollectionHelp { if (!map.isEmpty() || ctx.isIncludeEmpty()) { ctx.beginAssocMany(name); for (Entry entry : map.entrySet()) { - //FIXME: json write map key ... - targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue()); + many.jsonWriteMapEntry(ctx, entry); } ctx.endAssocMany(); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java new file mode 100644 index 000000000..0531839e0 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java @@ -0,0 +1,31 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebean.common.BeanMap; +import io.ebeaninternal.server.text.json.SpiJsonWriter; + +public class BeanMapHelpElement extends BeanMapHelp { + + BeanMapHelpElement(BeanPropertyAssocMany many) { + super(many); + } + + @Override + public void add(BeanCollection collection, EntityBean bean, boolean withCheck) { + Object key = bean._ebean_getField(0); + Object val = bean._ebean_getField(1); + + BeanMap map = ((BeanMap) collection); + if (withCheck) { + map.internalPutWithCheck(key, val); + } else { + map.internalPut(key, val); + } + } + + @Override + void jsonWriteElement(SpiJsonWriter ctx, Object element) { + throw new IllegalStateException("not called"); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 392e24e33..0072949a6 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -882,8 +882,13 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST return help; } + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + // Writing as json array rather than object ... + targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue()); + } + public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { - throw new IllegalStateException("Never Expected"); + throw new IllegalStateException("Unexpected - expect Element override"); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java index 639f6782a..6b9d1602e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java @@ -1,12 +1,12 @@ package io.ebeaninternal.server.deploy; -import io.ebean.PersistenceIOException; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection; import io.ebeaninternal.server.text.json.ReadJson; import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; +import java.util.Map; public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { @@ -34,18 +34,12 @@ public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { } } - /** - * Json write scalar value. - */ @Override - public void jsonWriteValue(SpiJsonWriter writeJson, Object value) { - try { - scalarType.jsonWrite(writeJson.gen(), value); - } catch (IOException e) { - throw new PersistenceIOException(e); - } + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + elementDescriptor.jsonWriteMapEntry(ctx, entry); } + @Override public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { elementDescriptor.jsonWriteElement(ctx, element); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java b/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java index c75cfff80..d5b97bfdd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementCollector.java @@ -10,6 +10,11 @@ public interface ElementCollector { */ void addElement(Object element); + /** + * Add an element. + */ + void addKeyValue(Object key, Object element); + /** * Return the populated collection/map. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java index 6e3f46c34..6c95550da 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java @@ -19,6 +19,11 @@ class ElementHelpList implements ElementHelp { list.add(element); } + @Override + public void addKeyValue(Object key, Object element) { + throw new IllegalStateException("never called"); + } + @Override public Object collection() { return list; diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java index 1d8869cfd..2d970a48f 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java @@ -16,8 +16,12 @@ class ElementHelpMap implements ElementHelp { @Override public void addElement(Object element) { - throw new RuntimeException("asd"); - //map.put() + throw new IllegalStateException("never called"); + } + + @Override + public void addKeyValue(Object key, Object element) { + map.put(key, element); } @Override diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java index d104b1d31..53a47de89 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java @@ -19,6 +19,11 @@ class ElementHelpSet implements ElementHelp { set.add(element); } + @Override + public void addKeyValue(Object key, Object element) { + throw new IllegalStateException("never called"); + } + @Override public Object collection() { return set; diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index eba9a4fbb..7c98d20c4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -29,6 +29,7 @@ import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.MapKey; +import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.OrderColumn; @@ -212,24 +213,50 @@ class AnnotationAssocManys extends AnnotationParser { elementDescriptor.setBaseTable(new TableName(fullTableName), readConfig.getAsOfViewSuffix(), readConfig.getVersionsBetweenSuffix()); ScalarType scalarType = util.getTypeManager().getScalarType(elementType); - DeployBeanProperty elementProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); - elementProp.setName("value"); - elementProp.setDbColumn(prop.getDbColumn()); + int sortOrder = 0; + if (!prop.getManyType().isMap()) { + elementDescriptor.setProperties(new String[]{"value"}); + } else { + elementDescriptor.setProperties(new String[]{"key", "value"}); + String dbKeyColumn = "key"; + MapKeyColumn mapKeyColumn = get(prop, MapKeyColumn.class); + if (mapKeyColumn != null) { + dbKeyColumn = mapKeyColumn.name(); + } + + DeployBeanProperty keyProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); + setElementProperty(keyProp, "key", dbKeyColumn, sortOrder++); + elementDescriptor.addBeanProperty(keyProp); + if (mapKeyColumn != null) { + keyProp.setDbLength(mapKeyColumn.length()); + keyProp.setDbScale(mapKeyColumn.scale()); + } + } + + DeployBeanProperty valueProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); + setElementProperty(valueProp, "value", prop.getDbColumn(), sortOrder++); + if (column != null) { + valueProp.setDbLength(column.length()); + valueProp.setDbScale(column.scale()); + } + + elementDescriptor.addBeanProperty(valueProp); + elementDescriptor.setName(prop.getFullBeanName()); + + factory.createUnidirectional(elementDescriptor, prop.getOwningType(), beanTable, prop.getTableJoin()); + prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor, prop.getManyType())); + } + + private void setElementProperty(DeployBeanProperty elementProp, String name, String dbColumn, int sortOrder) { + elementProp.setName(name); + elementProp.setDbColumn(dbColumn); elementProp.setNullable(false); elementProp.setDbInsertable(true); elementProp.setDbUpdateable(true); elementProp.setDbRead(true); + elementProp.setSortOrder(sortOrder); elementProp.setElementProperty(); - - elementDescriptor.addBeanProperty(elementProp); - elementDescriptor.setProperties(new String[]{"value"}); - elementDescriptor.setName(prop.getFullBeanName()); - - Class owningType = prop.getOwningType(); - - factory.createUnidirectional(elementDescriptor, owningType, beanTable, prop.getTableJoin()); - prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor, prop.getManyType())); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployCreateProperties.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployCreateProperties.java index e1a96c042..29c64d4d1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployCreateProperties.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployCreateProperties.java @@ -213,7 +213,6 @@ public class DeployCreateProperties { } catch (NullPointerException e) { logger.debug("expected non-scalar type {}", e.getMessage()); } - // TODO: Handle Collection of CompoundType and Embedded Type return new DeployBeanPropertyAssocMany(desc, targetType, manyType); } diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 7a9748649..f02969461 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -29,7 +29,6 @@ import io.ebeaninternal.server.deploy.BeanManager; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; -import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection; import io.ebeaninternal.server.deploy.IntersectionRow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -554,7 +553,7 @@ public final class DefaultPersister implements Persister { /** * Execute the delete request returning true if a delete occurred. */ - private int deleteRequest(PersistRequestBean req) { + int deleteRequest(PersistRequestBean req) { return deleteRequest(req, null); } @@ -890,7 +889,7 @@ public final class DefaultPersister implements Persister { for (BeanPropertyAssocMany many : desc.propertiesManySave()) { // check that property is loaded and collection should be cascaded to if (request.isLoadedProperty(many) && !many.isSkipSaveBeanCollection(parentBean, insertedParent)) { - saveMany2(insertedParent, many, parentBean, request); + saveMany(insertedParent, many, parentBean, request); if (!insertedParent) { request.addUpdatedManyProperty(many); } @@ -898,201 +897,23 @@ public final class DefaultPersister implements Persister { } } - private void saveMany2(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { - saveMany(saveManyRequest(insertedParent, many, parentBean, request)); + private void saveMany(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + saveManyRequest(insertedParent, many, parentBean, request).save(); } - private SaveManyPropRequest saveManyRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { - if (many instanceof BeanPropertySimpleCollection) { + private SaveManyBase saveManyRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + if (!many.isElementCollection()) { + return new SaveManyBeans(insertedParent, many, parentBean, request, this); + + } else if (many.getManyType().isMap()) { + return new SaveManySimpleMap(insertedParent, many, parentBean, request); + + } else { return new SaveManySimpleCollection(insertedParent, many, parentBean, request); - } else { - return new SaveManyPropRequest(insertedParent, many, parentBean, request); } } - private void saveMany(SaveManyPropRequest saveMany) { - - if (saveMany.getMany().hasJoinTable()) { - - // check if we can save the m2m intersection in this direction - // we only allow one direction based on first traversed basis - boolean saveIntersectionFromThisDirection = saveMany.isSaveIntersection(); - if (saveMany.isCascade()) { - saveAssocManyDetails(saveMany, false); - } - // for ManyToMany save the 'relationship' via inserts/deletes - // into/from the intersection table - if (saveIntersectionFromThisDirection) { - // only allowed on one direction of a m2m based on beanName - saveAssocManyIntersection(saveMany, saveMany.isDeleteMissingChildren()); - } else { - saveMany.resetModifyState(); - } - } else { - if (saveMany.isModifyListenMode()) { - // delete any removed beans via private owned. Needs to occur before - // a 'deleteMissingChildren' statement occurs - removeAssocManyPrivateOwned(saveMany); - } - if (saveMany.isCascade()) { - // potentially deletes 'missing children' for 'stateless update' - saveAssocManyDetails(saveMany, saveMany.isDeleteMissingChildren()); - } - } - } - - private void removeAssocManyPrivateOwned(SaveManyPropRequest saveMany) { - - Object details = saveMany.getValue(); - - // check that the list is not null and if it is a BeanCollection - // check that is has been populated (don't trigger lazy loading) - if (details instanceof BeanCollection) { - - BeanCollection c = (BeanCollection) details; - Set modifyRemovals = c.getModifyRemovals(); - saveMany.modifyListenReset(c); - if (modifyRemovals != null && !modifyRemovals.isEmpty()) { - for (Object removedBean : modifyRemovals) { - if (removedBean instanceof EntityBean) { - EntityBean eb = (EntityBean) removedBean; - if (eb._ebean_getIntercept().isLoaded()) { - // only delete if the bean was loaded meaning that it is known to exist in the DB - deleteRequest(createPublishRequest(removedBean, saveMany.getTransaction(), PersistRequest.Type.DELETE, saveMany.getFlags())); - } - } - } - } - } - } - - /** - * Save the details from a OneToMany collection. - */ - private void saveAssocManyDetails(SaveManyPropRequest saveMany, boolean deleteMissingChildren) { - - saveMany.saveDetails(this, deleteMissingChildren); - } - - /** - * Save the additions and removals from a ManyToMany collection as inserts - * and deletes from the intersection table. - *

    - * This is done via MapBeans. - *

    - */ - private void saveAssocManyIntersection(SaveManyPropRequest saveManyPropRequest, boolean deleteMissingChildren) { - - BeanPropertyAssocMany prop = saveManyPropRequest.getMany(); - Object value = prop.getValue(saveManyPropRequest.getParentBean()); - if (value == null) { - return; - } - - SpiTransaction t = saveManyPropRequest.getTransaction(); - boolean vanillaCollection = !(value instanceof BeanCollection); - - if (vanillaCollection || deleteMissingChildren) { - // delete all intersection rows and then treat all - // beans in the collection as additions - deleteAssocManyIntersection(saveManyPropRequest.getParentBean(), prop, t, saveManyPropRequest.isPublish()); - } - - Collection deletions = null; - Collection additions; - - if (saveManyPropRequest.isInsertedParent() || vanillaCollection || deleteMissingChildren) { - // treat everything in the list/set/map as an intersection addition - if (value instanceof Map) { - additions = ((Map) value).values(); - } else if (value instanceof Collection) { - additions = (Collection) value; - } else { - String msg = "Unhandled ManyToMany type " + value.getClass().getName() + " for " + prop.getFullBeanName(); - throw new PersistenceException(msg); - } - if (!vanillaCollection) { - BeanCollection manyValue = (BeanCollection) value; - setListenMode(manyValue, prop); - manyValue.modifyReset(); - } - } else { - // BeanCollection so get the additions/deletions - BeanCollection manyValue = (BeanCollection) value; - if (setListenMode(manyValue, prop)) { - additions = manyValue.getActualDetails(); - } else { - additions = manyValue.getModifyAdditions(); - deletions = manyValue.getModifyRemovals(); - } - // reset so the changes are only processed once - manyValue.modifyReset(); - } - - t.depth(+1); - - if (additions != null && !additions.isEmpty()) { - // ensure any cascade batch has been flushed prior - // to inserting into the intersection table - t.flushBatch(); - - for (Object other : additions) { - EntityBean otherBean = (EntityBean) other; - // the object from the 'other' side of the ManyToMany - if (deletions != null && deletions.remove(otherBean)) { - String m = "Inserting and Deleting same object? " + otherBean; - if (t.isLogSummary()) { - t.logSummary(m); - } - logger.warn(m); - - } else { - if (!prop.hasImportedId(otherBean)) { - String msg = "ManyToMany bean " + otherBean + " does not have an Id value."; - throw new PersistenceException(msg); - - } else { - // build a intersection row for 'insert' - IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherBean, saveManyPropRequest.isPublish()); - SqlUpdate sqlInsert = intRow.createInsert(server); - executeSqlUpdate(sqlInsert, t); - } - } - } - } - if (deletions != null && !deletions.isEmpty()) { - // ensure any cascade batch has been flushed prior - // to inserting into the intersection table - t.flushBatch(); - - for (Object other : deletions) { - EntityBean otherDelete = (EntityBean) other; - // the object from the 'other' side of the ManyToMany - // build a intersection row for 'delete' - IntersectionRow intRow = prop.buildManyToManyMapBean(saveManyPropRequest.getParentBean(), otherDelete, saveManyPropRequest.isPublish()); - SqlUpdate sqlDelete = intRow.createDelete(server, false); - executeSqlUpdate(sqlDelete, t); - } - } - - // decrease the depth back to what it was - t.depth(-1); - } - - /** - * Check if we need to set the listen mode (on new collections persisted for the first time). - */ - private boolean setListenMode(BeanCollection manyValue, BeanPropertyAssocMany prop) { - ModifyListenMode mode = manyValue.getModifyListening(); - if (mode == null) { - // new collection persisted for the first time - manyValue.setModifyListening(prop.getModifyListenMode()); - return true; - } - return false; - } - - private void deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany many, Transaction t, boolean publish) { + void deleteAssocManyIntersection(EntityBean bean, BeanPropertyAssocMany many, Transaction t, boolean publish) { // delete all intersection rows for this bean IntersectionRow intRow = many.buildManyToManyDeleteChildren(bean, publish); @@ -1241,9 +1062,7 @@ public final class DefaultPersister implements Persister { BeanDescriptor desc = request.getBeanDescriptor(); // imported ones with save cascade - BeanPropertyAssocOne[] ones = desc.propertiesOneImportedSave(); - - for (BeanPropertyAssocOne prop : ones) { + for (BeanPropertyAssocOne prop : desc.propertiesOneImportedSave()) { // check for partial objects if (request.isLoadedProperty(prop)) { EntityBean detailBean = prop.getValueAsEntityBean(request.getEntityBean()); @@ -1277,8 +1096,7 @@ public final class DefaultPersister implements Persister { DeleteUnloadedForeignKeys fkeys = null; - BeanPropertyAssocOne[] ones = request.getBeanDescriptor().propertiesOneImportedDelete(); - for (BeanPropertyAssocOne one : ones) { + for (BeanPropertyAssocOne one : request.getBeanDescriptor().propertiesOneImportedDelete()) { if (!request.isLoadedProperty(one)) { // we have cascade Delete on a partially populated bean and // this property was not loaded (so we are going to have to fetch it) @@ -1299,8 +1117,7 @@ public final class DefaultPersister implements Persister { boolean softDelete = request.isSoftDelete(); - BeanPropertyAssocOne[] ones = request.getBeanDescriptor().propertiesOneImportedDelete(); - for (BeanPropertyAssocOne prop : ones) { + for (BeanPropertyAssocOne prop : request.getBeanDescriptor().propertiesOneImportedDelete()) { if (!softDelete || prop.isTargetSoftDelete()) { if (request.isLoadedProperty(prop)) { Object detailBean = prop.getValue(request.getEntityBean()); @@ -1355,7 +1172,7 @@ public final class DefaultPersister implements Persister { /** * Create the Persist Request Object additionally specifying the publish status. */ - private PersistRequestBean createPublishRequest(T bean, Transaction t, PersistRequest.Type type, int flags) { + PersistRequestBean createPublishRequest(T bean, Transaction t, PersistRequest.Type type, int flags) { return createRequestInternal(bean, t, type, Flags.unsetRecuse(flags)); } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java new file mode 100644 index 000000000..61a080188 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java @@ -0,0 +1,37 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.SpiTransaction; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; + +/** + * Base for saving entity bean collections and element collections. + */ +abstract class SaveManyBase { + + final PersistRequestBean request; + final SpiEbeanServer server; + final boolean insertedParent; + final BeanPropertyAssocMany many; + final SpiTransaction transaction; + final EntityBean parentBean; + final Object value; + + SaveManyBase(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + this.request = request; + this.server = request.getServer(); + this.insertedParent = insertedParent; + this.many = many; + this.parentBean = parentBean; + this.transaction = request.getTransaction(); + this.value = many.getValue(parentBean); + } + + /** + * Save the collection. + */ + abstract void save(); + +} diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java new file mode 100644 index 000000000..cdd84d158 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java @@ -0,0 +1,381 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.SqlUpdate; +import io.ebean.bean.BeanCollection; +import io.ebean.bean.EntityBean; +import io.ebean.bean.EntityBeanIntercept; +import io.ebeaninternal.server.core.PersistRequest; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanCollectionUtil; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.IntersectionRow; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.PersistenceException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Saves the details for a OneToMany or ManyToMany relationship (entity beans). + */ +class SaveManyBeans extends SaveManyBase { + + private static final Logger log = LoggerFactory.getLogger(SaveManyBeans.class); + + private final boolean cascade; + private final boolean publish; + private final BeanDescriptor targetDescriptor; + private final boolean isMap; + private final boolean saveRecurseSkippable; + + private Collection collection; + private DefaultPersister persister; + private boolean deleteMissing; + private int sortOrder; + + SaveManyBeans(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request, DefaultPersister persister) { + super(insertedParent, many, parentBean, request); + this.persister = persister; + this.cascade = many.getCascadeInfo().isSave(); + this.publish = request.isPublish(); + this.targetDescriptor = many.getTargetDescriptor(); + this.isMap = many.getManyType().isMap(); + this.saveRecurseSkippable = many.isSaveRecurseSkippable(); + } + + @Override + void save() { + + if (many.hasJoinTable()) { + + // check if we can save the m2m intersection in this direction + // we only allow one direction based on first traversed basis + boolean saveIntersectionFromThisDirection = isSaveIntersection(); + if (cascade) { + saveAssocManyDetails( false); + } + // for ManyToMany save the 'relationship' via inserts/deletes + // into/from the intersection table + if (saveIntersectionFromThisDirection) { + // only allowed on one direction of a m2m based on beanName + saveAssocManyIntersection(request.isDeleteMissingChildren()); + } else { + resetModifyState(); + } + } else { + if (isModifyListenMode()) { + // delete any removed beans via private owned. Needs to occur before + // a 'deleteMissingChildren' statement occurs + removeAssocManyPrivateOwned(); + } + if (cascade) { + // potentially deletes 'missing children' for 'stateless update' + saveAssocManyDetails(request.isDeleteMissingChildren()); + } + } + } + + private boolean isSaveIntersection() { + return transaction.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName()); + } + + private boolean isModifyListenMode() { + return BeanCollection.ModifyListenMode.REMOVALS == many.getModifyListenMode(); + } + + private void modifyListenReset(BeanCollection c) { + if (insertedParent) { + // after insert set the modify listening mode for private owned etc + c.setModifyListening(many.getModifyListenMode()); + } + c.modifyReset(); + } + + private void resetModifyState() { + if (value instanceof BeanCollection) { + modifyListenReset((BeanCollection) value); + } + } + + /** + * Save the details from a OneToMany collection. + */ + private void saveAssocManyDetails(boolean deleteMissingChildren) { + + this.deleteMissing = deleteMissingChildren; + + // check that the list is not null and if it is a BeanCollection + // check that is has been populated (don't trigger lazy loading) + + collection = BeanCollectionUtil.getActualEntries(value); + if (collection != null) { + processDetails(); + } + } + + private void processDetails() { + + BeanProperty orderColumn = null; + boolean hasOrderColumn = many.hasOrderColumn(); + if (hasOrderColumn) { + if (!insertedParent && canSkipForOrderColumn()) { + return; + } + orderColumn = targetDescriptor.getOrderColumn(); + } + + if (insertedParent) { + // performance optimisation for large collections + targetDescriptor.preAllocateIds(collection.size()); + } + + if (deleteMissing) { + // collect the Id's (to exclude from deleteManyDetails) + List detailIds = collectIds(collection, targetDescriptor, isMap); + // deleting missing children - children not in our collected detailIds + persister.deleteManyDetails(transaction, many.getBeanDescriptor(), parentBean, many, detailIds, false); + } + + transaction.depth(+1); + saveAllBeans(orderColumn); + if (hasOrderColumn) { + resetModifyState(); + } + transaction.depth(-1); + } + + + private void saveAllBeans(BeanProperty orderColumn) { + + // if a map, then we get the key value and + // set it to the appropriate property on the + // detail bean before we save it + Object mapKeyValue = null; + boolean skipSavingThisBean; + + for (Object detailBean : collection) { + sortOrder++; + if (isMap) { + // its a map so need the key and value + Map.Entry entry = (Map.Entry) detailBean; + mapKeyValue = entry.getKey(); + detailBean = entry.getValue(); + } + + if (detailBean instanceof EntityBean) { + EntityBean detail = (EntityBean) detailBean; + EntityBeanIntercept ebi = detail._ebean_getIntercept(); + if (many.hasJoinTable()) { + skipSavingThisBean = targetDescriptor.isReference(ebi); + } else { + if (orderColumn != null) { + orderColumn.setValue(detail, sortOrder); + ebi.setDirty(true); + } + if (targetDescriptor.isReference(ebi)) { + // we can skip this one + skipSavingThisBean = true; + + } else if (ebi.isNewOrDirty()) { + skipSavingThisBean = false; + // set the parent bean to detailBean + many.setJoinValuesToChild(parentBean, detail, mapKeyValue); + + } else { + // unmodified so skip depending on prop.isSaveRecurseSkippable(); + skipSavingThisBean = saveRecurseSkippable; + } + } + + if (!skipSavingThisBean) { + persister.saveRecurse(detail, transaction, parentBean, request.getFlags()); + } + } + } + } + + /** + * Return true if we can skip based on .. no modifications to the collection and no beans are dirty. + */ + private boolean canSkipForOrderColumn() { + return value instanceof BeanCollection + && !((BeanCollection) value).wasTouched() + && noDirtyBeans(); + } + + private boolean noDirtyBeans() { + for (Object bean : collection) { + if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isDirty()) { + return false; + } + } + return true; + } + + /** + * Collect the Id values of the details to remove 'missing children' for stateless updates. + */ + private List collectIds(Collection collection, BeanDescriptor targetDescriptor, boolean isMap) { + + List detailIds = new ArrayList<>(); + // stateless update with deleteMissingChildren so first + // collect the Id values to remove the 'missing children' + for (Object detailBean : collection) { + if (isMap) { + detailBean = ((Map.Entry) detailBean).getValue(); + } + if (detailBean instanceof EntityBean) { + Object id = targetDescriptor.getId((EntityBean) detailBean); + if (!DmlUtil.isNullOrZero(id)) { + // remember the Id (other details not in the collection) will be removed + detailIds.add(id); + } + } + } + return detailIds; + } + + /** + * Save the additions and removals from a ManyToMany collection as inserts + * and deletes from the intersection table. + *

    + * This is done via MapBeans. + *

    + */ + private void saveAssocManyIntersection(boolean deleteMissingChildren) { + + if (value == null) { + return; + } + + //SpiTransaction t = saveManyPropRequest.getTransaction(); + boolean vanillaCollection = !(value instanceof BeanCollection); + + if (vanillaCollection || deleteMissingChildren) { + // delete all intersection rows and then treat all + // beans in the collection as additions + persister.deleteAssocManyIntersection(parentBean, many, transaction, publish); + } + + Collection deletions = null; + Collection additions; + + if (insertedParent || vanillaCollection || deleteMissingChildren) { + // treat everything in the list/set/map as an intersection addition + if (value instanceof Map) { + additions = ((Map) value).values(); + } else if (value instanceof Collection) { + additions = (Collection) value; + } else { + throw new PersistenceException("Unhandled ManyToMany type " + value.getClass().getName() + " for " + many.getFullBeanName()); + } + if (!vanillaCollection) { + BeanCollection manyValue = (BeanCollection) value; + setListenMode(manyValue, many); + manyValue.modifyReset(); + } + } else { + // BeanCollection so get the additions/deletions + BeanCollection manyValue = (BeanCollection) value; + if (setListenMode(manyValue, many)) { + additions = manyValue.getActualDetails(); + } else { + additions = manyValue.getModifyAdditions(); + deletions = manyValue.getModifyRemovals(); + } + // reset so the changes are only processed once + manyValue.modifyReset(); + } + + transaction.depth(+1); + + if (additions != null && !additions.isEmpty()) { + // ensure any cascade batch has been flushed prior + // to inserting into the intersection table + transaction.flushBatch(); + + for (Object other : additions) { + EntityBean otherBean = (EntityBean) other; + // the object from the 'other' side of the ManyToMany + if (deletions != null && deletions.remove(otherBean)) { + String m = "Inserting and Deleting same object? " + otherBean; + if (transaction.isLogSummary()) { + transaction.logSummary(m); + } + log.warn(m); + + } else { + if (!many.hasImportedId(otherBean)) { + String msg = "ManyToMany bean " + otherBean + " does not have an Id value."; + throw new PersistenceException(msg); + + } else { + // build a intersection row for 'insert' + IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherBean, publish); + SqlUpdate sqlInsert = intRow.createInsert(server); + persister.executeSqlUpdate(sqlInsert, transaction); + } + } + } + } + if (deletions != null && !deletions.isEmpty()) { + // ensure any cascade batch has been flushed prior + // to inserting into the intersection table + transaction.flushBatch(); + + for (Object other : deletions) { + EntityBean otherDelete = (EntityBean) other; + // the object from the 'other' side of the ManyToMany + // build a intersection row for 'delete' + IntersectionRow intRow = many.buildManyToManyMapBean(parentBean, otherDelete, publish); + SqlUpdate sqlDelete = intRow.createDelete(server, false); + persister.executeSqlUpdate(sqlDelete, transaction); + } + } + + // decrease the depth back to what it was + transaction.depth(-1); + } + + private void removeAssocManyPrivateOwned() { + + // check that the list is not null and if it is a BeanCollection + // check that is has been populated (don't trigger lazy loading) + if (value instanceof BeanCollection) { + + BeanCollection c = (BeanCollection) value; + Set modifyRemovals = c.getModifyRemovals(); + modifyListenReset(c); + if (modifyRemovals != null && !modifyRemovals.isEmpty()) { + for (Object removedBean : modifyRemovals) { + if (removedBean instanceof EntityBean) { + EntityBean eb = (EntityBean) removedBean; + if (eb._ebean_getIntercept().isLoaded()) { + // only delete if the bean was loaded meaning that it is known to exist in the DB + persister.deleteRequest(persister.createPublishRequest(removedBean, transaction, PersistRequest.Type.DELETE, request.getFlags())); + } + } + } + } + } + } + + /** + * Check if we need to set the listen mode (on new collections persisted for the first time). + */ + private boolean setListenMode(BeanCollection manyValue, BeanPropertyAssocMany prop) { + BeanCollection.ModifyListenMode mode = manyValue.getModifyListening(); + if (mode == null) { + // new collection persisted for the first time + manyValue.setModifyListening(prop.getModifyListenMode()); + return true; + } + return false; + } +} diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java deleted file mode 100644 index dbd643d2f..000000000 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyPropRequest.java +++ /dev/null @@ -1,251 +0,0 @@ -package io.ebeaninternal.server.persist; - -import io.ebean.bean.BeanCollection; -import io.ebean.bean.EntityBean; -import io.ebean.bean.EntityBeanIntercept; -import io.ebeaninternal.api.SpiTransaction; -import io.ebeaninternal.server.core.PersistRequestBean; -import io.ebeaninternal.server.deploy.BeanCollectionUtil; -import io.ebeaninternal.server.deploy.BeanDescriptor; -import io.ebeaninternal.server.deploy.BeanProperty; -import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -import io.ebeaninternal.server.deploy.ManyType; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - -/** - * Helper to wrap the details when saving a OneToMany or ManyToMany relationship. - */ -class SaveManyPropRequest { - - final PersistRequestBean request; - private final boolean insertedParent; - final BeanPropertyAssocMany many; - final EntityBean parentBean; - final SpiTransaction transaction; - private final boolean cascade; - private final boolean deleteMissingChildren; - private final boolean publish; - - private final Object value; - private final BeanDescriptor targetDescriptor; - private final boolean isMap; - private final boolean saveRecurseSkippable; - - Collection collection; - DefaultPersister persister; - private boolean deleteMissing; - private int sortOrder; - - SaveManyPropRequest(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { - this.request = request; - this.insertedParent = insertedParent; - this.many = many; - this.cascade = many.getCascadeInfo().isSave(); - this.parentBean = parentBean; - this.transaction = request.getTransaction(); - this.deleteMissingChildren = request.isDeleteMissingChildren(); - this.publish = request.isPublish(); - this.value = many.getValue(parentBean); - this.targetDescriptor = many.getTargetDescriptor(); - this.isMap = ManyType.MAP == many.getManyType(); - this.saveRecurseSkippable = many.isSaveRecurseSkippable(); - } - - public boolean isSaveIntersection() { - return transaction.isSaveAssocManyIntersection(many.getIntersectionTableJoin().getTable(), many.getBeanDescriptor().getName()); - } - - Object getValue() { - return value; - } - - boolean isModifyListenMode() { - return BeanCollection.ModifyListenMode.REMOVALS == many.getModifyListenMode(); - } - - boolean isDeleteMissingChildren() { - return deleteMissingChildren; - } - - public int getFlags() { - return request.getFlags(); - } - - boolean isInsertedParent() { - return insertedParent; - } - - BeanPropertyAssocMany getMany() { - return many; - } - - EntityBean getParentBean() { - return parentBean; - } - - SpiTransaction getTransaction() { - return transaction; - } - - boolean isCascade() { - return cascade; - } - - boolean isPublish() { - return publish; - } - - void modifyListenReset(BeanCollection c) { - if (insertedParent) { - // after insert set the modify listening mode for private owned etc - c.setModifyListening(many.getModifyListenMode()); - } - c.modifyReset(); - } - - void resetModifyState() { - if (value instanceof BeanCollection) { - modifyListenReset((BeanCollection) value); - } - } - - void saveDetails(DefaultPersister persister, boolean deleteMissing) { - - this.persister = persister; - this.deleteMissing = deleteMissing; - - // check that the list is not null and if it is a BeanCollection - // check that is has been populated (don't trigger lazy loading) - // For a Map this is a collection of Map.Entry objects and not beans - collection = BeanCollectionUtil.getActualEntries(value); - if (collection != null) { - processDetails(); - } - } - - void processDetails() { - - BeanProperty orderColumn = null; - boolean hasOrderColumn = many.hasOrderColumn(); - if (hasOrderColumn) { - if (!insertedParent && canSkipForOrderColumn()) { - return; - } - orderColumn = targetDescriptor.getOrderColumn(); - } - - if (insertedParent) { - // performance optimisation for large collections - targetDescriptor.preAllocateIds(collection.size()); - } - - if (deleteMissing) { - // collect the Id's (to exclude from deleteManyDetails) - List detailIds = collectIds(collection, targetDescriptor, isMap); - // deleting missing children - children not in our collected detailIds - persister.deleteManyDetails(transaction, many.getBeanDescriptor(), parentBean, many, detailIds, false); - } - - transaction.depth(+1); - saveAllBeans(orderColumn); - if (hasOrderColumn) { - resetModifyState(); - } - transaction.depth(-1); - } - - - private void saveAllBeans(BeanProperty orderColumn) { - - // if a map, then we get the key value and - // set it to the appropriate property on the - // detail bean before we save it - Object mapKeyValue = null; - boolean skipSavingThisBean; - - for (Object detailBean : collection) { - sortOrder++; - if (isMap) { - // its a map so need the key and value - Map.Entry entry = (Map.Entry) detailBean; - mapKeyValue = entry.getKey(); - detailBean = entry.getValue(); - } - - if (detailBean instanceof EntityBean) { - EntityBean detail = (EntityBean) detailBean; - EntityBeanIntercept ebi = detail._ebean_getIntercept(); - if (many.hasJoinTable()) { - skipSavingThisBean = targetDescriptor.isReference(ebi); - } else { - if (orderColumn != null) { - orderColumn.setValue(detail, sortOrder); - ebi.setDirty(true); - } - if (targetDescriptor.isReference(ebi)) { - // we can skip this one - skipSavingThisBean = true; - - } else if (ebi.isNewOrDirty()) { - skipSavingThisBean = false; - // set the parent bean to detailBean - many.setJoinValuesToChild(parentBean, detail, mapKeyValue); - - } else { - // unmodified so skip depending on prop.isSaveRecurseSkippable(); - skipSavingThisBean = saveRecurseSkippable; - } - } - - if (!skipSavingThisBean) { - persister.saveRecurse(detail, transaction, parentBean, request.getFlags()); - } - } - } - } - - /** - * Return true if we can skip based on .. no modifications to the collection and no beans are dirty. - */ - private boolean canSkipForOrderColumn() { - return value instanceof BeanCollection - && !((BeanCollection) value).wasTouched() - && noDirtyBeans(); - } - - private boolean noDirtyBeans() { - for (Object bean : collection) { - if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isDirty()) { - return false; - } - } - return true; - } - - /** - * Collect the Id values of the details to remove 'missing children' for stateless updates. - */ - private List collectIds(Collection collection, BeanDescriptor targetDescriptor, boolean isMap) { - - List detailIds = new ArrayList<>(); - // stateless update with deleteMissingChildren so first - // collect the Id values to remove the 'missing children' - for (Object detailBean : collection) { - if (isMap) { - detailBean = ((Map.Entry) detailBean).getValue(); - } - if (detailBean instanceof EntityBean) { - Object id = targetDescriptor.getId((EntityBean) detailBean); - if (!DmlUtil.isNullOrZero(id)) { - // remember the Id (other details not in the collection) will be removed - detailIds.add(id); - } - } - } - return detailIds; - } -} diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java index 62faf73e3..49a4f09e9 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java @@ -4,16 +4,27 @@ import io.ebean.SqlUpdate; import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanCollectionUtil; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; -class SaveManySimpleCollection extends SaveManyPropRequest { +import java.util.Collection; + +/** + * Save details for a simple scalar element collection. + */ +class SaveManySimpleCollection extends SaveManyBase { SaveManySimpleCollection(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { super(insertedParent, many, parentBean, request); } @Override - void processDetails() { + void save() { + + Collection collection = BeanCollectionUtil.getActualEntries(value); + if (collection == null) { + return; + } Object parentId = request.getBeanId(); diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java new file mode 100644 index 000000000..84d57c222 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java @@ -0,0 +1,52 @@ +package io.ebeaninternal.server.persist; + +import io.ebean.SqlUpdate; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.server.core.PersistRequestBean; +import io.ebeaninternal.server.deploy.BeanCollectionUtil; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; + +import java.util.Map; +import java.util.Set; + +/** + * Save details for a simple scalar map element collection. + */ +class SaveManySimpleMap extends SaveManyBase { + + SaveManySimpleMap(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + super(insertedParent, many, parentBean, request); + } + + @SuppressWarnings("unchecked") + @Override + void save() { + + Set> entries = (Set>)BeanCollectionUtil.getActualEntries(value); + if (entries == null) { + return; + } + + Object parentId = request.getBeanId(); + + SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); + + SpiEbeanServer server = request.getServer(); + server.execute(sqlDelete, transaction); + + transaction.depth(+1); + + String insert = many.insertElementCollection(); + SqlUpdate sqlInsert = server.createSqlUpdate(insert); + + for (Map.Entry entry : entries) { + sqlInsert.setParameter(1, parentId); + sqlInsert.setParameter(2, entry.getKey()); + sqlInsert.setParameter(3, entry.getValue()); + server.execute(sqlInsert, transaction); + } + + transaction.depth(-1); + } +} diff --git a/src/test/java/org/tests/model/elementcollection/EcmPerson.java b/src/test/java/org/tests/model/elementcollection/EcmPerson.java new file mode 100644 index 000000000..8be26fa50 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcmPerson.java @@ -0,0 +1,68 @@ +package org.tests.model.elementcollection; + +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.MapKeyColumn; +import javax.persistence.Version; +import java.util.LinkedHashMap; +import java.util.Map; + +@Entity +public class EcmPerson { + + @Id + long id; + + String name; + + @ElementCollection + @MapKeyColumn(name = "type", length = 4) + @Column(name = "number", length = 10) + Map phoneNumbers = new LinkedHashMap<>(); + + @Version + long version; + + public EcmPerson(String name) { + this.name = name; + } + + @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 Map getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(Map phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java new file mode 100644 index 000000000..83bbb7561 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java @@ -0,0 +1,63 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionBasicMap extends BaseTestCase { + + @Test + public void test() { + + EcmPerson person = new EcmPerson("Fiona021"); + person.getPhoneNumbers().put("home","021 1234"); + person.getPhoneNumbers().put("work","021 4321"); + Ebean.save(person); + + + EcmPerson person1 = new EcmPerson("Fiona09"); + person1.getPhoneNumbers().put("home","09 1234"); + person1.getPhoneNumbers().put("work","09 4321"); + person1.getPhoneNumbers().put("mob","09 9876"); + Ebean.save(person1); + + List found = + Ebean.find(EcmPerson.class).where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + Map phoneNumbers0 = found.get(0).getPhoneNumbers(); + Map phoneNumbers1 = found.get(1).getPhoneNumbers(); + phoneNumbers0.size(); + + assertThat(phoneNumbers0).containsValues("021 1234", "021 4321"); + assertThat(phoneNumbers0.get("work")).isEqualTo("021 4321"); + assertThat(phoneNumbers1).containsValues("09 1234", "09 4321", "09 9876"); + assertThat(phoneNumbers1.get("mob")).isEqualTo("09 9876"); + + + List found2 = + Ebean.find(EcmPerson.class) + .fetch("phoneNumbers") + .where() + .startsWith("name", "Fiona0") + .order().asc("id") + .findList(); + + assertThat(found2).hasSize(2); + EcmPerson foundFirst = found2.get(0); + String asJson = Ebean.json().toJson(foundFirst); + + EcmPerson fromJson = Ebean.json().toBean(EcmPerson.class, asJson); + + assertThat(fromJson.getPhoneNumbers()).containsValues("021 1234", "021 4321"); + assertThat(fromJson.getPhoneNumbers().get("home")).isEqualTo("021 1234"); + + } +} From 765125608398f60eac474fe6c932f043ebe8634d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Mar 2018 15:47:20 +1300 Subject: [PATCH 0197/1036] #1352 - Bump default datasource - with better defaults for Idle connection cleanup (5 mins) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 85d2ecd68..0005b29df 100644 --- a/pom.xml +++ b/pom.xml @@ -118,7 +118,7 @@ org.avaje avaje-datasource - 3.1.1 + 3.2.2 From 6cf5e3386de9d12b9e8f0a9519f95495cfd20ed9 Mon Sep 17 00:00:00 2001 From: Yuan Xuegui Date: Mon, 26 Mar 2018 11:37:25 +0800 Subject: [PATCH 0198/1036] ENH: Add mappingsLocation config to search xml mapping files. (#1350) ENH: Add mappingsLocation config and search xml mapping files feature. --- .../java/io/ebean/config/ServerConfig.java | 65 +++++++++++++------ .../server/deploy/BeanDescriptorManager.java | 39 ++++++++++- .../java/io/ebean/EbeanServer_eqlTest.java | 15 +++++ .../org/tests/rawsql/TestRawSqlOrmQuery.java | 26 ++++++++ .../ebean-xml-mappings/CustomerMapping.xml | 14 ++++ .../ebean-xml-mappings/OrderMapping.xml | 19 ++++++ src/test/resources/ebean.properties | 2 + 7 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 src/test/resources/ebean-xml-mappings/CustomerMapping.xml create mode 100644 src/test/resources/ebean-xml-mappings/OrderMapping.xml diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 51221e96f..8d0d6f797 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -14,14 +14,7 @@ import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbType; import io.ebean.config.dbplatform.IdType; import io.ebean.config.properties.PropertiesLoader; -import io.ebean.event.BeanFindController; -import io.ebean.event.BeanPersistController; -import io.ebean.event.BeanPersistListener; -import io.ebean.event.BeanPostConstructListener; -import io.ebean.event.BeanPostLoad; -import io.ebean.event.BeanQueryAdapter; -import io.ebean.event.BulkTableEventListener; -import io.ebean.event.ServerConfigStartup; +import io.ebean.event.*; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeLogRegister; @@ -33,14 +26,7 @@ import io.ebean.util.StringHelper; import org.avaje.datasource.DataSourceConfig; import javax.sql.DataSource; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.ServiceLoader; +import java.util.*; /** * The configuration used for creating a EbeanServer. @@ -488,6 +474,12 @@ public class ServerConfig { */ private boolean defaultOrderById = false; + /** + * The mappingLocations for searching xml mapping. Only used when + * mappingLocations is empty/not explicitly specified. + */ + private List mappingLocations = new ArrayList<>(); + /** * Construct a Server Configuration for programmatically creating an EbeanServer. */ @@ -2782,7 +2774,7 @@ public class ServerConfig { if (packages != null) { String packagesProp = p.get("search.packages", p.get("packages", null)); - packages = getSearchJarsPackages(packagesProp); + packages = getSearchList(packagesProp); } collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode); @@ -2862,6 +2854,12 @@ public class ServerConfig { tenantSchemaProvider = p.createInstance(TenantSchemaProvider.class, "tenant.schemaProvider", tenantSchemaProvider); tenantPartitionColumn = p.get("tenant.partitionColumn", tenantPartitionColumn); classes = getClasses(p); + + + if (mappingLocations != null) { + String mappingsProp = p.get("search.mappingsLocations", p.get("mappingsLocations", null)); + mappingLocations = getSearchList(mappingsProp); + } } private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) { @@ -2898,10 +2896,10 @@ public class ServerConfig { return classes; } - private List getSearchJarsPackages(String searchPackages) { + private List getSearchList(String searchNames) { - if (searchPackages != null) { - String[] entries = StringHelper.splitNames(searchPackages); + if (searchNames != null) { + String[] entries = StringHelper.splitNames(searchNames); List hitList = new ArrayList<>(entries.length); Collections.addAll(hitList, entries); @@ -3076,6 +3074,33 @@ public class ServerConfig { return config; } + /** + * Add a mapping location to search for xml mapping via class path search. + */ + public void addMappingLocation(String mappingLocation) { + if (mappingLocations == null) { + mappingLocations = new ArrayList<>(); + } + mappingLocations.add(mappingLocation); + } + + /** + * Return mapping locations to search for xml mapping via class path search. + */ + public List getMappingLocations() { + return mappingLocations; + } + + /** + * Set mapping locations to search for xml mapping via class path search. + *

    + * This is only used if classes have not been explicitly specified. + *

    + */ + public void setMappingLocations(List mappingLocations) { + this.mappingLocations = mappingLocations; + } + public enum UuidVersion { VERSION4, VERSION1, diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 190322d07..62dae4b39 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -26,6 +26,7 @@ import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.TransactionEventTable; import io.ebeaninternal.server.cache.SpiCacheManager; +import io.ebeaninternal.server.core.ClassPathScanners; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.core.InternalConfiguration; import io.ebeaninternal.server.core.Message; @@ -65,6 +66,9 @@ import io.ebeaninternal.xmlmapping.model.XmNamedQuery; import io.ebeaninternal.xmlmapping.model.XmRawSql; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; import io.ebeanservice.docstore.api.DocStoreFactory; +import org.avaje.classpath.scanner.ClassPathScanner; +import org.avaje.classpath.scanner.Resource; +import org.avaje.classpath.scanner.ResourceFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,6 +76,7 @@ import javax.persistence.MappedSuperclass; import javax.persistence.PersistenceException; import javax.persistence.Transient; import javax.sql.DataSource; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; @@ -413,6 +418,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } + List xmlMappingResources = searchXmlMapping(); + for (Resource xmlMappingRes : xmlMappingResources) { + try (InputStream is = new FileInputStream(xmlMappingRes.getLocationOnDisk())) { + mappings.add(XmlMappingReader.read(is)); + } + } + for (XmEbean mapping : mappings) { List entityDeploy = mapping.getEntity(); for (XmEntity deploy : entityDeploy) { @@ -421,10 +433,35 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } } catch (IOException e) { - throw new RuntimeException("Error reading ebean.xml", e); + throw new RuntimeException("Error reading ebean xml mapping", e); } } + private List searchXmlMapping() { + List scanners = ClassPathScanners.find(serverConfig); + List mappingLocations = serverConfig.getMappingLocations(); + List resourceList = new ArrayList<>(); + + long st = System.currentTimeMillis(); + if (mappingLocations != null && !mappingLocations.isEmpty()) { + for (ClassPathScanner finder : scanners) { + for (String mappingLocation : mappingLocations) { + resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() { + + @Override + public boolean isMatch(String resourceName) { + return resourceName.endsWith(".xml"); + } + })); + } + } + } + + long searchTime = System.currentTimeMillis() - st; + logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime); + return resourceList; + } + private void readEntityMapping(ClassLoader classLoader, XmEntity entityDeploy) { String entityClassName = entityDeploy.getClazz(); diff --git a/src/test/java/io/ebean/EbeanServer_eqlTest.java b/src/test/java/io/ebean/EbeanServer_eqlTest.java index a29e00bad..75c0c1f4f 100644 --- a/src/test/java/io/ebean/EbeanServer_eqlTest.java +++ b/src/test/java/io/ebean/EbeanServer_eqlTest.java @@ -250,4 +250,19 @@ public class EbeanServer_eqlTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id "); } + + @Test + public void namedQuery_fromCustomXmlLocations() { + + ResetBasicData.reset(); + + Query query = server() + .createNamedQuery(Customer.class, "withContactsById2") + .setParameter("id", 1); + + query.setUseCache(false); + query.findOne(); + + assertThat(query.getGeneratedSql()).contains("from o_customer t0 left join contact t1 on t1.customer_id = t0.id "); + } } diff --git a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java index 51e3d53c5..cabde9917 100644 --- a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java +++ b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java @@ -51,6 +51,32 @@ public class TestRawSqlOrmQuery extends BaseTestCase { assertThat(sql).contains("where o.status = ? order by c.name, c.id"); } + @IgnorePlatform(Platform.ORACLE) + @Test + public void testNamed_fromCustomXmlLocations() { + + ResetBasicData.reset(); + + Query query = Ebean.createNamedQuery(Order.class, "myRawTest2"); + query.setParameter("orderStatus", Order.Status.NEW); + query.setMaxRows(10); + List list = query.findList(); + for (Order order : list) { + order.getCretime(); + } + + String sql = query.getGeneratedSql(); + if (isSqlServer()) { + assertThat(sql).contains("select top 10 o.id,"); + } else { + assertThat(sql).contains("select o.id,"); + assertThat(sql).contains("limit 10"); + } + assertThat(sql).contains("o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city from o_order o"); + assertThat(sql).contains("join o_customer c on o.kcustomer_id = c.id "); + assertThat(sql).contains("where o.status = ? order by c.name, c.id"); + } + @Test public void test() { diff --git a/src/test/resources/ebean-xml-mappings/CustomerMapping.xml b/src/test/resources/ebean-xml-mappings/CustomerMapping.xml new file mode 100644 index 000000000..b55626fbf --- /dev/null +++ b/src/test/resources/ebean-xml-mappings/CustomerMapping.xml @@ -0,0 +1,14 @@ + + + + + + + select (name, version) + fetch contacts (firstName, lastName, email) + where id = :id + + + + + diff --git a/src/test/resources/ebean-xml-mappings/OrderMapping.xml b/src/test/resources/ebean-xml-mappings/OrderMapping.xml new file mode 100644 index 000000000..cd35e81a9 --- /dev/null +++ b/src/test/resources/ebean-xml-mappings/OrderMapping.xml @@ -0,0 +1,19 @@ + + + + + + + + + select o.id, o.status, o.ship_date, c.id, c.name, a.id, a.line_1, a.line_2, a.city + from o_order o + join o_customer c on o.kcustomer_id = c.id + join o_address a on c.billing_address_id = a.id + where o.status = :orderStatus + order by c.name, c.id + + + + + diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 3b048c4c2..3616698d1 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -168,3 +168,5 @@ ebean.migrationtest.ddl.header=-- Migrationscripts for ebean unittest ebean.migrationtest.migration.appName=migrationtest ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest ebean.migrationtest.migration.strict=true + +ebean.mappingsLocations=classpath:/ebean-xml-mappings From 6534feb5dab2e9663b7ea512a8a508011c1ef9ca Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Mar 2018 16:55:25 +1300 Subject: [PATCH 0199/1036] #1350 - ENH: Add mappingsLocation config to search xml mapping files. Minor adjustments - read "mappingLocations" only etc. --- .../java/io/ebean/config/ServerConfig.java | 35 ++++++++++++------- .../io/ebean/config/ServerConfigTest.java | 3 ++ src/test/resources/ebean.properties | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 8d0d6f797..c0b8a5ffe 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -14,7 +14,14 @@ import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbType; import io.ebean.config.dbplatform.IdType; import io.ebean.config.properties.PropertiesLoader; -import io.ebean.event.*; +import io.ebean.event.BeanFindController; +import io.ebean.event.BeanPersistController; +import io.ebean.event.BeanPersistListener; +import io.ebean.event.BeanPostConstructListener; +import io.ebean.event.BeanPostLoad; +import io.ebean.event.BeanQueryAdapter; +import io.ebean.event.BulkTableEventListener; +import io.ebean.event.ServerConfigStartup; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeLogRegister; @@ -26,7 +33,14 @@ import io.ebean.util.StringHelper; import org.avaje.datasource.DataSourceConfig; import javax.sql.DataSource; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ServiceLoader; /** * The configuration used for creating a EbeanServer. @@ -2772,10 +2786,8 @@ public class ServerConfig { dbOffline = p.getBoolean("dbOffline", dbOffline); serverCachePlugin = p.createInstance(ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin); - if (packages != null) { - String packagesProp = p.get("search.packages", p.get("packages", null)); - packages = getSearchList(packagesProp); - } + String packagesProp = p.get("search.packages", p.get("packages", null)); + packages = getSearchList(packagesProp, packages); collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode); collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins); @@ -2855,11 +2867,8 @@ public class ServerConfig { tenantPartitionColumn = p.get("tenant.partitionColumn", tenantPartitionColumn); classes = getClasses(p); - - if (mappingLocations != null) { - String mappingsProp = p.get("search.mappingsLocations", p.get("mappingsLocations", null)); - mappingLocations = getSearchList(mappingsProp); - } + String mappingsProp = p.get("mappingLocations", null); + mappingLocations = getSearchList(mappingsProp, mappingLocations); } private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) { @@ -2896,7 +2905,7 @@ public class ServerConfig { return classes; } - private List getSearchList(String searchNames) { + private List getSearchList(String searchNames, List defaultValue) { if (searchNames != null) { String[] entries = StringHelper.splitNames(searchNames); @@ -2906,7 +2915,7 @@ public class ServerConfig { return hitList; } else { - return new ArrayList<>(); + return defaultValue; } } diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index 6aa9f64c9..03c86481d 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -64,6 +64,7 @@ public class ServerConfigTest { props.setProperty("disableL2Cache", "true"); props.setProperty("notifyL2CacheInForeground", "true"); props.setProperty("idType", "SEQUENCE"); + props.setProperty("mappingLocations", "classpath:/foo;bar"); serverConfig.loadFromProperties(props); @@ -83,6 +84,8 @@ public class ServerConfigTest { assertEquals(4, serverConfig.getBackgroundExecutorSchedulePoolSize()); assertEquals(98, serverConfig.getBackgroundExecutorShutdownSecs()); + assertThat(serverConfig.getMappingLocations()).containsExactly("classpath:/foo","bar"); + serverConfig.setPersistBatch(PersistBatch.NONE); serverConfig.setPersistBatchOnCascade(PersistBatch.NONE); diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 3616698d1..33121aa37 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -27,6 +27,7 @@ ebean.autoReadOnlyDataSource=true #ebean.h2.idType=SEQUENCE +ebean.mappingLocations=classpath:/ebean-xml-mappings ebean.currentUserProvider=io.ebean.MyCurrentUserProvider #ebean.expressionNativeIlike=true #ebean.jsonInclude=NON_NULL @@ -169,4 +170,3 @@ ebean.migrationtest.migration.appName=migrationtest ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest ebean.migrationtest.migration.strict=true -ebean.mappingsLocations=classpath:/ebean-xml-mappings From 74e0a16531862eaa5f2d88b1c38f5e73a40322c1 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Mar 2018 20:45:39 +1300 Subject: [PATCH 0200/1036] #1351 - ENH: Add named DtoQuery Merge branch 'feature/namedDtoQuery' of https://github.com/hexagonframework/ebean into hexagonframework-feature/namedDtoQuery --- src/main/java/io/ebean/EbeanServer.java | 18 ++--- .../server/core/DefaultServer.java | 21 +++--- .../server/core/InternalConfigXmlRead.java | 74 ++++++++++++++++--- .../server/core/InternalConfiguration.java | 55 +++----------- .../server/deploy/BeanDescriptorManager.java | 15 ---- .../server/dto/DtoBeanDescriptor.java | 61 ++------------- .../server/dto/DtoBeanManager.java | 68 ++++------------- .../xmlmapping/XmlMappingReader.java | 17 +++-- .../ebeaninternal/xmlmapping/model/XmDto.java | 4 +- .../xmlmapping/model/XmEbean.java | 7 +- src/main/resources/ebean-1.0.xsd | 4 +- src/test/java/io/ebean/NamedDtoQueryTest.java | 5 +- .../ebeaninternal/api/TDSpiEbeanServer.java | 5 +- src/test/resources/ebean.properties | 1 + 14 files changed, 139 insertions(+), 216 deletions(-) diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java index 78619886b..6fbc54b24 100644 --- a/src/main/java/io/ebean/EbeanServer.java +++ b/src/main/java/io/ebean/EbeanServer.java @@ -8,6 +8,12 @@ import io.ebean.plugin.Property; import io.ebean.plugin.SpiServer; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.persistence.NonUniqueResultException; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; import java.util.Collection; import java.util.List; import java.util.Map; @@ -16,11 +22,6 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Predicate; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.persistence.NonUniqueResultException; -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; /** * Provides the API for fetching and saving beans to a particular DataSource. @@ -104,7 +105,6 @@ public interface EbeanServer { * * @param shutdownDataSource if true then shutdown the underlying DataSource if it is the EbeanORM * DataSource implementation. - * DataSource implementation. * @param deregisterDriver if true then deregister the JDBC driver if it is the EbeanORM * DataSource implementation. */ @@ -444,9 +444,9 @@ public interface EbeanServer { * They do not need to be registered with Ebean before use. *

    * - * @param dtoType The type of the DTO bean the rows will be mapped into. - * @param namedQuery The name of the query - * @param The type of the DTO bean. + * @param dtoType The type of the DTO bean the rows will be mapped into. + * @param namedQuery The name of the query + * @param The type of the DTO bean. */ DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery); diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index da3d5af00..b4827d155 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -105,6 +105,13 @@ import io.ebeaninternal.server.transaction.TransactionManager; import io.ebeaninternal.util.ParamTypeHelper; import io.ebeaninternal.util.ParamTypeHelper.TypeInfo; import io.ebeanservice.docstore.api.DocStoreIntegration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.NonUniqueResultException; +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; +import javax.sql.DataSource; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -119,12 +126,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import javax.persistence.NonUniqueResultException; -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; -import javax.sql.DataSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The default server side implementation of EbeanServer. @@ -1001,11 +1002,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { @Override public DtoQuery createNamedDtoQuery(Class dtoType, String namedQuery) { DtoBeanDescriptor descriptor = dtoBeanManager.getDescriptor(dtoType); - SpiRawSql rawSql = descriptor.getNamedRawSql(namedQuery); - if (rawSql != null) { - return new DefaultDtoQuery<>(this, descriptor, rawSql.getSql().getUnparsedSql()); + String sql = descriptor.getNamedRawSql(namedQuery); + if (sql == null) { + throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName()); } - throw new PersistenceException("No named query called " + namedQuery + " for bean:" + dtoType.getName()); + return new DefaultDtoQuery<>(this, descriptor, sql); } @Override diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java b/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java index 401dbcd17..8bb1b9be7 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfigXmlRead.java @@ -1,39 +1,49 @@ package io.ebeaninternal.server.core; import io.ebean.config.ServerConfig; +import io.ebeaninternal.server.dto.DtoNamedQueries; import io.ebeaninternal.xmlmapping.XmlMappingReader; +import io.ebeaninternal.xmlmapping.model.XmDto; import io.ebeaninternal.xmlmapping.model.XmEbean; +import io.ebeaninternal.xmlmapping.model.XmRawSql; import org.avaje.classpath.scanner.ClassPathScanner; import org.avaje.classpath.scanner.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +/** + * Reads the Xml deployment information. + */ class InternalConfigXmlRead { private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlRead.class); private final ServerConfig serverConfig; + private final ClassLoader classLoader; + + private final Map, DtoNamedQueries> dtoNamedQueries = new HashMap<>(); + + private List xmlEbeanList; + InternalConfigXmlRead(ServerConfig serverConfig) { this.serverConfig = serverConfig; + this.classLoader = serverConfig.getClassLoadConfig().getClassLoader(); + + init(); } - List build() { - - ClassLoader classLoader = serverConfig.getClassLoadConfig().getClassLoader(); - List xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml"); - - List resources = searchXmlMapping(); - xmlEbeanList.addAll(XmlMappingReader.readByResourceList(resources)); - - return xmlEbeanList; + private void init() { + this.xmlEbeanList = XmlMappingReader.readByResourceName(classLoader, "ebean.xml"); + xmlEbeanList.addAll(XmlMappingReader.readByResourceList(xmlMappingResources())); } - - private List searchXmlMapping() { + private List xmlMappingResources() { List scanners = ClassPathScanners.find(serverConfig); List mappingLocations = serverConfig.getMappingLocations(); List resourceList = new ArrayList<>(); @@ -52,5 +62,47 @@ class InternalConfigXmlRead { return resourceList; } + /** + * Return the XML deployment information for entity beans. + */ + List xmlDeployment() { + return xmlEbeanList; + } + + /** + * Return the named queries for Dto beans. + */ + Map, DtoNamedQueries> readDtoMapping() { + for (XmEbean mapping : xmlEbeanList) { + List dtoList = mapping.getDto(); + for (XmDto dto : dtoList) { + readDtoMapping(dto); + } + } + + return dtoNamedQueries; + } + + private void readDtoMapping(XmDto dto) { + + String dtoClassName = dto.getClazz(); + Class dtoClass; + try { + dtoClass = Class.forName(dtoClassName, false, classLoader); + } catch (Exception e) { + log.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry"); + return; + } + + DtoNamedQueries namedQueries = dtoNamedQueries.computeIfAbsent(dtoClass, aClass -> new DtoNamedQueries()); + + for (XmRawSql sql : dto.getRawSql()) { + namedQueries.addRawSql(sql.getName(), sql.getQuery().getValue()); + } + + if (!dto.getNamedQuery().isEmpty()) { + log.error("Only raw-sql named queries supported for DTO beans - bean:" + dtoClass); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index 82d395aed..31aea3889 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -69,23 +69,19 @@ import io.ebeaninternal.server.transaction.TransactionManagerOptions; import io.ebeaninternal.server.transaction.TransactionScopeManager; import io.ebeaninternal.server.type.DefaultTypeManager; import io.ebeaninternal.server.type.TypeManager; -import io.ebeaninternal.xmlmapping.XmlMappingReader; -import io.ebeaninternal.xmlmapping.model.XmEbean; import io.ebeanservice.docstore.api.DocStoreFactory; import io.ebeanservice.docstore.api.DocStoreIntegration; import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; import io.ebeanservice.docstore.none.NoneDocStoreFactory; +import org.avaje.datasource.DataSourcePool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.avaje.classpath.scanner.ClassPathScanner; -import org.avaje.classpath.scanner.Resource; -import org.avaje.classpath.scanner.ResourceFilter; -import org.avaje.datasource.DataSourcePool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Used to extend the ServerConfig with additional objects used to configure and @@ -138,8 +134,6 @@ public class InternalConfiguration { private final MultiValueBind multiValueBind; - private List xmlEbeanList = new ArrayList<>(); - public InternalConfiguration(ClusterManager clusterManager, SpiCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor, ServerConfig serverConfig, BootupClasses bootupClasses) { @@ -159,20 +153,14 @@ public class InternalConfiguration { this.multiValueBind = createMultiValueBind(databasePlatform.getPlatform()); this.deployInherit = new DeployInherit(bootupClasses); - xmlEbeanList = XmlMappingReader.readByResourceName(serverConfig.getClassLoadConfig().getClassLoader(), - "ebean.xml"); - List searchXmlMapping = searchXmlMapping(); - xmlEbeanList.addAll(XmlMappingReader.readByResourceList(serverConfig.getClassLoadConfig().getClassLoader(), - searchXmlMapping)); - this.deployCreateProperties = new DeployCreateProperties(typeManager); this.deployUtil = new DeployUtil(typeManager, serverConfig); - this.dtoBeanManager = new DtoBeanManager(typeManager); - dtoBeanManager.readXmlMapping(serverConfig.getClassLoadConfig().getClassLoader(), - xmlEbeanList); + InternalConfigXmlRead xmlRead = new InternalConfigXmlRead(serverConfig); + + this.dtoBeanManager = new DtoBeanManager(typeManager, xmlRead.readDtoMapping()); this.beanDescriptorManager = new BeanDescriptorManager(this); - Map asOfTableMapping = beanDescriptorManager.deploy(xmlEbeanList); + Map asOfTableMapping = beanDescriptorManager.deploy(xmlRead.xmlDeployment()); Map draftTableMap = beanDescriptorManager.getDraftTableMap(); beanDescriptorManager.scheduleBackgroundTrim(); @@ -181,31 +169,6 @@ public class InternalConfiguration { this.cQueryEngine = new CQueryEngine(serverConfig, databasePlatform, binder, asOfTableMapping, draftTableMap); } - private List searchXmlMapping() { - List scanners = ClassPathScanners.find(serverConfig); - List mappingLocations = serverConfig.getMappingLocations(); - List resourceList = new ArrayList<>(); - - long st = System.currentTimeMillis(); - if (mappingLocations != null && !mappingLocations.isEmpty()) { - for (ClassPathScanner finder : scanners) { - for (String mappingLocation : mappingLocations) { - resourceList.addAll(finder.scanForResources(mappingLocation, new ResourceFilter() { - - @Override - public boolean isMatch(String resourceName) { - return resourceName.endsWith(".xml"); - } - })); - } - } - } - - long searchTime = System.currentTimeMillis() - st; - logger.debug("Classpath search mappings[{}] searchTime[{}]", resourceList.size(), searchTime); - return resourceList; - } - /** * Create and return the ExpressionFactory based on configuration and database platform. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 6be9dd585..0e6814365 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -26,7 +26,6 @@ import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.TransactionEventTable; import io.ebeaninternal.server.cache.SpiCacheManager; -import io.ebeaninternal.server.core.ClassPathScanners; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.core.InternalConfiguration; import io.ebeaninternal.server.core.Message; @@ -57,7 +56,6 @@ import io.ebeaninternal.server.query.CQueryPlan; import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.server.type.ScalarTypeInteger; import io.ebeaninternal.server.type.TypeManager; -import io.ebeaninternal.xmlmapping.XmlMappingReader; import io.ebeaninternal.xmlmapping.model.XmAliasMapping; import io.ebeaninternal.xmlmapping.model.XmColumnMapping; import io.ebeaninternal.xmlmapping.model.XmEbean; @@ -66,9 +64,6 @@ import io.ebeaninternal.xmlmapping.model.XmNamedQuery; import io.ebeaninternal.xmlmapping.model.XmRawSql; import io.ebeanservice.docstore.api.DocStoreBeanAdapter; import io.ebeanservice.docstore.api.DocStoreFactory; -import org.avaje.classpath.scanner.ClassPathScanner; -import org.avaje.classpath.scanner.Resource; -import org.avaje.classpath.scanner.ResourceFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,17 +71,12 @@ import javax.persistence.MappedSuperclass; import javax.persistence.PersistenceException; import javax.persistence.Transient; import javax.sql.DataSource; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -1064,11 +1054,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap { unidirectional.setDbRead(true); unidirectional.setDbInsertable(true); unidirectional.setDbUpdateable(false); - - targetDesc.setUnidirectional(unidirectional); - - // specify table and table alias... - BeanTable beanTable = getBeanTable(owningType); unidirectional.setBeanTable(beanTable); unidirectional.setName(beanTable.getBaseTable()); unidirectional.setJoinType(true); diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java index 0e8f4b42f..10f2a2cdc 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanDescriptor.java @@ -1,9 +1,7 @@ package io.ebeaninternal.server.dto; import io.ebean.meta.MetricVisitor; -import io.ebeaninternal.server.rawsql.SpiRawSql; -import java.util.HashMap; -import java.util.LinkedHashMap; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -12,25 +10,18 @@ import java.util.concurrent.ConcurrentHashMap; */ public class DtoBeanDescriptor { - private static final Map EMPTY_NAMED_QUERY = new HashMap<>(); - - private static final Map EMPTY_RAW_MAP = new HashMap<>(); - private final Map plans = new ConcurrentHashMap<>(); private final Class dtoType; private final DtoMeta meta; - private Map namedRawSql; + private final Map namedQueries; - private Map namedQuery; - - DtoBeanDescriptor(Class dtoType, DtoMeta meta) { + DtoBeanDescriptor(Class dtoType, DtoMeta meta, Map namedQueries) { this.dtoType = dtoType; this.meta = meta; - this.namedQuery = getNamedQuery(); - this.namedRawSql = getNamedRawSql(); + this.namedQueries = namedQueries; } public Class getType() { @@ -55,51 +46,11 @@ public class DtoBeanDescriptor { } } - /** - * Return the named ORM query. - */ - public String getNamedQuery(String name) { - return namedQuery.get(name); - } - /** * Return the named RawSql query. */ - public SpiRawSql getNamedRawSql(String named) { - return namedRawSql.get(named); + public String getNamedRawSql(String name) { + return namedQueries.get(name); } - /** - * Return the named ORM queries. - */ - public Map getNamedQuery() { - return (namedQuery != null) ? namedQuery : EMPTY_NAMED_QUERY; - } - - /** - * Add a named query. - */ - public void addNamedQuery(String name, String query) { - if (namedQuery == null) { - namedQuery = new LinkedHashMap<>(); - } - namedQuery.put(name, query); - } - - /** - * Return the named RawSql queries. - */ - public Map getNamedRawSql() { - return (namedRawSql != null) ? namedRawSql : EMPTY_RAW_MAP; - } - - /** - * Add a named RawSql from ebean.xml file. - */ - public void addRawSql(String name, SpiRawSql rawSql) { - if (namedRawSql == null) { - namedRawSql = new HashMap<>(); - } - namedRawSql.put(name, rawSql); - } } diff --git a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java index 2871b6192..4388a180d 100644 --- a/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java +++ b/src/main/java/io/ebeaninternal/server/dto/DtoBeanManager.java @@ -1,34 +1,28 @@ package io.ebeaninternal.server.dto; -import io.ebean.RawSqlBuilder; import io.ebean.meta.MetricVisitor; -import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.type.TypeManager; -import io.ebeaninternal.xmlmapping.model.XmAliasMapping; -import io.ebeaninternal.xmlmapping.model.XmColumnMapping; -import io.ebeaninternal.xmlmapping.model.XmDto; -import io.ebeaninternal.xmlmapping.model.XmEbean; -import io.ebeaninternal.xmlmapping.model.XmNamedQuery; -import io.ebeaninternal.xmlmapping.model.XmRawSql; -import java.util.List; + +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Manages all the DTO bean descriptors. */ public class DtoBeanManager { - private static final Logger logger = LoggerFactory.getLogger(DtoBeanManager.class); + private static final Map EMPTY_NAMED_QUERIES = new HashMap<>(); private final TypeManager typeManager; + private final Map, DtoNamedQueries> namedQueries; + private final Map descriptorMap = new ConcurrentHashMap<>(); - public DtoBeanManager(TypeManager typeManager) { + public DtoBeanManager(TypeManager typeManager, Map, DtoNamedQueries> namedQueries) { this.typeManager = typeManager; + this.namedQueries = namedQueries; } /** @@ -44,56 +38,20 @@ public class DtoBeanManager { try { DtoMeta meta = new DtoMetaBuilder(dtoType, typeManager).build(); - return new DtoBeanDescriptor<>(dtoType, meta); + return new DtoBeanDescriptor<>(dtoType, meta, namedQueries(dtoType)); } catch (Exception e) { throw new IllegalStateException(e); } } + private Map namedQueries(Class dtoType) { + DtoNamedQueries namedQueries = this.namedQueries.get(dtoType); + return (namedQueries == null) ? EMPTY_NAMED_QUERIES : namedQueries.map(); + } + public void visitMetrics(MetricVisitor visitor) { for (DtoBeanDescriptor value : descriptorMap.values()) { value.visit(visitor); } } - - public void readXmlMapping(ClassLoader classLoader, List mappings) { - for (XmEbean mapping : mappings) { - List dtoList = mapping.getDto(); - for (XmDto dto : dtoList) { - readDtoMapping(classLoader, dto); - } - } - } - - private void readDtoMapping(ClassLoader classLoader, XmDto dto) { - String dtoClassName = dto.getClazz(); - Class dtoClass; - try { - dtoClass = Class.forName(dtoClassName, false, classLoader); - } catch (Exception e) { - logger.error("Could not load dto bean class " + dtoClassName + " for ebean xml entry"); - return; - } - - DtoBeanDescriptor dtoBeanDescriptor = getDescriptor(dtoClass); - if (dtoBeanDescriptor == null) { - logger.error("No dto bean for ebean xml entry " + dtoClass); - - } else { - for (XmRawSql sql : dto.getRawSql()) { - RawSqlBuilder builder = RawSqlBuilder.parse(sql.getQuery().getValue()); - for (XmColumnMapping columnMapping : sql.getColumnMapping()) { - builder.columnMapping(columnMapping.getColumn(), columnMapping.getProperty()); - } - for (XmAliasMapping aliasMapping : sql.getAliasMapping()) { - builder.tableAliasMapping(aliasMapping.getAlias(), aliasMapping.getProperty()); - } - dtoBeanDescriptor.addRawSql(sql.getName(), (SpiRawSql)builder.create()); - } - - for (XmNamedQuery namedQuery : dto.getNamedQuery()) { - dtoBeanDescriptor.addNamedQuery(namedQuery.getName(), namedQuery.getQuery().getValue()); - } - } - } } diff --git a/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java b/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java index 3e267349b..79a275e60 100644 --- a/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java +++ b/src/main/java/io/ebeaninternal/xmlmapping/XmlMappingReader.java @@ -1,6 +1,11 @@ package io.ebeaninternal.xmlmapping; import io.ebeaninternal.xmlmapping.model.XmEbean; +import org.avaje.classpath.scanner.Resource; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -8,10 +13,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import org.avaje.classpath.scanner.Resource; public class XmlMappingReader { @@ -31,6 +32,9 @@ public class XmlMappingReader { } } + /** + * Read the deployment XML for the given resource name. + */ public static List readByResourceName(ClassLoader classLoader, String resourceName){ try { Enumeration resources = classLoader.getResources(resourceName); @@ -47,7 +51,10 @@ public class XmlMappingReader { } } - public static List readByResourceList(ClassLoader classLoader, List resourceList){ + /** + * Read the deployment XML for the given resources. + */ + public static List readByResourceList(List resourceList){ try { List mappings = new ArrayList<>(); for (Resource xmlMappingRes : resourceList) { diff --git a/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java b/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java index cb64fbfa6..57e431322 100644 --- a/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java +++ b/src/main/java/io/ebeaninternal/xmlmapping/model/XmDto.java @@ -1,13 +1,13 @@ package io.ebeaninternal.xmlmapping.model; -import java.util.ArrayList; -import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; /** diff --git a/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java b/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java index 4979fc865..35ba42d58 100644 --- a/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java +++ b/src/main/java/io/ebeaninternal/xmlmapping/model/XmEbean.java @@ -1,12 +1,12 @@ package io.ebeaninternal.xmlmapping.model; -import java.util.ArrayList; -import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; /** @@ -67,6 +67,9 @@ public class XmEbean { return this.entity; } + /** + * Returns the List of XmDto beans. + */ public List getDto() { if (dto == null) { dto = new ArrayList<>(); diff --git a/src/main/resources/ebean-1.0.xsd b/src/main/resources/ebean-1.0.xsd index 4a79daecb..63de5f96b 100644 --- a/src/main/resources/ebean-1.0.xsd +++ b/src/main/resources/ebean-1.0.xsd @@ -7,8 +7,8 @@ - - + + diff --git a/src/test/java/io/ebean/NamedDtoQueryTest.java b/src/test/java/io/ebean/NamedDtoQueryTest.java index ec3b810e4..510aa709f 100644 --- a/src/test/java/io/ebean/NamedDtoQueryTest.java +++ b/src/test/java/io/ebean/NamedDtoQueryTest.java @@ -2,14 +2,15 @@ package io.ebean; import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; -import java.util.List; -import java.util.Optional; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.tests.model.basic.ResetBasicData; +import java.util.List; +import java.util.Optional; + import static org.assertj.core.api.Assertions.assertThat; public class NamedDtoQueryTest extends BaseTestCase { diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index 5f538f9d5..c5c916039 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -48,6 +48,9 @@ import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.query.CQuery; import io.ebeaninternal.server.transaction.RemoteTransactionEvent; + +import javax.persistence.OptimisticLockException; +import javax.persistence.PersistenceException; import java.lang.reflect.Type; import java.util.Collection; import java.util.Collections; @@ -58,8 +61,6 @@ import java.util.Set; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Predicate; -import javax.persistence.OptimisticLockException; -import javax.persistence.PersistenceException; /** diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 3ed29771d..33121aa37 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -169,3 +169,4 @@ ebean.migrationtest.ddl.header=-- Migrationscripts for ebean unittest ebean.migrationtest.migration.appName=migrationtest ebean.migrationtest.migration.migrationPath=dbmigration/migrationtest ebean.migrationtest.migration.strict=true + From db5a2b194d6519feb7ba43f4afb725dc8967309c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 26 Mar 2018 23:31:31 +1300 Subject: [PATCH 0201/1036] No effective change - add extra test coverage on DefaultTransactionThreadLocal --- .../DefaultTransactionThreadLocalTest.java | 68 +++++++++++++++++-- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/src/test/java/io/ebeaninternal/server/transaction/DefaultTransactionThreadLocalTest.java b/src/test/java/io/ebeaninternal/server/transaction/DefaultTransactionThreadLocalTest.java index 2480e6ef8..b235b56a6 100644 --- a/src/test/java/io/ebeaninternal/server/transaction/DefaultTransactionThreadLocalTest.java +++ b/src/test/java/io/ebeaninternal/server/transaction/DefaultTransactionThreadLocalTest.java @@ -2,26 +2,80 @@ package io.ebeaninternal.server.transaction; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.Transaction; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; import io.ebeaninternal.api.SpiTransaction; import org.junit.Test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; public class DefaultTransactionThreadLocalTest extends BaseTestCase { + @ForPlatform({Platform.H2}) @Test - public void get() throws Exception { + public void get() { + Ebean.execute(() -> { + SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); + assertNotNull(txn); + }); - if (isH2()) { - Ebean.execute(() -> { - SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); - assertNotNull(txn); - }); + // thread local should be set to null + assertNull(DefaultTransactionThreadLocal.get("h2")); + } - // thread local should be set to null + @ForPlatform({Platform.H2}) + @Test + public void tryWithResources_expect_scopeCleanup() { + + try (Transaction transaction = Ebean.beginTransaction()) { + assertNotNull(transaction); + SpiTransaction txn = DefaultTransactionThreadLocal.get("h2"); + assertSame(txn, transaction); + + try (Transaction nested = Ebean.beginTransaction()) { + assertNotNull(nested); + SpiTransaction txnNested = DefaultTransactionThreadLocal.get("h2"); + assertSame(txnNested, nested); + } + + assertNotNull(DefaultTransactionThreadLocal.get("h2")); + } + + assertNull(DefaultTransactionThreadLocal.get("h2")); + } + + @ForPlatform({Platform.H2}) + @Test + public void afterCommit_expect_scopeCleanup() { + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.commit(); assertNull(DefaultTransactionThreadLocal.get("h2")); } + assertNull(DefaultTransactionThreadLocal.get("h2")); + } + + @ForPlatform({Platform.H2}) + @Test + public void afterRollback_expect_scopeCleanup() { + + try (Transaction transaction = Ebean.beginTransaction()) { + + transaction.rollback(); + assertNull(DefaultTransactionThreadLocal.get("h2")); + } + assertNull(DefaultTransactionThreadLocal.get("h2")); + } + + @ForPlatform({Platform.H2}) + @Test + public void end_withoutActiveTransaction_isFine() { + + assertNull(Ebean.currentTransaction()); + Ebean.endTransaction(); } } From abbcd35ee648833473cc3d58d8252ecab5b2cea0 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Mar 2018 09:14:45 +1300 Subject: [PATCH 0202/1036] #1353 - Use of ebeanServer.commitTransaction() in nested transaction doesn't match transction.commit() and closes parent scope --- src/main/java/io/ebean/EbeanServer.java | 52 ++++++++-------- .../server/core/DefaultServer.java | 9 ++- .../DefaultTransactionScopeManager.java | 15 ----- .../transaction/TransactionScopeManager.java | 16 ----- .../transaction/TestNestedSubTransaction.java | 62 +++++++++++++++++++ 5 files changed, 94 insertions(+), 60 deletions(-) create mode 100644 src/test/java/org/tests/transaction/TestNestedSubTransaction.java diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java index 6fbc54b24..1b9157c1f 100644 --- a/src/main/java/io/ebean/EbeanServer.java +++ b/src/main/java/io/ebean/EbeanServer.java @@ -521,30 +521,44 @@ public interface EbeanServer { * etc. *

    *

    + *

    Using try with resources

    *
    {@code
        *
        *    // start a transaction (stored in a ThreadLocal)
    -   *    ebeanServer.beginTransaction();
    +   *
    +   *    try (Transaction txn = ebeanServer.beginTransaction()) {
    +   *
    +   * 	    Order order = ebeanServer.find(Order.class,10);
    +   * 	    ...
    +   * 	    ebeanServer.save(order);
    +   *
    +   * 	    txn.commit();
    +   *    }
    +   *
    +   * }
    + *

    + *

    Using try finally block

    + *
    {@code
    +   *
    +   *    // start a transaction (stored in a ThreadLocal)
    +   *    Transaction txn = ebeanServer.beginTransaction();
        *    try {
        * 	    Order order = ebeanServer.find(Order.class,10);
        *
        * 	    ebeanServer.save(order);
        *
    -   * 	    ebeanServer.commitTransaction();
    +   * 	    txn.commit();
        *
        *    } finally {
    -   * 	    // rollback if we didn't commit
    -   * 	    // i.e. an exception occurred before commitTransaction().
    -   * 	    ebeanServer.endTransaction();
    +   * 	    txn.end();
        *    }
        *
        * }
    *

    - *

    Transaction options:

    + *

    Transaction options

    *
    {@code
        *
    -   *     Transaction txn = ebeanServer.beginTransaction();
    -   *     try {
    +   *     try (Transaction txn = ebeanServer.beginTransaction()) {
        *       // explicitly turn on/off JDBC batch use
        *       txn.setBatchMode(true);
        *       txn.setBatchSize(50);
    @@ -565,10 +579,6 @@ public interface EbeanServer {
        *       ...
        *
        *       txn.commit();
    -   *
    -   *    } finally {
    -   *       // rollback if necessary
    -   *       txn.end();
        *    }
        *
        * }
    @@ -598,19 +608,16 @@ public interface EbeanServer { *
    {@code
        * // Start a new transaction. If there is a current transaction
        * // suspend it until this transaction ends
    -   * Transaction txn = server.beginTransaction(TxScope.requiresNew());
    -   * try {
    +   * try (Transaction txn = server.beginTransaction(TxScope.requiresNew())) {
        *
        *   ...
        *
        *   // commit the transaction
        *   txn.commit();
        *
    -   * } finally {
    -   *   // end this transaction which:
    -   *   //  A) will rollback transaction if it has not been committed already
    +   *   // At end this transaction will:
    +   *   //  A) will rollback transaction if it has not been committed
        *   //  B) will restore a previously suspended transaction
    -   *   txn.end();
        * }
        *
        * }
    @@ -619,20 +626,13 @@ public interface EbeanServer { *
    {@code
        *
        * // start a new transaction if there is not a current transaction
    -   * Transaction txn = server.beginTransaction(TxScope.required());
    -   * try {
    +   * try (Transaction txn = server.beginTransaction(TxScope.required())) {
        *
        *   ...
        *
        *   // commit the transaction if it was created or
        *   // do nothing if there was already a current transaction
        *   txn.commit();
    -   *
    -   * } finally {
    -   *   // end this transaction which will rollback the transaction
    -   *   // if it was created for this try finally scope and has not
    -   *   // already been committed
    -   *   txn.end();
        * }
        *
        * }
    diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index b4827d155..c131f6722 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -802,7 +802,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void commitTransaction() { - transactionManager.scope().commit(); + currentTransaction().commit(); } /** @@ -810,7 +810,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void rollbackTransaction() { - transactionManager.scope().rollback(); + currentTransaction().rollback(); } /** @@ -843,7 +843,10 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void endTransaction() { - transactionManager.scope().end(); + Transaction transaction = currentTransaction(); + if (transaction != null) { + transaction.end(); + } } /** diff --git a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java index 0f376b3cb..bf949c231 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/DefaultTransactionScopeManager.java @@ -17,16 +17,6 @@ public class DefaultTransactionScopeManager extends TransactionScopeManager { // do nothing } - @Override - public void commit() { - DefaultTransactionThreadLocal.commit(serverName); - } - - @Override - public void end() { - DefaultTransactionThreadLocal.end(serverName); - } - @Override public SpiTransaction getInScope() { return DefaultTransactionThreadLocal.get(serverName); @@ -47,11 +37,6 @@ public class DefaultTransactionScopeManager extends TransactionScopeManager { DefaultTransactionThreadLocal.replace(serverName, trans); } - @Override - public void rollback() { - DefaultTransactionThreadLocal.rollback(serverName); - } - @Override public void set(SpiTransaction trans) { DefaultTransactionThreadLocal.set(serverName, trans); diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java index 541b07b1d..61f2b8050 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionScopeManager.java @@ -34,22 +34,6 @@ public abstract class TransactionScopeManager implements SpiTransactionScopeMana */ public abstract void set(SpiTransaction trans); - /** - * Commit the current transaction. - */ - public abstract void commit(); - - /** - * Rollback the current transaction. - */ - public abstract void rollback(); - - - /** - * Rollback if required. - */ - public abstract void end(); - /** * Replace the current transaction with this one. *

    diff --git a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java new file mode 100644 index 000000000..f7e9e62e2 --- /dev/null +++ b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java @@ -0,0 +1,62 @@ +package org.tests.transaction; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.EbeanServer; +import io.ebean.PersistenceContextScope; +import io.ebean.Transaction; +import org.junit.Test; +import org.tests.model.basic.EBasic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; + +public class TestNestedSubTransaction extends BaseTestCase { + + @Test + public void ebeanServer_commitTransaction_expect_sameAsTransactionCommit() { + + EbeanServer server = server(); + + EBasic bean = new EBasic("x1"); + + try (Transaction txn0 = server.beginTransaction()) { + txn0.setRollbackOnly(); + + server.save(bean); + + try (Transaction txn1 = server.beginTransaction()) { + bean.setName("x2"); + server.save(bean); + //txn1.commit(); + server.commitTransaction(); + } + + EBasic fresh = server.find(EBasic.class, bean.getId()); + assertNotNull(fresh); // FAILS + assertThat(fresh.getName()).isEqualTo("x2"); + + try (Transaction txn2 = server.beginTransaction()) { + bean.setName("barney"); + Ebean.save(bean); + //txn2.commit(); + server.commitTransaction(); + } + + fresh = server.find(EBasic.class) + .setId(bean.getId()) + .setPersistenceContextScope(PersistenceContextScope.QUERY) + .findOne(); + + assertNotNull(fresh); + assertThat(fresh.getName()).isEqualTo("barney"); + + } finally { + cleanup(bean); + } + } + + private void cleanup(EBasic bean) { + Ebean.delete(EBasic.class, bean.getId()); + } +} From eb96c726fd0260c0688f8e4e18f8084d0fb320ef Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Mar 2018 10:47:24 +1300 Subject: [PATCH 0203/1036] No effective change - Modify some tests to use transaction try with resources --- .../java/io/ebean/TransactionalTestCase.java | 2 +- .../core/DefaultServer_getReferenceTest.java | 26 ++--- .../tests/basic/TestLogTransLogOnError.java | 20 ++-- .../tests/basic/TestMultipleOneToOneIUD.java | 14 +-- .../org/tests/basic/TestQueryForUpdate.java | 98 ++++++++----------- .../tests/cache/TestCacheCollectionIds.java | 10 +- .../org/tests/iud/TestInsertUpdateTrans.java | 12 +-- .../xtra/TestDeleteUnloadedChildren.java | 15 +-- 8 files changed, 78 insertions(+), 119 deletions(-) diff --git a/src/test/java/io/ebean/TransactionalTestCase.java b/src/test/java/io/ebean/TransactionalTestCase.java index 64093c213..3fcbb34bc 100644 --- a/src/test/java/io/ebean/TransactionalTestCase.java +++ b/src/test/java/io/ebean/TransactionalTestCase.java @@ -5,7 +5,7 @@ import org.junit.Before; import org.tests.model.basic.ResetBasicData; /** - * Transactional test case. Every test is coverered by a transaction, which is roll backed. + * Transactional test case. Every test is covered by a transaction, which is roll backed. * So no changes will persist to database. * * Use this test case if you modify data in your test case, so that the test does not interfere diff --git a/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java b/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java index 4ee4d6012..78cea8327 100644 --- a/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java +++ b/src/test/java/io/ebeaninternal/server/core/DefaultServer_getReferenceTest.java @@ -3,11 +3,11 @@ package io.ebeaninternal.server.core; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.junit.Test; import org.tests.model.basic.Car; import org.tests.model.basic.Customer; import org.tests.model.basic.ResetBasicData; import org.tests.model.basic.Vehicle; -import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -23,15 +23,11 @@ public class DefaultServer_getReferenceTest extends BaseTestCase { ResetBasicData.reset(); - Ebean.beginTransaction(); - try { + Ebean.execute(() -> { Customer loaded = Ebean.find(Customer.class, 1); Customer reference = Ebean.getReference(Customer.class, 1); assertThat(loaded).isSameAs(reference); - - } finally { - Ebean.endTransaction(); - } + }); } @@ -58,16 +54,12 @@ public class DefaultServer_getReferenceTest extends BaseTestCase { car.setDriver("TestForRef"); Ebean.save(car); - Ebean.beginTransaction(); - try { - Vehicle loaded = Ebean.find(Vehicle.class, car.getId()); - Vehicle reference = Ebean.getReference(Vehicle.class, car.getId()); - assertThat(reference).isSameAs(loaded); - - } finally { - Ebean.endTransaction(); - } - + Ebean.execute(() -> { + Vehicle loaded = Ebean.find(Vehicle.class, car.getId()); + Vehicle reference = Ebean.getReference(Vehicle.class, car.getId()); + assertThat(reference).isSameAs(loaded); + } + ); Ebean.delete(car); } } diff --git a/src/test/java/org/tests/basic/TestLogTransLogOnError.java b/src/test/java/org/tests/basic/TestLogTransLogOnError.java index 785d51e68..2c9b4b8cd 100644 --- a/src/test/java/org/tests/basic/TestLogTransLogOnError.java +++ b/src/test/java/org/tests/basic/TestLogTransLogOnError.java @@ -2,12 +2,13 @@ package org.tests.basic; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.Transaction; +import org.junit.Assert; +import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.EBasicVer; import org.tests.model.basic.Order; import org.tests.model.basic.ResetBasicData; -import org.junit.Assert; -import org.junit.Test; import java.util.List; @@ -18,8 +19,7 @@ public class TestLogTransLogOnError extends BaseTestCase { ResetBasicData.reset(); - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { Ebean.find(Customer.class).findList(); Ebean.find(Order.class).where().gt("id", 1).findList(); @@ -35,13 +35,11 @@ public class TestLogTransLogOnError extends BaseTestCase { Assert.assertEquals(0, list.size()); // Get here with mysql? // Assert.assertTrue(false); + txn.commit(); } catch (RuntimeException e) { // e.printStackTrace(); Assert.assertTrue(true); - - } finally { - Ebean.endTransaction(); } } @@ -49,8 +47,7 @@ public class TestLogTransLogOnError extends BaseTestCase { ResetBasicData.reset(); - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { Ebean.find(Customer.class).findList(); EBasicVer newBean = new EBasicVer("aName"); @@ -65,14 +62,11 @@ public class TestLogTransLogOnError extends BaseTestCase { // never get here Assert.assertTrue(false); + txn.commit(); } catch (RuntimeException e) { // e.printStackTrace(); Assert.assertTrue(true); - - } finally { - Ebean.endTransaction(); } - } } diff --git a/src/test/java/org/tests/basic/TestMultipleOneToOneIUD.java b/src/test/java/org/tests/basic/TestMultipleOneToOneIUD.java index 64e913279..57a0a8fc2 100644 --- a/src/test/java/org/tests/basic/TestMultipleOneToOneIUD.java +++ b/src/test/java/org/tests/basic/TestMultipleOneToOneIUD.java @@ -2,11 +2,12 @@ package org.tests.basic; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.Transaction; +import org.junit.Assert; +import org.junit.Test; import org.tests.model.basic.OCar; import org.tests.model.basic.OEngine; import org.tests.model.basic.OGearBox; -import org.junit.Assert; -import org.junit.Test; public class TestMultipleOneToOneIUD extends BaseTestCase { @@ -25,19 +26,14 @@ public class TestMultipleOneToOneIUD extends BaseTestCase { car.setName("test car"); car.setEngine(engine); - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { Ebean.save(gearBox); Ebean.save(car); Assert.assertNotNull(car.getId()); Assert.assertNotNull(engine.getEngineId()); Assert.assertNotNull(gearBox.getId()); - - Ebean.commitTransaction(); - - } finally { - Ebean.endTransaction(); + txn.commit(); } OCar c2 = Ebean.find(OCar.class, car.getId()); diff --git a/src/test/java/org/tests/basic/TestQueryForUpdate.java b/src/test/java/org/tests/basic/TestQueryForUpdate.java index c78aaebaa..c72884b89 100644 --- a/src/test/java/org/tests/basic/TestQueryForUpdate.java +++ b/src/test/java/org/tests/basic/TestQueryForUpdate.java @@ -29,10 +29,10 @@ public class TestQueryForUpdate extends BaseTestCase { ResetBasicData.reset(); Query query = Ebean.find(Customer.class) - .forUpdate() - .order().desc("id"); + .forUpdate() + .order().desc("id"); - query.findList(); + query.findList(); if (isSqlServer()) { assertThat(sqlOf(query)).contains("with (updlock)"); } else { @@ -48,25 +48,19 @@ public class TestQueryForUpdate extends BaseTestCase { ResetBasicData.reset(); - Ebean.beginTransaction(); - try { - Query query = Ebean.find(Customer.class) - .forUpdateNoWait() - .order().desc("id"); + Query query = Ebean.find(Customer.class) + .forUpdateNoWait() + .order().desc("id"); - query.findList(); - if (isOracle()) { - assertThat(sqlOf(query)).contains("for update nowait"); - } else if (isH2()) { - assertThat(sqlOf(query)).contains("for update"); - } else if (isSqlServer()) { - assertThat(sqlOf(query)).contains("with (updlock,nowait)"); - } else { - assertThat(sqlOf(query)).contains("for update nowait"); - } - - } finally { - Ebean.endTransaction(); + query.findList(); + if (isOracle()) { + assertThat(sqlOf(query)).contains("for update nowait"); + } else if (isH2()) { + assertThat(sqlOf(query)).contains("for update"); + } else if (isSqlServer()) { + assertThat(sqlOf(query)).contains("with (updlock,nowait)"); + } else { + assertThat(sqlOf(query)).contains("for update nowait"); } } @@ -80,42 +74,36 @@ public class TestQueryForUpdate extends BaseTestCase { EbeanServer server = Ebean.getDefaultServer(); - Ebean.beginTransaction(); - try { - Query query = Ebean.find(Customer.class) - .forUpdateNoWait() - .setMaxRows(1) - .order().desc("id"); + try (Transaction txn = Ebean.beginTransaction()) { + Query query = Ebean.find(Customer.class) + .forUpdateNoWait() + .setMaxRows(1) + .order().desc("id"); - List list = query.findList(); - Customer first = list.get(0); - if (isSqlServer()) { - assertThat(sqlOf(query)).contains("with (updlock,nowait)"); - } else if (isH2()){ - assertThat(sqlOf(query)).contains("for update"); - } else { - assertThat(sqlOf(query)).contains("for update nowait"); - } - // create a 2nd transaction to test that the - // row is locked and we can't acquire it - Transaction txn2 = server.createTransaction(); - try { - logger.info("... attempt another acquire using 2nd transaction"); - Query query2 = - server.find(Customer.class) - .where().idEq(first.getId()) - .forUpdateNoWait(); + List list = query.findList(); + Customer first = list.get(0); + if (isSqlServer()) { + assertThat(sqlOf(query)).contains("with (updlock,nowait)"); + } else if (isH2()) { + assertThat(sqlOf(query)).contains("for update"); + } else { + assertThat(sqlOf(query)).contains("for update nowait"); + } + // create a 2nd transaction to test that the + // row is locked and we can't acquire it + try (Transaction txn2 = server.createTransaction()) { + logger.info("... attempt another acquire using 2nd transaction"); + Query query2 = + server.find(Customer.class) + .where().idEq(first.getId()) + .forUpdateNoWait(); - server.findOne(query2, txn2); - assertTrue(false); // never get here - } catch (AcquireLockException e) { - logger.info("... got AcquireLockException " + e); - } finally { - txn2.end(); - } - - } finally { - Ebean.endTransaction(); + server.findOne(query2, txn2); + assertTrue(false); // never get here + } catch (AcquireLockException e) { + logger.info("... got AcquireLockException " + e); + } + txn.commit(); } } } diff --git a/src/test/java/org/tests/cache/TestCacheCollectionIds.java b/src/test/java/org/tests/cache/TestCacheCollectionIds.java index b3e231195..515fb901f 100644 --- a/src/test/java/org/tests/cache/TestCacheCollectionIds.java +++ b/src/test/java/org/tests/cache/TestCacheCollectionIds.java @@ -4,6 +4,7 @@ import io.ebean.BaseTestCase; import io.ebean.CacheMode; import io.ebean.Ebean; import io.ebean.SqlUpdate; +import io.ebean.Transaction; import io.ebean.Update; import io.ebean.cache.ServerCache; import io.ebean.cache.ServerCacheManager; @@ -253,8 +254,7 @@ public class TestCacheCollectionIds extends BaseTestCase { ResetBasicData.reset(); - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { OCachedBean cachedBean = new OCachedBean(); cachedBean.setName("helloForUpdate"); @@ -272,9 +272,7 @@ public class TestCacheCollectionIds extends BaseTestCase { cachedBean.setName("mod2"); Ebean.save(cachedBean); - Ebean.commitTransaction(); - } finally { - Ebean.endTransaction(); + txn.commit(); } @@ -340,7 +338,7 @@ public class TestCacheCollectionIds extends BaseTestCase { Assert.assertEquals(1, rows); // We need to notify the cache manually - Ebean.externalModification("o_order_detail",false, false, true); + Ebean.externalModification("o_order_detail", false, false, true); // read the order from cache Order orderFromCache = Ebean.find(Order.class, 1L); diff --git a/src/test/java/org/tests/iud/TestInsertUpdateTrans.java b/src/test/java/org/tests/iud/TestInsertUpdateTrans.java index 01f79b933..32dc30f16 100644 --- a/src/test/java/org/tests/iud/TestInsertUpdateTrans.java +++ b/src/test/java/org/tests/iud/TestInsertUpdateTrans.java @@ -2,17 +2,17 @@ package org.tests.iud; import io.ebean.BaseTestCase; import io.ebean.Ebean; -import org.tests.model.basic.EBasicVer; +import io.ebean.Transaction; import org.junit.Assert; import org.junit.Test; +import org.tests.model.basic.EBasicVer; public class TestInsertUpdateTrans extends BaseTestCase { @Test public void test() { - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { EBasicVer e0 = new EBasicVer("onInsert"); e0.setDescription("something"); @@ -34,11 +34,7 @@ public class TestInsertUpdateTrans extends BaseTestCase { Assert.assertEquals("onUpdate", e1.getName()); Assert.assertEquals("differentFromInsert", e1.getDescription()); - - Ebean.commitTransaction(); - - } finally { - Ebean.endTransaction(); + txn.commit(); } } } diff --git a/src/test/java/org/tests/model/basic/xtra/TestDeleteUnloadedChildren.java b/src/test/java/org/tests/model/basic/xtra/TestDeleteUnloadedChildren.java index edc220a13..2291bd0b7 100644 --- a/src/test/java/org/tests/model/basic/xtra/TestDeleteUnloadedChildren.java +++ b/src/test/java/org/tests/model/basic/xtra/TestDeleteUnloadedChildren.java @@ -3,6 +3,7 @@ package org.tests.model.basic.xtra; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.SqlUpdate; +import io.ebean.Transaction; import org.junit.Test; import java.util.ArrayList; @@ -11,8 +12,7 @@ public class TestDeleteUnloadedChildren extends BaseTestCase { private void init() { - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { String sql; SqlUpdate delete; @@ -48,9 +48,7 @@ public class TestDeleteUnloadedChildren extends BaseTestCase { Ebean.save(extendedParent); - Ebean.commitTransaction(); - } finally { - Ebean.endTransaction(); + txn.commit(); } } @@ -59,15 +57,12 @@ public class TestDeleteUnloadedChildren extends BaseTestCase { init(); - Ebean.beginTransaction(); - try { + try (Transaction txn = Ebean.beginTransaction()) { EdParent parent = Ebean.find(EdParent.class).where().eq("name", "MyComputer").findOne(); // // Works only if the following statement is included // int x = parent.getChildren().size(); Ebean.delete(parent); - Ebean.commitTransaction(); - } finally { - Ebean.endTransaction(); + txn.commit(); } } From 4ef581f87c585d5d5e484f2af597cfed9e9351df Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Mar 2018 17:16:35 +1300 Subject: [PATCH 0204/1036] No effective change - Update agent in pom to 11.11.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0005b29df..abf1a3e82 100644 --- a/pom.xml +++ b/pom.xml @@ -224,7 +224,7 @@ io.ebean ebean-agent - 11.10.1 + 11.11.1 test @@ -297,7 +297,7 @@ io.ebean ebean-maven-plugin - 11.10.1 + 11.11.1 test From dfa7b765f972cb1b33849edd99bcff9cd72e039d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 27 Mar 2018 22:58:19 +1300 Subject: [PATCH 0205/1036] #1354 - ENH: Add SqlUpdate setNextParameter() ... as alternative for positioned parameters --- src/main/java/io/ebean/SqlUpdate.java | 38 ++++++++++++++++++- .../server/core/DefaultSqlUpdate.java | 4 +- .../TestPersistenceContextQueryScope.java | 6 +-- .../tests/rawsql/TestInsertSqlLogging.java | 32 ++++++++++++---- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java index 59865f815..87364334d 100644 --- a/src/main/java/io/ebean/SqlUpdate.java +++ b/src/main/java/io/ebean/SqlUpdate.java @@ -30,6 +30,35 @@ package io.ebean; * String msg = "There were " + modifiedCount + " rows updated"; * * } + *

    + *

    Example: Using setNextParameter()

    + *
    {@code
    + *
    + *  String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
    + *  SqlUpdate insert = Ebean.createSqlUpdate(sql);
    + *
    + *  try (Transaction txn = Ebean.beginTransaction()) {
    + *    txn.setBatchMode(true);
    + *
    + *    insert.setNextParameter(10000);
    + *    insert.setNextParameter("hello");
    + *    insert.setNextParameter("rob");
    + *    insert.execute();
    + *
    + *    insert.setNextParameter(10001);
    + *    insert.setNextParameter("goodbye");
    + *    insert.setNextParameter("rob");
    + *    insert.execute();
    + *
    + *    insert.setNextParameter(10002);
    + *    insert.setNextParameter("chow");
    + *    insert.setNextParameter("bob");
    + *    insert.execute();
    + *
    + *    txn.commit();
    + *  }
    + *
    + * }
    * * @see Update * @see SqlQuery @@ -61,7 +90,7 @@ public interface SqlUpdate { /** * Execute and return the generated key. This is effectively a short cut for: - * + *

    *

    {@code
        *
        *   sqlUpdate.execute();
    @@ -137,6 +166,13 @@ public interface SqlUpdate {
        */
       SqlUpdate setTimeout(int secs);
     
    +  /**
    +   * Set the next positioned parameter.
    +   *
    +   * @param value The value to bind
    +   */
    +  SqlUpdate setNextParameter(Object value);
    +
       /**
        * Set a parameter via its index position.
        */
    diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    index c65b6c269..28869a8c3 100644
    --- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    +++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    @@ -105,6 +105,7 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
     
       @Override
       public int execute() {
    +    addPos = 0;
         if (server != null) {
           return server.execute(this);
         } else {
    @@ -182,8 +183,9 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
         return this;
       }
     
    -  public void addParameter(Object value) {
    +  public SqlUpdate setNextParameter(Object value) {
         setParameter(++addPos, value);
    +    return this;
       }
     
       @Override
    diff --git a/src/test/java/org/tests/persistencecontext/TestPersistenceContextQueryScope.java b/src/test/java/org/tests/persistencecontext/TestPersistenceContextQueryScope.java
    index 367ec77ac..2221a7424 100644
    --- a/src/test/java/org/tests/persistencecontext/TestPersistenceContextQueryScope.java
    +++ b/src/test/java/org/tests/persistencecontext/TestPersistenceContextQueryScope.java
    @@ -3,8 +3,8 @@ package org.tests.persistencecontext;
     import io.ebean.BaseTestCase;
     import io.ebean.Ebean;
     import io.ebean.SqlUpdate;
    -import org.tests.model.basic.EBasicVer;
     import org.junit.Test;
    +import org.tests.model.basic.EBasicVer;
     
     import static io.ebean.PersistenceContextScope.QUERY;
     import static io.ebean.PersistenceContextScope.TRANSACTION;
    @@ -28,8 +28,8 @@ public class TestPersistenceContextQueryScope extends BaseTestCase {
     
           // do an update of the name in the DB
           SqlUpdate sqlUpdate = Ebean.createSqlUpdate("update e_basicver set name=? where id=?");
    -      sqlUpdate.setParameter(1, "second");
    -      sqlUpdate.setParameter(2, bean.getId());
    +      sqlUpdate.setNextParameter("second");
    +      sqlUpdate.setNextParameter(bean.getId());
           int rowCount = sqlUpdate.execute();
           assertEquals(1, rowCount);
     
    diff --git a/src/test/java/org/tests/rawsql/TestInsertSqlLogging.java b/src/test/java/org/tests/rawsql/TestInsertSqlLogging.java
    index 0d0c1824b..44e7ceef3 100644
    --- a/src/test/java/org/tests/rawsql/TestInsertSqlLogging.java
    +++ b/src/test/java/org/tests/rawsql/TestInsertSqlLogging.java
    @@ -5,8 +5,8 @@ import io.ebean.Ebean;
     import io.ebean.SqlUpdate;
     import io.ebean.Transaction;
     import io.ebeaninternal.api.SpiTransaction;
    -import org.tests.idkeys.db.AuditLog;
     import org.junit.Test;
    +import org.tests.idkeys.db.AuditLog;
     
     import static org.junit.Assert.assertFalse;
     
    @@ -15,15 +15,33 @@ public class TestInsertSqlLogging extends BaseTestCase {
       @Test
       public void test() {
     
    -    Ebean.delete(AuditLog.class, 10000);
    +    Ebean.find(AuditLog.class).where().ge("id", 10000).delete();
     
         String sql = "insert into audit_log (id, description, modified_description) values (?,?,?)";
    -    SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql);
    -    sqlUpdate.setParameter(1, 10000);
    -    sqlUpdate.setParameter(2, "hello");
    -    sqlUpdate.setParameter(3, "rob");
    +    SqlUpdate insert = Ebean.createSqlUpdate(sql);
    +
    +    try (Transaction txn = Ebean.beginTransaction()) {
    +      txn.setBatchMode(true);
    +      txn.setBatchSize(2);
    +
    +      insert.setNextParameter(10000);
    +      insert.setNextParameter("hello");
    +      insert.setNextParameter("rob");
    +      insert.execute();
    +
    +      insert.setNextParameter(10001);
    +      insert.setNextParameter("goodbye");
    +      insert.setNextParameter("rob");
    +      insert.execute();
    +
    +      insert.setNextParameter(10002);
    +      insert.setNextParameter("chow");
    +      insert.setNextParameter("bob");
    +      insert.execute();
    +
    +      txn.commit();
    +    }
     
    -    sqlUpdate.execute();
       }
     
       @Test
    
    From 534eb2f0e2f224b22f96f054037184eb5a1528fe Mon Sep 17 00:00:00 2001
    From: Rob Bygrave 
    Date: Tue, 27 Mar 2018 23:24:30 +1300
    Subject: [PATCH 0206/1036] #1354 - ENH: Add SqlUpdate setNextParameter() ...
     as alternative for positioned parameters
    
    ---
     src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java       | 5 +++++
     .../io/ebeaninternal/server/core/DefaultSqlUpdate.java     | 6 +++++-
     .../ebeaninternal/server/core/PersistRequestUpdateSql.java | 7 ++++---
     3 files changed, 14 insertions(+), 4 deletions(-)
    
    diff --git a/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java b/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java
    index 10c7ccad7..a7c8c6e7f 100644
    --- a/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java
    +++ b/src/main/java/io/ebeaninternal/api/SpiSqlUpdate.java
    @@ -23,4 +23,9 @@ public interface SpiSqlUpdate extends SqlUpdate {
        * Set the generated key value.
        */
       void setGeneratedKey(Object idValue);
    +
    +  /**
    +   * Reset bind position to be ready for another bind execute.
    +   */
    +  void reset();
     }
    diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    index 28869a8c3..92e40b48b 100644
    --- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    +++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java
    @@ -97,6 +97,11 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
         this(null, sql, new BindParams());
       }
     
    +  @Override
    +  public void reset() {
    +    addPos = 0;
    +  }
    +
       @Override
       public Object executeGetKey() {
         execute();
    @@ -105,7 +110,6 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
     
       @Override
       public int execute() {
    -    addPos = 0;
         if (server != null) {
           return server.execute(this);
         } else {
    diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
    index 5261de3f9..202eb5141 100644
    --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
    +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java
    @@ -30,12 +30,13 @@ public final class PersistRequestUpdateSql extends PersistRequest {
       /**
        * Create.
        */
    -  public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate updateSql,
    +  public PersistRequestUpdateSql(SpiEbeanServer server, SqlUpdate sqlUpdate,
                                      SpiTransaction t, PersistExecute persistExecute) {
     
    -    super(server, t, persistExecute, updateSql.getLabel());
    +    super(server, t, persistExecute, sqlUpdate.getLabel());
         this.type = Type.UPDATESQL;
    -    this.updateSql = (SpiSqlUpdate) updateSql;
    +    this.updateSql = (SpiSqlUpdate) sqlUpdate;
    +    updateSql.reset();
       }
     
       @Override
    
    From cca837bcfa43a666c1f03e9d95d4aeb7b6d17121 Mon Sep 17 00:00:00 2001
    From: Rob Bygrave 
    Date: Wed, 28 Mar 2018 00:45:12 +1300
    Subject: [PATCH 0207/1036] #1354 - ENH: Add SqlUpdate setNextParameter() ...
     as alternative for positioned parameters
    
    ---
     .../io/ebeaninternal/server/deploy/BeanDescriptor.java    | 2 +-
     .../io/ebeaninternal/server/deploy/BeanPropertyAssoc.java | 8 ++++----
     .../ebeaninternal/server/deploy/id/IdBinderEmbedded.java  | 2 +-
     .../io/ebeaninternal/server/deploy/id/IdBinderSimple.java | 4 ++--
     4 files changed, 8 insertions(+), 8 deletions(-)
    
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    index 8a9d0fa4b..5bbd28ee8 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    @@ -1015,7 +1015,7 @@ public class BeanDescriptor implements BeanType, STreeType {
     
         Object[] bindValues = idBinder.getBindValues(id);
         for (Object bindValue : bindValues) {
    -      sqlDelete.addParameter(bindValue);
    +      sqlDelete.setNextParameter(bindValue);
         }
     
         return sqlDelete;
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
    index cbe81bcbb..7fa20d8d6 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssoc.java
    @@ -482,12 +482,12 @@ public abstract class BeanPropertyAssoc extends BeanProperty implements STree
       void bindParentIds(DefaultSqlUpdate delete, List parentIds) {
     
         if (isExportedSimple()) {
    -      delete.addParameter(new MultiValueWrapper(parentIds));
    +      delete.setNextParameter(new MultiValueWrapper(parentIds));
         } else {
           // embedded ids etc
           List bindValues = flattenParentIds(parentIds);
           for (Object bindValue : bindValues) {
    -        delete.addParameter(bindValue);
    +        delete.setNextParameter(bindValue);
           }
         }
       }
    @@ -495,12 +495,12 @@ public abstract class BeanPropertyAssoc extends BeanProperty implements STree
       void bindParentId(DefaultSqlUpdate sqlUpd, Object parentId) {
     
         if (isExportedSimple()) {
    -      sqlUpd.addParameter(parentId);
    +      sqlUpd.setNextParameter(parentId);
           return;
         }
         EntityBean parent = (EntityBean) parentId;
         for (ExportedProperty exportedProperty : exportedProperties) {
    -      sqlUpd.addParameter(exportedProperty.getValue(parent));
    +      sqlUpd.setNextParameter(exportedProperty.getValue(parent));
         }
       }
     
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java
    index 5013b2d9e..c78e9ba25 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderEmbedded.java
    @@ -277,7 +277,7 @@ public final class IdBinderEmbedded implements IdBinder {
       public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
         for (BeanProperty prop : props) {
           Object embFieldValue = prop.getValue((EntityBean) value);
    -      sqlUpdate.addParameter(embFieldValue);
    +      sqlUpdate.setNextParameter(embFieldValue);
         }
       }
     
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderSimple.java b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderSimple.java
    index a4da8e3f2..f424f4662 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderSimple.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/id/IdBinderSimple.java
    @@ -146,7 +146,7 @@ public final class IdBinderSimple implements IdBinder {
     
       @Override
       public void addIdInBindValues(DefaultSqlUpdate sqlUpdate, Collection ids) {
    -    sqlUpdate.addParameter(new MultiValueWrapper(ids));
    +    sqlUpdate.setNextParameter(new MultiValueWrapper(ids));
       }
     
       @Override
    @@ -171,7 +171,7 @@ public final class IdBinderSimple implements IdBinder {
     
       @Override
       public void bindId(DefaultSqlUpdate sqlUpdate, Object value) {
    -    sqlUpdate.addParameter(value);
    +    sqlUpdate.setNextParameter(value);
       }
     
       @Override
    
    From 57870aaa058966f73efb3078edaeccac75ad6841 Mon Sep 17 00:00:00 2001
    From: Rob Bygrave 
    Date: Wed, 28 Mar 2018 13:22:46 +1300
    Subject: [PATCH 0208/1036] #115 - Mapping - Add support for @ElementCollection
     enhancement
    
    Add embedded bean support
    ---
     .../java/io/ebean/bean/BeanCollection.java    |   5 +
     .../ebean/common/AbstractBeanCollection.java  |   3 +-
     .../server/deploy/BeanCollectionUtil.java     |  10 ++
     .../server/deploy/BeanDescriptor.java         |  31 +++-
     .../server/deploy/BeanDescriptorElement.java  |  59 +++----
     .../deploy/BeanDescriptorElementEmbedded.java |  79 ++++++++++
     .../BeanDescriptorElementEmbeddedMap.java     |  84 ++++++++++
     .../deploy/BeanDescriptorElementMap.java      |  97 ------------
     .../deploy/BeanDescriptorElementScalar.java   |  56 +++++++
     .../BeanDescriptorElementScalarMap.java       |  88 +++++++++++
     .../server/deploy/BeanDescriptorJsonHelp.java |   2 +-
     .../server/deploy/BeanDescriptorManager.java  |  16 +-
     .../server/deploy/BeanPropertyAssocMany.java  |  38 ++++-
     .../deploy/BeanPropertySimpleCollection.java  |  32 +---
     .../meta/DeployBeanPropertyAssocMany.java     |  11 ++
     .../deploy/parse/AnnotationAssocManys.java    |  42 +++--
     .../server/persist/DefaultPersister.java      |   4 +-
     .../server/persist/SaveManyBase.java          |  14 ++
     .../server/persist/SaveManyBeans.java         |  14 --
     ...on.java => SaveManyElementCollection.java} |  19 ++-
     ...java => SaveManyElementCollectionMap.java} |  23 +--
     .../server/type/TypeReflectHelper.java        |   7 +
     .../model/elementcollection/EcPhone.java      |  52 ++++++
     .../model/elementcollection/EcblPerson.java   |  67 ++++++++
     .../model/elementcollection/EcbmPerson.java   |  68 ++++++++
     .../TestElementCollectionBasic.java           |  89 ++++++++++-
     .../TestElementCollectionBasicMap.java        | 103 ++++++++++--
     .../TestElementCollectionBasicSet.java        |  88 ++++++++++-
     .../TestElementCollectionEmbeddedList.java    | 148 ++++++++++++++++++
     .../TestElementCollectionEmbeddedMap.java     | 141 +++++++++++++++++
     30 files changed, 1247 insertions(+), 243 deletions(-)
     create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java
     create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java
     delete mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java
     create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java
     create mode 100644 src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java
     rename src/main/java/io/ebeaninternal/server/persist/{SaveManySimpleCollection.java => SaveManyElementCollection.java} (64%)
     rename src/main/java/io/ebeaninternal/server/persist/{SaveManySimpleMap.java => SaveManyElementCollectionMap.java} (57%)
     create mode 100644 src/test/java/org/tests/model/elementcollection/EcPhone.java
     create mode 100644 src/test/java/org/tests/model/elementcollection/EcblPerson.java
     create mode 100644 src/test/java/org/tests/model/elementcollection/EcbmPerson.java
     create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java
     create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java
    
    diff --git a/src/main/java/io/ebean/bean/BeanCollection.java b/src/main/java/io/ebean/bean/BeanCollection.java
    index 8c3b95b08..3ec5163e3 100644
    --- a/src/main/java/io/ebean/bean/BeanCollection.java
    +++ b/src/main/java/io/ebean/bean/BeanCollection.java
    @@ -72,6 +72,11 @@ public interface BeanCollection extends Serializable {
        */
       boolean isSkipSave();
     
    +  /**
    +   * Return true if the collection holds modifications.
    +   */
    +  boolean holdsModifications();
    +
       /**
        * Return the bean that owns this collection.
        */
    diff --git a/src/main/java/io/ebean/common/AbstractBeanCollection.java b/src/main/java/io/ebean/common/AbstractBeanCollection.java
    index e4641814a..ca5493d2a 100644
    --- a/src/main/java/io/ebean/common/AbstractBeanCollection.java
    +++ b/src/main/java/io/ebean/common/AbstractBeanCollection.java
    @@ -207,7 +207,8 @@ abstract class AbstractBeanCollection implements BeanCollection {
       /**
        * Return true if there are underlying additions or removals.
        */
    -  boolean holdsModifications() {
    +  @Override
    +  public boolean holdsModifications() {
         return modifyHolder != null && modifyHolder.hasModifications();
       }
     
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionUtil.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionUtil.java
    index 40171b0da..0b8d46dcf 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionUtil.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionUtil.java
    @@ -11,6 +11,16 @@ import java.util.Map;
      */
     public class BeanCollectionUtil {
     
    +  /**
    +   * Return true if this is a bean collection and not considered dirty.
    +   */
    +  public static boolean isModified(Object collection) {
    +    if ((collection instanceof BeanCollection)) {
    +      return ((BeanCollection) collection).holdsModifications();
    +    }
    +    return true;
    +  }
    +
       /**
        * Return the details of the collection or map taking care to avoid
        * unnecessary fetching of the data.
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    index 5bbd28ee8..620b6e1fd 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    @@ -235,7 +235,7 @@ public class BeanDescriptor implements BeanType, STreeType {
       /**
        * The type of bean this describes.
        */
    -  private final Class beanType;
    +  final Class beanType;
     
       protected final Class rootBeanType;
     
    @@ -428,8 +428,8 @@ public class BeanDescriptor implements BeanType, STreeType {
         this.name = InternString.intern(deploy.getName());
         this.baseTableAlias = "t0";
         this.fullName = InternString.intern(deploy.getFullName());
    -    this.locationById = ProfileLocation.createAt(fullName+".byId");
    -    this.locationAll = ProfileLocation.createAt(fullName+".all");
    +    this.locationById = ProfileLocation.createAt(fullName + ".byId");
    +    this.locationAll = ProfileLocation.createAt(fullName + ".all");
         this.profileBeanId = deploy.getProfileId();
         this.beanType = deploy.getBeanType();
         this.rootBeanType = PersistenceContextUtil.root(beanType);
    @@ -776,7 +776,7 @@ public class BeanDescriptor implements BeanType, STreeType {
     
         for (BeanProperty prop : propertiesNonTransient) {
           if (prop.isUnique()) {
    -        propertiesUnique.add(new BeanProperty[] { prop });
    +        propertiesUnique.add(new BeanProperty[]{prop});
           }
         }
         // convert unique columns to properties
    @@ -860,6 +860,16 @@ public class BeanDescriptor implements BeanType, STreeType {
         }
       }
     
    +  /**
    +   * Bind all the property values to the SqlUpdate.
    +   */
    +  public void bindElementValue(SqlUpdate insert, Object value) {
    +    EntityBean bean = (EntityBean) value;
    +    for (BeanProperty property : propertiesBaseScalar) {
    +      insert.setNextParameter(property.getValue(bean));
    +    }
    +  }
    +
       /**
        * Return the ReadAuditLogger for logging read audit events.
        */
    @@ -1420,7 +1430,7 @@ public class BeanDescriptor implements BeanType, STreeType {
       @SuppressWarnings("unchecked")
       public void cacheBeanPutAll(Collection beans) {
         if (!beans.isEmpty()) {
    -      cacheHelp.beanPutAll((Collection)beans);
    +      cacheHelp.beanPutAll((Collection) beans);
         }
       }
     
    @@ -1879,12 +1889,19 @@ public class BeanDescriptor implements BeanType, STreeType {
       }
     
       /**
    -   * Creates a new entitybean without invoking {@link BeanPostConstructListener#postCreate(Object)}
    +   * Creates a new entity bean without invoking {@link BeanPostConstructListener#postCreate(Object)}
        */
       public EntityBean createEntityBean() {
         return createEntityBean(false);
       }
     
    +  /**
    +   * Create an entity bean for JSON marshalling (which differs for the element collection case).
    +   */
    +  public EntityBean createEntityBeanForJson() {
    +    return createEntityBean();
    +  }
    +
       /**
        * Create a reference bean based on the id.
        */
    @@ -2471,7 +2488,7 @@ public class BeanDescriptor implements BeanType, STreeType {
     
       /**
        * Return a property that is part of the SQL tree.
    -   *
    +   * 

    * The property can be a dynamic formula or a well known bean property. */ @Override diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java index a1c23603a..0790ba10e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElement.java @@ -1,34 +1,35 @@ package io.ebeaninternal.server.deploy; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import io.ebean.PersistenceIOException; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.ScalarType; -import java.io.IOException; +import java.util.Arrays; /** * Bean descriptor used with ElementCollection (where we don't have a mapped type/class). + *

    + * This is somewhat a BeanDescriptor created 'on the fly' for a specific element collection property + * with a unidirectional property and mapping etc specific to the property (and not the type if embedded). */ -class BeanDescriptorElement extends BeanDescriptor { +abstract class BeanDescriptorElement extends BeanDescriptor { - private final ScalarType scalarType; - private final ElementHelp elementHelp; + final ElementHelp elementHelp; BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { super(owner, deploy); this.elementHelp = elementHelp; + } - BeanProperty[] props = propertiesNonTransient(); - if (props.length == 1) { - this.scalarType = props[0].getScalarType(); - } else { - this.scalarType = null; + /** + * Find and return the first base scalar type (and we expect only 1). + */ + ScalarType firstBaseScalarType() { + BeanProperty[] props = propertiesBaseScalar(); + if (props.length != 1) { + throw new IllegalStateException("Expecting 1 property for element scalar but got " + Arrays.toString(props)); } + return props[0].getScalarType(); } @Override @@ -36,35 +37,13 @@ class BeanDescriptorElement extends BeanDescriptor { return true; } + /** + * Our entity beans used are somewhat fake ones (ElementEntityBean) such that we hold the unidirectional property + * value (foreign key) and the actual element collection value (scalar or embedded plus map key). + */ @Override protected EntityBean createPrototypeEntityBean(Class beanType) { return new ElementEntityBean(properties); } - @Override - public void jsonWriteElement(SpiJsonWriter ctx, Object element) { - try { - scalarType.jsonWrite(ctx.gen(), element); - } catch (IOException e) { - throw new PersistenceIOException(e); - } - } - - @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { - - JsonParser parser = readJson.getParser(); - ElementCollector add = elementHelp.createCollector(); - do { - JsonToken token = parser.nextToken(); - if (JsonToken.VALUE_NULL == token || JsonToken.END_ARRAY == token) { - break; - } - Object element = scalarType.jsonRead(parser); - add.addElement(element); - } while (true); - - return add.collection(); - } - } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java new file mode 100644 index 000000000..cb17a9492 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java @@ -0,0 +1,79 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.PersistenceIOException; +import io.ebean.SqlUpdate; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; + +import java.io.IOException; + +/** + * Bean descriptor used with element collection of list/set of embeddable. + */ +class BeanDescriptorElementEmbedded extends BeanDescriptorElement { + + private final BeanPropertyAssocOne embeddedProperty; + + private final EntityBean prototype; + + private BeanDescriptor targetDescriptor; + + BeanDescriptorElementEmbedded(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { + super(owner, deploy, elementHelp); + try { + this.prototype = (EntityBean) beanType.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("Unable to create entity bean prototype for "+beanType); + } + BeanPropertyAssocOne[] embedded = propertiesEmbedded(); + if (embedded.length == 1) { + embeddedProperty = embedded[0]; + } else { + embeddedProperty = null; + } + } + + @Override + public void initialiseOther(BeanDescriptorInitContext initContext) { + super.initialiseOther(initContext); + this.targetDescriptor = embeddedProperty.getTargetDescriptor(); + } + + @Override + public EntityBean createEntityBeanForJson() { + return (EntityBean)prototype._ebean_newInstance(); + } + + public void bindElementValue(SqlUpdate insert, Object value) { + targetDescriptor.bindElementValue(insert, value); + } + + @Override + public void jsonWriteElement(SpiJsonWriter ctx, Object element) { + writeJsonElement(ctx, element); + } + + @Override + public T jsonRead(ReadJson jsonRead, String path) throws IOException { + return readJsonElement(jsonRead, path); + } + + @SuppressWarnings("unchecked") + T readJsonElement(ReadJson jsonRead, String path) throws IOException { + return (T)targetDescriptor.jsonRead(jsonRead, path); + } + + void writeJsonElement(SpiJsonWriter ctx, Object element) { + try { + if (element == null) { + ctx.writeNull(); + } else { + targetDescriptor.jsonWrite(ctx, (EntityBean)element); + } + } catch (IOException e) { + throw new PersistenceIOException(e); + } + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java new file mode 100644 index 000000000..49b85d699 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java @@ -0,0 +1,84 @@ +package io.ebeaninternal.server.deploy; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; + +import java.io.IOException; +import java.util.Map; + +/** + * Descriptor for element collection using Map with the value holding an embedded bean. + *

    + * The expected limitation is that the key is a scalar type. + */ +class BeanDescriptorElementEmbeddedMap extends BeanDescriptorElementEmbedded { + + private final ScalarType scalarTypeKey; + + private final boolean stringKey; + + BeanDescriptorElementEmbeddedMap(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { + super(owner, deploy, elementHelp); + this.scalarTypeKey = firstBaseScalarType(); + this.stringKey = String.class.equals(scalarTypeKey.getType()); + } + + @Override + @SuppressWarnings("unchecked") + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + ctx.writeStartObject(); + if (stringKey) { + Object key = entry.getKey(); + String keyName = (key == null) ? "null" : key.toString(); + ctx.writeFieldName(keyName); + writeJsonElement(ctx, entry.getValue()); + } else { + ctx.writeFieldName("key"); + scalarTypeKey.jsonWrite(ctx.gen(), entry.getKey()); + ctx.writeFieldName("value"); + writeJsonElement(ctx, entry.getValue()); + } + ctx.writeEndObject(); + } + + @Override + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + JsonParser parser = readJson.getParser(); + ElementCollector add = elementHelp.createCollector(); + do { + JsonToken token = parser.nextToken(); + if (token != JsonToken.START_OBJECT) { + break; + } + if (stringKey) { + String key = parser.nextFieldName(); + parser.nextToken(); + Object val = readJsonElement(readJson, null); + add.addKeyValue(key, val); + + } else { + parser.nextFieldName(); + Object key = scalarTypeKey.jsonRead(parser); + + parser.nextFieldName(); + Object val = readJsonElement(readJson, null); + add.addKeyValue(key, val); + } + + token = parser.nextToken(); + if (token != JsonToken.END_OBJECT) { + break; + } + + } while (true); + + return add.collection(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java deleted file mode 100644 index 3319ba8fc..000000000 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementMap.java +++ /dev/null @@ -1,97 +0,0 @@ -package io.ebeaninternal.server.deploy; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; -import io.ebeaninternal.server.type.ScalarType; - -import java.io.IOException; -import java.util.Map; - -/** - * Bean descriptor used with ElementCollection (where we don't have a mapped type/class). - */ -class BeanDescriptorElementMap extends BeanDescriptor { - - private final ScalarType[] scalarTypes; - private final ElementHelp elementHelp; - private final boolean stringKey; - - BeanDescriptorElementMap(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { - super(owner, deploy); - this.elementHelp = elementHelp; - BeanProperty[] props = propertiesNonTransient(); - this.scalarTypes = new ScalarType[props.length]; - for (int i = 0; i < props.length; i++) { - scalarTypes[i] = props[i].getScalarType(); - } - this.stringKey = String.class.equals(scalarTypes[0].getType()); - } - - @Override - public boolean isElementType() { - return true; - } - - @Override - protected EntityBean createPrototypeEntityBean(Class beanType) { - return new ElementEntityBean(properties); - } - - @Override - @SuppressWarnings("unchecked") - public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { - ctx.writeStartObject(); - if (stringKey) { - Object key = entry.getKey(); - String keyName = (key == null) ? "null" : key.toString(); - ctx.writeFieldName(keyName); - scalarTypes[1].jsonWrite(ctx.gen(), entry.getValue()); - } else { - ctx.writeFieldName("key"); - scalarTypes[0].jsonWrite(ctx.gen(), entry.getKey()); - ctx.writeFieldName("value"); - scalarTypes[1].jsonWrite(ctx.gen(), entry.getValue()); - } - ctx.writeEndObject(); - } - - @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { - - JsonParser parser = readJson.getParser(); - ElementCollector add = elementHelp.createCollector(); - do { - JsonToken token = parser.nextToken(); - if (token != JsonToken.START_OBJECT) { - break; - } - if (stringKey) { - String key = parser.nextFieldName(); - parser.nextToken(); - Object val = scalarTypes[0].jsonRead(parser); - add.addKeyValue(key, val); - - } else { - parser.nextFieldName(); - Object key= scalarTypes[0].jsonRead(parser); - - parser.nextFieldName(); - Object val = scalarTypes[0].jsonRead(parser); - add.addKeyValue(key, val); - } - - token = parser.nextToken(); - if (token != JsonToken.END_OBJECT) { - break; - } - - } while (true); - - return add.collection(); - } - -} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java new file mode 100644 index 000000000..1b7ac70ea --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java @@ -0,0 +1,56 @@ +package io.ebeaninternal.server.deploy; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import io.ebean.PersistenceIOException; +import io.ebean.SqlUpdate; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; + +import java.io.IOException; + +/** + * Bean descriptor used with element collection mapped to a list or set of scalar values. + */ +class BeanDescriptorElementScalar extends BeanDescriptorElement { + + private final ScalarType scalarType; + + BeanDescriptorElementScalar(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { + super(owner, deploy, elementHelp); + this.scalarType = firstBaseScalarType(); + } + + public void bindElementValue(SqlUpdate insert, Object value) { + insert.setNextParameter(value); + } + + @Override + public void jsonWriteElement(SpiJsonWriter ctx, Object element) { + try { + scalarType.jsonWrite(ctx.gen(), element); + } catch (IOException e) { + throw new PersistenceIOException(e); + } + } + + @Override + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + JsonParser parser = readJson.getParser(); + ElementCollector add = elementHelp.createCollector(); + do { + JsonToken token = parser.nextToken(); + if (JsonToken.VALUE_NULL == token || JsonToken.END_ARRAY == token) { + break; + } + add.addElement(scalarType.jsonRead(parser)); + } while (true); + + return add.collection(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java new file mode 100644 index 000000000..9eb87ba0b --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java @@ -0,0 +1,88 @@ +package io.ebeaninternal.server.deploy; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import io.ebean.bean.EntityBean; +import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; +import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.server.type.ScalarType; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; + +/** + * Bean descriptor used with element collection mapped to Map where key and value are scalar types. + */ +class BeanDescriptorElementScalarMap extends BeanDescriptorElement { + + private final ScalarType scalarTypeKey; + private final ScalarType scalarTypeVal; + private final boolean stringKey; + + BeanDescriptorElementScalarMap(BeanDescriptorMap owner, DeployBeanDescriptor deploy, ElementHelp elementHelp) { + super(owner, deploy, elementHelp); + BeanProperty[] props = propertiesNonTransient(); + if (props.length != 2) { + throw new IllegalStateException("Expecting 2 properties for key and value but got " + Arrays.toString(props)); + } + this.scalarTypeKey = props[0].getScalarType(); + this.scalarTypeVal = props[1].getScalarType(); + this.stringKey = String.class.equals(scalarTypeKey.getType()); + } + + @Override + @SuppressWarnings("unchecked") + public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { + ctx.writeStartObject(); + if (stringKey) { + Object key = entry.getKey(); + String keyName = (key == null) ? "null" : key.toString(); + ctx.writeFieldName(keyName); + scalarTypeVal.jsonWrite(ctx.gen(), entry.getValue()); + } else { + ctx.writeFieldName("key"); + scalarTypeKey.jsonWrite(ctx.gen(), entry.getKey()); + ctx.writeFieldName("value"); + scalarTypeVal.jsonWrite(ctx.gen(), entry.getValue()); + } + ctx.writeEndObject(); + } + + @Override + public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + JsonParser parser = readJson.getParser(); + ElementCollector add = elementHelp.createCollector(); + do { + JsonToken token = parser.nextToken(); + if (token != JsonToken.START_OBJECT) { + break; + } + if (stringKey) { + String key = parser.nextFieldName(); + parser.nextToken(); + Object val = scalarTypeVal.jsonRead(parser); + add.addKeyValue(key, val); + + } else { + parser.nextFieldName(); + Object key = scalarTypeKey.jsonRead(parser); + + parser.nextFieldName(); + Object val = scalarTypeVal.jsonRead(parser); + add.addKeyValue(key, val); + } + + token = parser.nextToken(); + if (token != JsonToken.END_OBJECT) { + break; + } + + } while (true); + + return add.collection(); + } + +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java index ad9d640a3..8d90a3af5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java @@ -118,7 +118,7 @@ public class BeanDescriptorJsonHelp { protected T jsonReadObject(ReadJson readJson, String path) throws IOException { - EntityBean bean = desc.createEntityBean(); + EntityBean bean = desc.createEntityBeanForJson(); return jsonReadProperties(readJson, bean, path); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 0e6814365..3c95f9515 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -637,7 +637,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { /** * Return a BeanTable for an ElementCollection. */ - public BeanTable getCollectionBeanTable(String fullTableName, Class targetType) { + public BeanTable createCollectionBeanTable(String fullTableName, Class targetType) { return new BeanTable(this, fullTableName, targetType); } @@ -1637,13 +1637,21 @@ public class BeanDescriptorManager implements BeanDescriptorMap { /** * Create a BeanDescriptor for an ElementCollection target. */ - public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor, ManyType manyType) { + public BeanDescriptor createElementDescriptor(DeployBeanDescriptor elementDescriptor, ManyType manyType, boolean scalar) { ElementHelp elementHelp = elementHelper(manyType); if (manyType.isMap()) { - return new BeanDescriptorElementMap<>(this, elementDescriptor, elementHelp); + if (scalar) { + return new BeanDescriptorElementScalarMap<>(this, elementDescriptor, elementHelp); + } else { + return new BeanDescriptorElementEmbeddedMap<>(this, elementDescriptor, elementHelp); + } + } + if (scalar) { + return new BeanDescriptorElementScalar<>(this, elementDescriptor, elementHelp); + } else { + return new BeanDescriptorElementEmbedded<>(this, elementDescriptor, elementHelp); } - return new BeanDescriptorElement<>(this, elementDescriptor, elementHelp); } private ElementHelp elementHelper(ManyType manyType) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 0072949a6..2ef769116 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -70,6 +70,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST private final boolean elementCollection; + /** + * Descriptor for the 'target' when the property maps to an element collection. + */ + BeanDescriptor elementDescriptor; + /** * Order by used when fetch joining the associated many. */ @@ -116,6 +121,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST this.hasOrderColumn = deploy.hasOrderColumn(); this.manyToMany = deploy.isManyToMany(); this.elementCollection = deploy.isElementCollection(); + this.elementDescriptor = deploy.getElementDescriptor(); this.manyType = deploy.getManyType(); this.mapKey = deploy.getMapKey(); this.fetchOrderBy = deploy.getFetchOrderBy(); @@ -136,6 +142,19 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST public void initialise(BeanDescriptorInitContext initContext) { super.initialise(initContext); initialiseAssocMany(); + if (elementCollection) { + // initialise all non-id properties (we don't have an Id property) + elementDescriptor.initialiseOther(initContext); + } + } + + @Override + void initialiseTargetDescriptor(BeanDescriptorInitContext initContext) { + if (elementCollection) { + targetDescriptor = elementDescriptor; + } else { + targetDescriptor = descriptor.getBeanDescriptor(targetType); + } } private void initialiseAssocMany() { @@ -170,7 +189,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST } String targetTable() { - return targetDescriptor.getBaseTable(); + return beanTable.getBaseTable(); } /** @@ -883,18 +902,22 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST } public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { - // Writing as json array rather than object ... - targetDescriptor.jsonWrite(ctx, (EntityBean) entry.getValue()); + elementDescriptor.jsonWriteMapEntry(ctx, entry); } public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { - throw new IllegalStateException("Unexpected - expect Element override"); + elementDescriptor.jsonWriteElement(ctx, element); } /** * Read the collection (JSON Array) containing entity beans. */ public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + + if (elementDescriptor != null && manyType.isMap()) { + return elementDescriptor.jsonReadCollection(readJson, parentBean); + } + BeanCollection collection = createEmpty(parentBean); BeanCollectionAdd add = getBeanCollectionAdd(collection, null); do { @@ -913,4 +936,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST return collection; } + + /** + * Bind all the property values to the SqlUpdate. + */ + public void bindElementValue(SqlUpdate insert, Object value) { + targetDescriptor.bindElementValue(insert, value); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java index 6b9d1602e..f00b401cd 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java @@ -1,47 +1,21 @@ package io.ebeaninternal.server.deploy; +import io.ebean.SqlUpdate; import io.ebean.bean.EntityBean; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection; import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; -import java.util.Map; public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { - private BeanDescriptor elementDescriptor; - public BeanPropertySimpleCollection(BeanDescriptor descriptor, DeployBeanPropertySimpleCollection deploy) { super(descriptor, deploy); - this.elementDescriptor = deploy.getElementDescriptor(); } @Override - public void initialise(BeanDescriptorInitContext initContext) { - super.initialise(initContext); - if (isElementCollection()) { - // initialise all non-id properties (we don't have an Id property) - elementDescriptor.initialiseOther(initContext); - } - } - - void initialiseTargetDescriptor(BeanDescriptorInitContext initContext) { - if (isElementCollection()) { - targetDescriptor = elementDescriptor; - } else { - targetDescriptor = descriptor.getBeanDescriptor(targetType); - } - } - - @Override - public void jsonWriteMapEntry(SpiJsonWriter ctx, Map.Entry entry) throws IOException { - elementDescriptor.jsonWriteMapEntry(ctx, entry); - } - - @Override - public void jsonWriteElementValue(SpiJsonWriter ctx, Object element) { - elementDescriptor.jsonWriteElement(ctx, element); + public void bindElementValue(SqlUpdate insert, Object value) { + insert.setNextParameter(value); } @Override diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java index 4e6d7d7d8..6e0394273 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocMany.java @@ -4,6 +4,9 @@ import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.ManyType; import io.ebeaninternal.server.deploy.TableJoin; +import io.ebeaninternal.server.type.TypeReflectHelper; + +import java.lang.reflect.Type; /** * Property mapped to a List Set or Map. @@ -179,6 +182,14 @@ public class DeployBeanPropertyAssocMany extends DeployBeanPropertyAssoc { return fetchOrderBy; } + /** + * Return the type of the map key (valid only when this property is a Map). + */ + public Class getMapKeyType() { + Type genericType = getField().getGenericType(); + return TypeReflectHelper.getMapKeyType(genericType); + } + /** * Return the default mapKey when returning a Map. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 7c98d20c4..24f3c96aa 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -15,6 +15,7 @@ import io.ebeaninternal.server.deploy.BeanTable; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import io.ebeaninternal.server.deploy.meta.DeployOrderColumn; import io.ebeaninternal.server.deploy.meta.DeployTableJoin; import io.ebeaninternal.server.deploy.meta.DeployTableJoinColumn; @@ -204,7 +205,7 @@ class AnnotationAssocManys extends AnnotationParser { } } - BeanTable beanTable = factory.getCollectionBeanTable(fullTableName, prop.getTargetType()); + BeanTable beanTable = factory.createCollectionBeanTable(fullTableName, prop.getTargetType()); prop.setBeanTable(beanTable); Class elementType = prop.getTargetType(); @@ -212,8 +213,6 @@ class AnnotationAssocManys extends AnnotationParser { DeployBeanDescriptor elementDescriptor = factory.createDeployDescriptor(elementType); elementDescriptor.setBaseTable(new TableName(fullTableName), readConfig.getAsOfViewSuffix(), readConfig.getVersionsBetweenSuffix()); - ScalarType scalarType = util.getTypeManager().getScalarType(elementType); - int sortOrder = 0; if (!prop.getManyType().isMap()) { elementDescriptor.setProperties(new String[]{"value"}); @@ -225,27 +224,46 @@ class AnnotationAssocManys extends AnnotationParser { dbKeyColumn = mapKeyColumn.name(); } - DeployBeanProperty keyProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); + ScalarType keyScalarType = util.getTypeManager().getScalarType(prop.getMapKeyType()); + + DeployBeanProperty keyProp = new DeployBeanProperty(elementDescriptor, elementType, keyScalarType, null); setElementProperty(keyProp, "key", dbKeyColumn, sortOrder++); elementDescriptor.addBeanProperty(keyProp); if (mapKeyColumn != null) { keyProp.setDbLength(mapKeyColumn.length()); keyProp.setDbScale(mapKeyColumn.scale()); + keyProp.setUnique(mapKeyColumn.unique()); } } - DeployBeanProperty valueProp = new DeployBeanProperty(elementDescriptor, elementType, scalarType, null); - setElementProperty(valueProp, "value", prop.getDbColumn(), sortOrder++); - if (column != null) { - valueProp.setDbLength(column.length()); - valueProp.setDbScale(column.scale()); + ScalarType valueScalarType = util.getTypeManager().getScalarType(elementType); + + boolean scalar = true; + if (valueScalarType == null) { + // embedded value type + scalar = false; + DeployBeanPropertyAssocOne valueProp = new DeployBeanPropertyAssocOne<>(elementDescriptor, elementType); + valueProp.setName("value"); + valueProp.setEmbedded(); + valueProp.setElementProperty(); + valueProp.setSortOrder(sortOrder++); + elementDescriptor.addBeanProperty(valueProp); + + } else { + // scalar value type + DeployBeanProperty valueProp = new DeployBeanProperty(elementDescriptor, elementType, valueScalarType, null); + setElementProperty(valueProp, "value", prop.getDbColumn(), sortOrder++); + if (column != null) { + valueProp.setDbLength(column.length()); + valueProp.setDbScale(column.scale()); + } + elementDescriptor.addBeanProperty(valueProp); } - elementDescriptor.addBeanProperty(valueProp); elementDescriptor.setName(prop.getFullBeanName()); factory.createUnidirectional(elementDescriptor, prop.getOwningType(), beanTable, prop.getTableJoin()); - prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor, prop.getManyType())); + prop.setElementDescriptor(factory.createElementDescriptor(elementDescriptor, prop.getManyType(), scalar)); } private void setElementProperty(DeployBeanProperty elementProp, String name, String dbColumn, int sortOrder) { @@ -307,7 +325,7 @@ class AnnotationAssocManys extends AnnotationParser { * Return the full table name */ private String getFullTableName(CollectionTable collectionTable) { - if (collectionTable == null) { + if (collectionTable == null || collectionTable.name().isEmpty()) { return null; } StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index f02969461..b16a0ced8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -906,10 +906,10 @@ public final class DefaultPersister implements Persister { return new SaveManyBeans(insertedParent, many, parentBean, request, this); } else if (many.getManyType().isMap()) { - return new SaveManySimpleMap(insertedParent, many, parentBean, request); + return new SaveManyElementCollectionMap(insertedParent, many, parentBean, request); } else { - return new SaveManySimpleCollection(insertedParent, many, parentBean, request); + return new SaveManyElementCollection(insertedParent, many, parentBean, request); } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java index 61a080188..9f892c5e8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.persist; +import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiTransaction; @@ -34,4 +35,17 @@ abstract class SaveManyBase { */ abstract void save(); + void resetModifyState() { + if (value instanceof BeanCollection) { + modifyListenReset((BeanCollection) value); + } + } + + void modifyListenReset(BeanCollection c) { + if (insertedParent) { + // after insert set the modify listening mode for private owned etc + c.setModifyListening(many.getModifyListenMode()); + } + c.modifyReset(); + } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java index cdd84d158..063862967 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java @@ -89,20 +89,6 @@ class SaveManyBeans extends SaveManyBase { return BeanCollection.ModifyListenMode.REMOVALS == many.getModifyListenMode(); } - private void modifyListenReset(BeanCollection c) { - if (insertedParent) { - // after insert set the modify listening mode for private owned etc - c.setModifyListening(many.getModifyListenMode()); - } - c.modifyReset(); - } - - private void resetModifyState() { - if (value instanceof BeanCollection) { - modifyListenReset((BeanCollection) value); - } - } - /** * Save the details from a OneToMany collection. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java similarity index 64% rename from src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java rename to src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java index 49a4f09e9..1867421fa 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java @@ -12,9 +12,9 @@ import java.util.Collection; /** * Save details for a simple scalar element collection. */ -class SaveManySimpleCollection extends SaveManyBase { +class SaveManyElementCollection extends SaveManyBase { - SaveManySimpleCollection(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + SaveManyElementCollection(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { super(insertedParent, many, parentBean, request); } @@ -22,16 +22,18 @@ class SaveManySimpleCollection extends SaveManyBase { void save() { Collection collection = BeanCollectionUtil.getActualEntries(value); - if (collection == null) { + if (collection == null || !BeanCollectionUtil.isModified(value)) { return; } Object parentId = request.getBeanId(); - SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); - SpiEbeanServer server = request.getServer(); - server.execute(sqlDelete, transaction); + + if (!insertedParent) { + SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); + server.execute(sqlDelete, transaction); + } transaction.depth(+1); @@ -40,11 +42,12 @@ class SaveManySimpleCollection extends SaveManyBase { for (Object value : collection) { - sqlInsert.setParameter(1, parentId); - sqlInsert.setParameter(2, value); + sqlInsert.setNextParameter(parentId); + many.bindElementValue(sqlInsert, value); server.execute(sqlInsert, transaction); } transaction.depth(-1); + resetModifyState(); } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java similarity index 57% rename from src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java rename to src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java index 84d57c222..3ba94d781 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManySimpleMap.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java @@ -13,9 +13,9 @@ import java.util.Set; /** * Save details for a simple scalar map element collection. */ -class SaveManySimpleMap extends SaveManyBase { +class SaveManyElementCollectionMap extends SaveManyBase { - SaveManySimpleMap(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { + SaveManyElementCollectionMap(boolean insertedParent, BeanPropertyAssocMany many, EntityBean parentBean, PersistRequestBean request) { super(insertedParent, many, parentBean, request); } @@ -23,17 +23,19 @@ class SaveManySimpleMap extends SaveManyBase { @Override void save() { - Set> entries = (Set>)BeanCollectionUtil.getActualEntries(value); - if (entries == null) { + Set> entries = (Set>) BeanCollectionUtil.getActualEntries(value); + if (entries == null || !BeanCollectionUtil.isModified(value)) { return; } Object parentId = request.getBeanId(); - SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); - SpiEbeanServer server = request.getServer(); - server.execute(sqlDelete, transaction); + + if (!insertedParent) { + SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); + server.execute(sqlDelete, transaction); + } transaction.depth(+1); @@ -41,12 +43,13 @@ class SaveManySimpleMap extends SaveManyBase { SqlUpdate sqlInsert = server.createSqlUpdate(insert); for (Map.Entry entry : entries) { - sqlInsert.setParameter(1, parentId); - sqlInsert.setParameter(2, entry.getKey()); - sqlInsert.setParameter(3, entry.getValue()); + sqlInsert.setNextParameter(parentId); + sqlInsert.setNextParameter(entry.getKey()); + many.bindElementValue(sqlInsert, entry.getValue()); server.execute(sqlInsert, transaction); } transaction.depth(-1); + resetModifyState(); } } diff --git a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java index 392c0829b..663d18f00 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeReflectHelper.java @@ -30,6 +30,13 @@ public class TypeReflectHelper { } } + /** + * Return the type of the map key. + */ + public static Class getMapKeyType(Type genericType) { + return getClass(getValueType(genericType)); + } + /** * Return the value type of a collection type (list, set, map values). */ diff --git a/src/test/java/org/tests/model/elementcollection/EcPhone.java b/src/test/java/org/tests/model/elementcollection/EcPhone.java new file mode 100644 index 000000000..24f71559f --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcPhone.java @@ -0,0 +1,52 @@ +package org.tests.model.elementcollection; + +import javax.persistence.Embeddable; +import javax.validation.constraints.Size; + +@Embeddable +public class EcPhone { + + @Size(max = 2) + String countryCode; + + @Size(max = 6) + String area; + + @Size(max = 20) + String number; + + public EcPhone(String countryCode, String area, String number) { + this.countryCode = countryCode; + this.area = area; + this.number = number; + } + + @Override + public String toString() { + return countryCode + "-" + area + "-" + number; + } + + public String getCountryCode() { + return countryCode; + } + + public void setCountryCode(String countryCode) { + this.countryCode = countryCode; + } + + public String getArea() { + return area; + } + + public void setArea(String area) { + this.area = area; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/EcblPerson.java b/src/test/java/org/tests/model/elementcollection/EcblPerson.java new file mode 100644 index 000000000..982071e13 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcblPerson.java @@ -0,0 +1,67 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Version; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class EcblPerson { + + @Id + long id; + + String name; + + @ElementCollection + @CollectionTable(joinColumns = @JoinColumn(name = "person_id")) + List phoneNumbers = new ArrayList<>(); + + @Version + long version; + + public EcblPerson(String name) { + this.name = name; + } + + @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/src/test/java/org/tests/model/elementcollection/EcbmPerson.java b/src/test/java/org/tests/model/elementcollection/EcbmPerson.java new file mode 100644 index 000000000..7a236bb85 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcbmPerson.java @@ -0,0 +1,68 @@ +package org.tests.model.elementcollection; + +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Version; +import java.util.LinkedHashMap; +import java.util.Map; + + +@Entity +public class EcbmPerson { + + @Id + long id; + + String name; + + @ElementCollection + @CollectionTable(joinColumns = @JoinColumn(name = "person_id")) + Map phoneNumbers = new LinkedHashMap<>(); + + @Version + long version; + + public EcbmPerson(String name) { + this.name = name; + } + + @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 Map getPhoneNumbers() { + return phoneNumbers; + } + + public void setPhoneNumbers(Map phoneNumbers) { + this.phoneNumbers = phoneNumbers; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java index 54ef094cb..b55b3dba2 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -2,6 +2,7 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import java.util.List; @@ -13,17 +14,25 @@ public class TestElementCollectionBasic extends BaseTestCase { @Test public void test() { + LoggedSqlCollector.start(); + EcPerson person = new EcPerson("Fiona021"); person.getPhoneNumbers().add("021 1234"); person.getPhoneNumbers().add("021 4321"); Ebean.save(person); + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ec_person"); + assertThat(sql.get(1)).contains("insert into ec_person_phone"); EcPerson person1 = new EcPerson("Fiona09"); person1.getPhoneNumbers().add("09 1234"); person1.getPhoneNumbers().add("09 4321"); Ebean.save(person1); + LoggedSqlCollector.current(); + List found = Ebean.find(EcPerson.class).where() .startsWith("name", "Fiona0") @@ -37,6 +46,10 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321"); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version from ec_person t0 where"); + assertThat(trimSql(sql.get(1))).contains("select t0.owner_id, t0.phone from ec_person_phone t0 where"); List found2 = Ebean.find(EcPerson.class) @@ -47,11 +60,83 @@ public class TestElementCollectionBasic extends BaseTestCase { .findList(); assertThat(found2).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version, t1.phone from ec_person t0 left join ec_person_phone t1"); + EcPerson foundFirst = found2.get(0); + + jsonToFrom(foundFirst); + updateBasic(foundFirst); + + LoggedSqlCollector.stop(); + } + + private void updateBasic(EcPerson bean) { + + bean.setName("Fiona021-mod-0"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ec_person"); + + updateBoth(bean); + } + + private void updateBoth(EcPerson bean) { + + bean.setName("Fiona021-mod-both"); + bean.getPhoneNumbers().add("01-22123"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ec_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + + updateNothing(bean); + } + + private void updateNothing(EcPerson bean) { + + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(0); + + updateOnlyCollection(bean); + } + + private void updateOnlyCollection(EcPerson bean) { + + bean.getPhoneNumbers().add("01-4321"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + + delete(bean); + } + + private void delete(EcPerson bean) { + + Ebean.delete(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id = ?"); + assertThat(sql.get(1)).contains("delete from ec_person where id=? and version=?"); + } + + private void jsonToFrom(EcPerson foundFirst) { + String asJson = Ebean.json().toJson(foundFirst); - EcPerson fromJson = Ebean.json().toBean(EcPerson.class, asJson); - assertThat(fromJson.getPhoneNumbers()).containsAll(foundFirst.getPhoneNumbers()); } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java index 83bbb7561..f03bf1933 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java @@ -2,6 +2,7 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import java.util.List; @@ -14,26 +15,34 @@ public class TestElementCollectionBasicMap extends BaseTestCase { @Test public void test() { + LoggedSqlCollector.start(); + EcmPerson person = new EcmPerson("Fiona021"); - person.getPhoneNumbers().put("home","021 1234"); - person.getPhoneNumbers().put("work","021 4321"); + person.getPhoneNumbers().put("home", "021 1234"); + person.getPhoneNumbers().put("work", "021 4321"); Ebean.save(person); + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecm_person"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone"); EcmPerson person1 = new EcmPerson("Fiona09"); - person1.getPhoneNumbers().put("home","09 1234"); - person1.getPhoneNumbers().put("work","09 4321"); - person1.getPhoneNumbers().put("mob","09 9876"); + person1.getPhoneNumbers().put("home", "09 1234"); + person1.getPhoneNumbers().put("work", "09 4321"); + person1.getPhoneNumbers().put("mob", "09 9876"); Ebean.save(person1); + LoggedSqlCollector.current(); + List found = Ebean.find(EcmPerson.class).where() .startsWith("name", "Fiona0") .order().asc("id") .findList(); - Map phoneNumbers0 = found.get(0).getPhoneNumbers(); - Map phoneNumbers1 = found.get(1).getPhoneNumbers(); + Map phoneNumbers0 = found.get(0).getPhoneNumbers(); + Map phoneNumbers1 = found.get(1).getPhoneNumbers(); phoneNumbers0.size(); assertThat(phoneNumbers0).containsValues("021 1234", "021 4321"); @@ -41,6 +50,10 @@ public class TestElementCollectionBasicMap extends BaseTestCase { assertThat(phoneNumbers1).containsValues("09 1234", "09 4321", "09 9876"); assertThat(phoneNumbers1.get("mob")).isEqualTo("09 9876"); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version from ecm_person t0 where"); + assertThat(trimSql(sql.get(1))).contains("select t0.ecm_person_id, t0.type, t0.number from ecm_person_phone_numbers t0 where"); List found2 = Ebean.find(EcmPerson.class) @@ -51,13 +64,83 @@ public class TestElementCollectionBasicMap extends BaseTestCase { .findList(); assertThat(found2).hasSize(2); - EcmPerson foundFirst = found2.get(0); - String asJson = Ebean.json().toJson(foundFirst); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version, t1.type, t1.number from ecm_person t0 left join ecm_person_phone_numbers t1"); + + EcmPerson foundFirst = found2.get(0); + jsonToFrom(foundFirst); + updateBasic(foundFirst); + + LoggedSqlCollector.stop(); + } + + private void updateBasic(EcmPerson bean) { + + bean.setName("Fiona021-mod-0"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ecm_person"); + + updateBoth(bean); + } + + private void updateBoth(EcmPerson bean) { + + bean.setName("Fiona021-mod-both"); + bean.getPhoneNumbers().put("one", "01-22123"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + + updateNothing(bean); + } + + private void updateNothing(EcmPerson bean) { + + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(0); + + updateOnlyCollection(bean); + } + + private void updateOnlyCollection(EcmPerson bean) { + + bean.getPhoneNumbers().put("two", "01-4321"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + + delete(bean); + } + + private void delete(EcmPerson bean) { + + Ebean.delete(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecm_person_phone_numbers where ecm_person_id = ?"); + assertThat(sql.get(1)).contains("delete from ecm_person where id=? and version=?"); + } + + private void jsonToFrom(EcmPerson foundFirst) { + String asJson = Ebean.json().toJson(foundFirst); EcmPerson fromJson = Ebean.json().toBean(EcmPerson.class, asJson); assertThat(fromJson.getPhoneNumbers()).containsValues("021 1234", "021 4321"); assertThat(fromJson.getPhoneNumbers().get("home")).isEqualTo("021 1234"); - } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java index 946e273f7..2d3124351 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java @@ -2,6 +2,7 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import java.util.List; @@ -14,11 +15,17 @@ public class TestElementCollectionBasicSet extends BaseTestCase { @Test public void test() { + LoggedSqlCollector.start(); + EcsPerson person = new EcsPerson("Fiona021"); person.getPhoneNumbers().add("021 1234"); person.getPhoneNumbers().add("021 4321"); Ebean.save(person); + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecs_person"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone"); EcsPerson person1 = new EcsPerson("Fiona09"); person1.getPhoneNumbers().add("09 1234"); @@ -26,6 +33,8 @@ public class TestElementCollectionBasicSet extends BaseTestCase { person1.getPhoneNumbers().add("09 9876"); Ebean.save(person1); + LoggedSqlCollector.current(); + List found = Ebean.find(EcsPerson.class).where() .startsWith("name", "Fiona0") @@ -39,6 +48,10 @@ public class TestElementCollectionBasicSet extends BaseTestCase { assertThat(phoneNumbers0).containsExactly("021 1234", "021 4321"); assertThat(phoneNumbers1).containsExactly("09 1234", "09 4321", "09 9876"); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version from ecs_person t0 where"); + assertThat(trimSql(sql.get(1))).contains("select t0.ecs_person_id, t0.phone from ecs_person_phone t0 where"); List found2 = Ebean.find(EcsPerson.class) @@ -49,11 +62,82 @@ public class TestElementCollectionBasicSet extends BaseTestCase { .findList(); assertThat(found2).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version, t1.phone from ecs_person t0 left join ecs_person_phone t1"); + EcsPerson foundFirst = found2.get(0); + jsonToFrom(foundFirst); + + updateBasic(foundFirst); + + LoggedSqlCollector.stop(); + } + + private void updateBasic(EcsPerson bean) { + + bean.setName("Fiona021-mod-0"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ecs_person"); + + updateBoth(bean); + } + + private void updateBoth(EcsPerson bean) { + + bean.setName("Fiona021-mod-both"); + bean.getPhoneNumbers().add("01-22123"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecs_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + + updateNothing(bean); + } + + private void updateNothing(EcsPerson bean) { + + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(0); + + updateOnlyCollection(bean); + } + + private void updateOnlyCollection(EcsPerson bean) { + + bean.getPhoneNumbers().add("01-4321"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + + delete(bean); + } + + private void delete(EcsPerson bean) { + + Ebean.delete(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecs_person_phone where ecs_person_id = ?"); + assertThat(sql.get(1)).contains("delete from ecs_person where id=? and version=?"); + } + + private void jsonToFrom(EcsPerson foundFirst) { String asJson = Ebean.json().toJson(foundFirst); - EcsPerson fromJson = Ebean.json().toBean(EcsPerson.class, asJson); - assertThat(fromJson.getPhoneNumbers()).containsAll(foundFirst.getPhoneNumbers()); } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java new file mode 100644 index 000000000..8b86e6477 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java @@ -0,0 +1,148 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionEmbeddedList extends BaseTestCase { + + @Test + public void test() { + + LoggedSqlCollector.start(); + + EcblPerson person = new EcblPerson("Fiona64021"); + person.getPhoneNumbers().add(new EcPhone("64", "021","1234")); + person.getPhoneNumbers().add(new EcPhone("64","021","4321")); + Ebean.save(person); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecbl_person"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers"); + + EcblPerson person1 = new EcblPerson("Fiona6409"); + person1.getPhoneNumbers().add(new EcPhone("61","09","1234")); + person1.getPhoneNumbers().add(new EcPhone("64","09","4321")); + Ebean.save(person1); + + LoggedSqlCollector.current(); + + List found = + Ebean.find(EcblPerson.class).where() + .startsWith("name", "Fiona640") + .order().asc("id") + .findList(); + + List phoneNumbers0 = found.get(0).getPhoneNumbers(); + List phoneNumbers1 = found.get(1).getPhoneNumbers(); + phoneNumbers0.size(); + + assertThat(phoneNumbers0.toString()).contains("64-021-1234", "64-021-4321"); + assertThat(phoneNumbers1.toString()).contains("61-09-1234", "64-09-4321"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.name, t0.version from ecbl_person"); + assertThat(trimSql(sql.get(1))).contains("select t0.person_id, t0.country_code, t0.area, t0.number from ecbl_person_phone_numbers"); + + List found2 = + Ebean.find(EcblPerson.class) + .fetch("phoneNumbers") + .where() + .startsWith("name", "Fiona640") + .order().asc("id") + .findList(); + + assertThat(found2).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + String trimmedSql = trimSql(sql.get(0)); + assertThat(trimmedSql).contains("select t0.id, t0.name, t0.version, t1.country_code, t1.area, t1.number from ecbl_person t0 left join ecbl_person_phone_numbers t1"); + + + EcblPerson foundFirst = found2.get(0); + jsonToFrom(foundFirst); + + updateBasic(foundFirst); + + LoggedSqlCollector.stop(); + } + + private void updateBasic(EcblPerson bean) { + + bean.setName("Fiona64-mod-0"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ecbl_person"); + + updateBoth(bean); + } + + private void updateBoth(EcblPerson bean) { + + bean.setName("Fiona64-mod-both"); + bean.getPhoneNumbers().add(new EcPhone("01", "234", "123")); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecbl_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + + updateNothing(bean); + } + + private void updateNothing(EcblPerson bean) { + + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(0); + + updateOnlyCollection(bean); + } + + private void updateOnlyCollection(EcblPerson bean) { + + bean.getPhoneNumbers().add(new EcPhone("01", "12", "4321")); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + + delete(bean); + } + + private void delete(EcblPerson bean) { + + Ebean.delete(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id = ?"); + assertThat(sql.get(1)).contains("delete from ecbl_person where id=? and version=?"); + } + + private void jsonToFrom(EcblPerson foundFirst) { + + String asJson = Ebean.json().toJson(foundFirst); + + EcblPerson fromJson = Ebean.json().toBean(EcblPerson.class, asJson); + + String phoneString = fromJson.getPhoneNumbers().toString(); + assertThat(phoneString).contains("64-021-1234"); + assertThat(phoneString).contains("64-021-4321"); + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java new file mode 100644 index 000000000..ca342342c --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java @@ -0,0 +1,141 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionEmbeddedMap extends BaseTestCase { + + @Test + public void test() { + + LoggedSqlCollector.start(); + + EcbmPerson person = new EcbmPerson("Fiona64021"); + person.getPhoneNumbers().put("home", new EcPhone("64", "021","1234")); + person.getPhoneNumbers().put("work", new EcPhone("64","021","4321")); + Ebean.save(person); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecbm_person"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers"); + + EcbmPerson person1 = new EcbmPerson("Fiona6409"); + person1.getPhoneNumbers().put("home",new EcPhone("64","09","1234")); + person1.getPhoneNumbers().put("mob",new EcPhone("61","09","4321")); + + Ebean.save(person1); + + LoggedSqlCollector.current(); + + List found = + Ebean.find(EcbmPerson.class).where() + .startsWith("name", "Fiona640") + .order().asc("id") + .findList(); + + Map phoneNumbers0 = found.get(0).getPhoneNumbers(); + Map phoneNumbers1 = found.get(1).getPhoneNumbers(); + phoneNumbers0.size(); + + assertThat(phoneNumbers0.toString()).contains("64-021-1234", "64-021-4321"); + assertThat(phoneNumbers1.toString()).contains("64-09-1234", "61-09-4321"); + + List found2 = + Ebean.find(EcbmPerson.class) + .fetch("phoneNumbers") + .where() + .startsWith("name", "Fiona640") + .order().asc("id") + .findList(); + + assertThat(found2).hasSize(2); + EcbmPerson foundFirst = found2.get(0); + + LoggedSqlCollector.current(); + + jsonToFrom(foundFirst); + + updateBasic(foundFirst); + + LoggedSqlCollector.stop(); + } + + private void updateBasic(EcbmPerson bean) { + + bean.setName("Fiona64-mod-0"); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ecbm_person"); + + updateBoth(bean); + } + + private void updateBoth(EcbmPerson bean) { + + bean.setName("Fiona64-mod-both"); + bean.getPhoneNumbers().put("more", new EcPhone("01", "234", "123")); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecbm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,key,country_code,area,number)"); + + updateNothing(bean); + } + + private void updateNothing(EcbmPerson bean) { + + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(0); + + updateOnlyCollection(bean); + } + + private void updateOnlyCollection(EcbmPerson bean) { + + bean.getPhoneNumbers().put("other", new EcPhone("01", "12", "4321")); + Ebean.save(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,key,country_code,area,number) values (?,?,?,?,?)"); + + delete(bean); + } + + private void delete(EcbmPerson bean) { + + Ebean.delete(bean); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id = ?"); + assertThat(sql.get(1)).contains("delete from ecbm_person where id=? and version=?"); + } + + private void jsonToFrom(EcbmPerson foundFirst) { + String asJson = Ebean.json().toJson(foundFirst); + + EcbmPerson fromJson = Ebean.json().toBean(EcbmPerson.class, asJson); + + String phoneString = fromJson.getPhoneNumbers().toString(); + assertThat(phoneString).contains("64-021-1234"); + assertThat(phoneString).contains("64-021-4321"); + } + +} From 07946cd5051508022e5b6b040b785a0690637cbe Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 28 Mar 2018 17:31:53 +1300 Subject: [PATCH 0209/1036] #115 - Mapping - Add support for @ElementCollection enhancement Add element collection notification - combine into preUpdate/postUpdate of the bean --- .../server/core/PersistRequestBean.java | 50 +++++++++++- .../deploy/BeanLifecycleAdapterFactory.java | 3 - .../server/persist/DefaultPersister.java | 7 +- .../persist/SaveManyElementCollection.java | 5 +- .../persist/SaveManyElementCollectionMap.java | 6 +- .../EcPersonPersistAdapter.java | 58 ++++++++++++++ .../TestElementCollectionBasic.java | 77 +++++++++++++++++++ 7 files changed, 193 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/tests/model/elementcollection/EcPersonPersistAdapter.java diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 33f72c636..283d426bd 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -154,6 +154,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private boolean getterCallback; + /** + * postUpdate notifications. Used to combine bean and element update updates into single postUpdate event. + */ + private int pendingPostUpdateNotify; + public PersistRequestBean(SpiEbeanServer server, T bean, Object parentBean, BeanManager mgr, SpiTransaction t, PersistExecute persistExecute, PersistRequest.Type type, int flags) { @@ -337,11 +342,16 @@ public final class PersistRequestBean extends PersistRequest implements BeanP @Override public void preGetterTrigger(int propertyIndex) { - if (propertyIndex < 0 || beanDescriptor.isGeneratedProperty(propertyIndex)) { + if (flushBatchOnGetter(propertyIndex)) { transaction.flushBatch(); } } + private boolean flushBatchOnGetter(int propertyIndex) { + // propertyIndex of -1 the Id property, no flush for get Id on UPDATE + return propertyIndex == -1 ? type == Type.INSERT : beanDescriptor.isGeneratedProperty(propertyIndex); + } + public void setSkipBatchForTopLevel() { skipBatchForTopLevel = true; } @@ -858,6 +868,16 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } } + private void postUpdateNotify() { + if (pendingPostUpdateNotify > 0) { + // invoke the delayed postUpdate notification (combined with element collection update) + controller.postUpdate(this); + } else { + // batched update with no element collection, send postUpdate notification once it executes + pendingPostUpdateNotify = -1; + } + } + /** * Aggressive L1 and L2 cache cleanup for deletes. */ @@ -905,13 +925,38 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } } + /** + * Ensure the preUpdate event fires (for case where only element collection has changed). + */ + public void preElementCollectionUpdate() { + if (controller != null && !dirty) { + // fire preUpdate notification when only element collection updated + controller.preUpdate(this); + } + } + + /** + * Combine with the beans postUpdate event notification. + */ + public void postElementCollectionUpdate() { + if (controller != null) { + pendingPostUpdateNotify += 2; + } + } + private void controllerPost() { switch (type) { case INSERT: controller.postInsert(this); break; case UPDATE: - controller.postUpdate(this); + if (pendingPostUpdateNotify == -1) { + // notify now - batched bean update with no element collection + controller.postUpdate(this); + } else { + // delay notify to combine with element collection update + pendingPostUpdateNotify++; + } break; case SOFT_DELETE: controller.postSoftDelete(this); @@ -1031,6 +1076,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP setNotifyCache(); addEvent(); } + postUpdateNotify(); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java index ae6e670f0..f9bdcd224 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanLifecycleAdapterFactory.java @@ -102,7 +102,6 @@ class BeanLifecycleAdapterFactory { postInserts.add(method); hasPersistMethods = true; } - if (method.isAnnotationPresent(PreUpdate.class)) { preUpdates.add(method); hasPersistMethods = true; @@ -111,7 +110,6 @@ class BeanLifecycleAdapterFactory { postUpdates.add(method); hasPersistMethods = true; } - if (method.isAnnotationPresent(PreRemove.class)) { preDeletes.add(method); hasPersistMethods = true; @@ -128,7 +126,6 @@ class BeanLifecycleAdapterFactory { postSoftDeletes.add(method); hasPersistMethods = true; } - if (method.isAnnotationPresent(PostLoad.class)) { postLoads.add(method); } diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index b16a0ced8..c3cb2dcda 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -510,11 +510,8 @@ public final class DefaultPersister implements Persister { if (request.isDirty()) { request.executeOrQueue(); - } else { - // skip validation on unchanged bean - if (logger.isDebugEnabled()) { - logger.debug(Message.msg("persist.update.skipped", request.getBean())); - } + } else if (logger.isDebugEnabled()) { + logger.debug(Message.msg("persist.update.skipped", request.getBean())); } if (request.isPersistCascade()) { diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java index 1867421fa..402a5e80a 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java @@ -27,10 +27,10 @@ class SaveManyElementCollection extends SaveManyBase { } Object parentId = request.getBeanId(); - SpiEbeanServer server = request.getServer(); if (!insertedParent) { + request.preElementCollectionUpdate(); SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); server.execute(sqlDelete, transaction); } @@ -49,5 +49,8 @@ class SaveManyElementCollection extends SaveManyBase { transaction.depth(-1); resetModifyState(); + if (!insertedParent) { + request.postElementCollectionUpdate(); + } } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java index 3ba94d781..e19b7e314 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java @@ -29,10 +29,9 @@ class SaveManyElementCollectionMap extends SaveManyBase { } Object parentId = request.getBeanId(); - SpiEbeanServer server = request.getServer(); - if (!insertedParent) { + request.preElementCollectionUpdate(); SqlUpdate sqlDelete = many.deleteByParentId(parentId, null); server.execute(sqlDelete, transaction); } @@ -51,5 +50,8 @@ class SaveManyElementCollectionMap extends SaveManyBase { transaction.depth(-1); resetModifyState(); + if (!insertedParent) { + request.postElementCollectionUpdate(); + } } } diff --git a/src/test/java/org/tests/model/elementcollection/EcPersonPersistAdapter.java b/src/test/java/org/tests/model/elementcollection/EcPersonPersistAdapter.java new file mode 100644 index 000000000..02dd4c191 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/EcPersonPersistAdapter.java @@ -0,0 +1,58 @@ +package org.tests.model.elementcollection; + +import io.ebean.event.BeanPersistAdapter; +import io.ebean.event.BeanPersistRequest; + +import java.util.ArrayList; +import java.util.List; + +public class EcPersonPersistAdapter extends BeanPersistAdapter { + + private static List LOG = new ArrayList<>(); + + static List eventLog() { + List copy = new ArrayList(LOG); + LOG.clear(); + return copy; + } + + @Override + public boolean isRegisterFor(Class cls) { + return cls.equals(EcPerson.class); + } + + + @Override + public boolean preInsert(BeanPersistRequest request) { + LOG.add("preInsert"); + return true; + } + + @Override + public void postInsert(BeanPersistRequest request) { + LOG.add("postInsert"); + } + + @Override + public boolean preUpdate(BeanPersistRequest request) { + LOG.add("preUpdate"); + return true; + } + + @Override + public void postUpdate(BeanPersistRequest request) { + LOG.add("postUpdate"); + } + + @Override + public boolean preDelete(BeanPersistRequest request) { + LOG.add("preDelete"); + return true; + } + + @Override + public void postDelete(BeanPersistRequest request) { + LOG.add("postDelete"); + } + +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java index b55b3dba2..0dea97952 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -2,6 +2,7 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.Transaction; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -11,6 +12,10 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestElementCollectionBasic extends BaseTestCase { + private List eventLog() { + return EcPersonPersistAdapter.eventLog(); + } + @Test public void test() { @@ -21,6 +26,8 @@ public class TestElementCollectionBasic extends BaseTestCase { person.getPhoneNumbers().add("021 4321"); Ebean.save(person); + assertThat(eventLog()).containsExactly("preInsert", "postInsert"); + List sql = LoggedSqlCollector.current(); assertThat(sql).hasSize(2); assertThat(sql.get(0)).contains("insert into ec_person"); @@ -31,6 +38,8 @@ public class TestElementCollectionBasic extends BaseTestCase { person1.getPhoneNumbers().add("09 4321"); Ebean.save(person1); + assertThat(eventLog()).containsExactly("preInsert", "postInsert"); + LoggedSqlCollector.current(); List found = @@ -82,6 +91,26 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(sql).hasSize(1); assertThat(sql.get(0)).contains("update ec_person"); + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + + updateBasicInBatch(bean); + } + + private void updateBasicInBatch(EcPerson bean) { + + try (Transaction txn = Ebean.beginTransaction()) { + txn.setBatchMode(true); + bean.setName("Fiona021-mod-0-batch"); + Ebean.save(bean); + txn.commit(); + } + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ec_person"); + + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + updateBoth(bean); } @@ -97,6 +126,29 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + + updateBothInBatch(bean); + } + + private void updateBothInBatch(EcPerson bean) { + + try (Transaction txn = Ebean.beginTransaction()) { + txn.setBatchMode(true); + bean.setName("Fiona021-mod-both-batch"); + bean.getPhoneNumbers().add("01-22123"); + Ebean.save(bean); + txn.commit(); + } + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ec_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + updateNothing(bean); } @@ -107,6 +159,27 @@ public class TestElementCollectionBasic extends BaseTestCase { List sql = LoggedSqlCollector.current(); assertThat(sql).hasSize(0); + assertThat(eventLog()).isEmpty(); + + updateOnlyCollectionInBatch(bean); + } + + private void updateOnlyCollectionInBatch(EcPerson bean) { + + try (Transaction txn = Ebean.beginTransaction()) { + txn.setBatchMode(true); + bean.getPhoneNumbers().add("01-4321"); + Ebean.save(bean); + txn.commit(); + } + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + updateOnlyCollection(bean); } @@ -120,6 +193,8 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); + delete(bean); } @@ -131,6 +206,8 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(sql).hasSize(2); assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id = ?"); assertThat(sql.get(1)).contains("delete from ec_person where id=? and version=?"); + + assertThat(eventLog()).containsExactly("preDelete", "postDelete"); } private void jsonToFrom(EcPerson foundFirst) { From acd5578d8a980e6d661c5cbabd7d1aa5ffbac700 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 01:15:58 +1300 Subject: [PATCH 0210/1036] #115 - Mapping - Add support for @ElementCollection enhancement Add element collection L2 cache support --- .../ebean/common/AbstractBeanCollection.java | 2 +- .../io/ebeaninternal/api/SpiJsonContext.java | 10 ++- .../ebeaninternal/api/json/SpiJsonReader.java | 36 ++++++++ .../text => api}/json/SpiJsonWriter.java | 10 ++- .../server/cache/CachedBeanDataFromBean.java | 7 ++ .../server/cache/CachedBeanDataToBean.java | 12 +-- .../server/core/PersistRequestBean.java | 65 ++++++++++++-- .../server/deploy/BaseCollectionHelp.java | 2 +- .../server/deploy/BeanChangeJson.java | 6 +- .../server/deploy/BeanCollectionHelp.java | 2 +- .../server/deploy/BeanDescriptor.java | 20 +++-- .../deploy/BeanDescriptorCacheHelp.java | 67 +++++++------- .../deploy/BeanDescriptorElementEmbedded.java | 8 +- .../BeanDescriptorElementEmbeddedMap.java | 6 +- .../deploy/BeanDescriptorElementScalar.java | 6 +- .../BeanDescriptorElementScalarMap.java | 6 +- .../server/deploy/BeanDescriptorJsonHelp.java | 10 +-- .../server/deploy/BeanListHelp.java | 2 +- .../server/deploy/BeanListHelpElement.java | 2 +- .../server/deploy/BeanMapHelp.java | 2 +- .../server/deploy/BeanMapHelpElement.java | 2 +- .../server/deploy/BeanProperty.java | 6 +- .../server/deploy/BeanPropertyAssocMany.java | 73 +++++++++++++-- .../deploy/BeanPropertyAssocManyJsonHelp.java | 6 +- .../BeanPropertyAssocManyJsonTransient.java | 4 +- .../server/deploy/BeanPropertyAssocOne.java | 6 +- .../deploy/BeanPropertySimpleCollection.java | 4 +- .../server/deploy/BeanSetHelp.java | 2 +- .../server/deploy/BeanSetHelpElement.java | 2 +- .../server/deploy/ElementHelpList.java | 7 +- .../server/deploy/ElementHelpMap.java | 7 +- .../server/deploy/ElementHelpSet.java | 7 +- .../deploy/parse/AnnotationAssocManys.java | 2 +- .../server/persist/SaveManyBase.java | 19 ++++ .../persist/SaveManyElementCollection.java | 4 +- .../persist/SaveManyElementCollectionMap.java | 4 +- .../server/text/json/DJsonBeanReader.java | 7 +- .../server/text/json/DJsonContext.java | 20 +++-- .../server/text/json/ReadJson.java | 22 +++-- .../server/text/json/WriteJson.java | 10 ++- .../deploy/TestDiffHelpInsertSimple.java | 4 +- .../TestDiffHelpInsertWithEmbedded.java | 4 +- .../model/elementcollection/EcPerson.java | 3 + .../model/elementcollection/EcblPerson.java | 3 + .../model/elementcollection/EcbmPerson.java | 4 +- .../model/elementcollection/EcmPerson.java | 3 + .../TestElementCollectionBasicCache.java | 80 +++++++++++++++++ .../TestElementCollectionBasicMapCache.java | 85 ++++++++++++++++++ ...estElementCollectionEmbeddedListCache.java | 88 ++++++++++++++++++ .../TestElementCollectionEmbeddedMap.java | 4 +- ...TestElementCollectionEmbeddedMapCache.java | 89 +++++++++++++++++++ .../json/TestJsonBeanDescriptorParse.java | 7 +- 52 files changed, 734 insertions(+), 135 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/api/json/SpiJsonReader.java rename src/main/java/io/ebeaninternal/{server/text => api}/json/SpiJsonWriter.java (90%) create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java create mode 100644 src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java diff --git a/src/main/java/io/ebean/common/AbstractBeanCollection.java b/src/main/java/io/ebean/common/AbstractBeanCollection.java index ca5493d2a..33b30f3ac 100644 --- a/src/main/java/io/ebean/common/AbstractBeanCollection.java +++ b/src/main/java/io/ebean/common/AbstractBeanCollection.java @@ -63,7 +63,7 @@ abstract class AbstractBeanCollection implements BeanCollection { this.ebeanServerName = loader.getName(); this.ownerBean = ownerBean; this.propertyName = propertyName; - this.readOnly = ownerBean._ebean_getIntercept().isReadOnly(); + this.readOnly = ownerBean != null && ownerBean._ebean_getIntercept().isReadOnly(); } @Override diff --git a/src/main/java/io/ebeaninternal/api/SpiJsonContext.java b/src/main/java/io/ebeaninternal/api/SpiJsonContext.java index 4be1a3034..2700ed60e 100644 --- a/src/main/java/io/ebeaninternal/api/SpiJsonContext.java +++ b/src/main/java/io/ebeaninternal/api/SpiJsonContext.java @@ -1,9 +1,11 @@ package io.ebeaninternal.api; import com.fasterxml.jackson.core.JsonGenerator; +import io.ebean.plugin.BeanType; import io.ebean.text.json.JsonContext; import io.ebean.text.json.JsonWriteOptions; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.Writer; @@ -21,4 +23,10 @@ public interface SpiJsonContext extends JsonContext { * Create a Json Writer for writing beans as JSON supplying a writer. */ SpiJsonWriter createJsonWriter(Writer writer); + + /** + * Create a Json Reader for reading the JSON content. + */ + SpiJsonReader createJsonRead(BeanType beanType, String json); + } diff --git a/src/main/java/io/ebeaninternal/api/json/SpiJsonReader.java b/src/main/java/io/ebeaninternal/api/json/SpiJsonReader.java new file mode 100644 index 000000000..aaf4e2ce8 --- /dev/null +++ b/src/main/java/io/ebeaninternal/api/json/SpiJsonReader.java @@ -0,0 +1,36 @@ +package io.ebeaninternal.api.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.ebean.bean.EntityBean; +import io.ebean.bean.PersistenceContext; +import io.ebeaninternal.server.deploy.BeanDescriptor; + +import java.io.IOException; +import java.util.Map; + +public interface SpiJsonReader { + + PersistenceContext getPersistenceContext(); + + SpiJsonReader forJson(JsonParser moreJson, boolean resetContext); + + void persistenceContextPut(Object beanId, T currentBean); + + Object persistenceContextPutIfAbsent(Object id, EntityBean bean, BeanDescriptor beanDesc); + + ObjectMapper getObjectMapper(); + + JsonParser getParser(); + + JsonToken nextToken() throws IOException; + + void pushPath(String path); + + void popPath(); + + void beanVisitor(Object bean, Map unmappedProperties); + + Object readValueUsingObjectMapper(Class propertyType) throws IOException; +} diff --git a/src/main/java/io/ebeaninternal/server/text/json/SpiJsonWriter.java b/src/main/java/io/ebeaninternal/api/json/SpiJsonWriter.java similarity index 90% rename from src/main/java/io/ebeaninternal/server/text/json/SpiJsonWriter.java rename to src/main/java/io/ebeaninternal/api/json/SpiJsonWriter.java index ebcb88379..4fd44f183 100644 --- a/src/main/java/io/ebeaninternal/server/text/json/SpiJsonWriter.java +++ b/src/main/java/io/ebeaninternal/api/json/SpiJsonWriter.java @@ -1,9 +1,10 @@ -package io.ebeaninternal.server.text.json; +package io.ebeaninternal.api.json; import io.ebean.bean.EntityBean; import io.ebean.text.json.JsonWriter; import io.ebeaninternal.server.deploy.BeanDescriptor; +import java.io.IOException; import java.util.Collection; /** @@ -11,6 +12,11 @@ import java.util.Collection; */ public interface SpiJsonWriter extends JsonWriter { + /** + * Flush the buffer. + */ + void flush() throws IOException; + /** * Return true if the value is a parent bean. */ @@ -60,7 +66,7 @@ public interface SpiJsonWriter extends JsonWriter { * Write value using underlying Jaskson object mapper if available. */ void writeValueUsingObjectMapper(String name, Object value); - + /** * Write the bean properties. */ diff --git a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataFromBean.java b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataFromBean.java index 1de76f18a..e894a8710 100644 --- a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataFromBean.java +++ b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataFromBean.java @@ -4,6 +4,7 @@ import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBeanIntercept; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; +import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import java.util.LinkedHashMap; import java.util.Map; @@ -33,6 +34,12 @@ public class CachedBeanDataFromBean { } } + for (BeanPropertyAssocMany prop : desc.propertiesMany()) { + if (prop.isElementCollection()) { + data.put(prop.getName(), prop.getCacheDataValue(bean)); + } + } + long version = desc.getVersion(bean); EntityBean sharableBean = createSharableBean(desc, bean, ebi); return new CachedBeanData(sharableBean, desc.getDiscValue(), data, version); diff --git a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java index beee32400..05b2a0d1f 100644 --- a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java +++ b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java @@ -21,14 +21,16 @@ public class CachedBeanDataToBean { } // load the non-many properties - BeanProperty[] props = desc.propertiesNonMany(); - for (BeanProperty prop : props) { + for (BeanProperty prop : desc.propertiesNonMany()) { loadProperty(bean, cacheBeanData, ebi, prop, context); } - BeanPropertyAssocMany[] many = desc.propertiesMany(); - for (BeanPropertyAssocMany aMany : many) { - aMany.createReferenceIfNull(bean); + for (BeanPropertyAssocMany prop : desc.propertiesMany()) { + if (prop.isElementCollection()) { + loadProperty(bean, cacheBeanData, ebi, prop, context); + } else { + prop.createReferenceIfNull(bean); + } } ebi.setLoadedLazy(); diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 283d426bd..07618f6b9 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -35,6 +35,7 @@ import javax.persistence.PersistenceException; import java.io.IOException; import java.sql.Statement; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -107,6 +108,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private boolean updatedManysOnly; + /** + * Element collection change as part of bean cache. + */ + private Map collectionChanges; + /** * Many properties that were cascade saved (and hence might need caches updated later). */ @@ -938,10 +944,14 @@ public final class PersistRequestBean extends PersistRequest implements BeanP /** * Combine with the beans postUpdate event notification. */ - public void postElementCollectionUpdate() { + public boolean postElementCollectionUpdate() { if (controller != null) { pendingPostUpdateNotify += 2; } + if (!dirty) { + setNotifyCache(); + } + return notifyCache; } private void controllerPost() { @@ -1079,13 +1089,6 @@ public final class PersistRequestBean extends PersistRequest implements BeanP postUpdateNotify(); } - /** - * Return true if only many properties where updated. - */ - public boolean isUpdatedManysOnly() { - return updatedManysOnly; - } - /** * For requests that update document store add this event to either the list * of queue events or list of update events. @@ -1311,4 +1314,50 @@ public final class PersistRequestBean extends PersistRequest implements BeanP public boolean isInsertedParent() { return Flags.isInsert(flags); } + + /** + * Add an element collection change to L2 bean cache update. + */ + public void addCollectionChange(String name, Object value) { + if (collectionChanges == null) { + collectionChanges = new LinkedHashMap<>(); + } + collectionChanges.put(name, value); + } + + /** + * Build the bean update for the L2 cache. + */ + public void addBeanUpdate(CacheChangeSet changeSet) { + + if (!updatedManysOnly || collectionChanges != null) { + + boolean updateNaturalKey = false; + + Map changes = new LinkedHashMap<>(); + EntityBean bean = getEntityBean(); + boolean[] dirtyProperties = getDirtyProperties(); + if (dirtyProperties != null) { + for (int i = 0; i < dirtyProperties.length; i++) { + if (dirtyProperties[i]) { + BeanProperty property = beanDescriptor.propertyByIndex(i); + if (property.isCacheDataInclude()) { + Object val = property.getCacheDataValue(bean); + changes.put(property.getName(), val); + if (property.isNaturalKey()) { + updateNaturalKey = true; + changeSet.addNaturalKeyPut(beanDescriptor, idValue, val); + } + } + } + } + } + if (collectionChanges != null) { + // add element collection update + changes.putAll(collectionChanges); + } + + changeSet.addBeanUpdate(beanDescriptor, idValue, changes, updateNaturalKey, getVersion()); + } + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java index 4d8dbda97..576d9a12b 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BaseCollectionHelp.java @@ -3,7 +3,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.IOException; import java.util.Collection; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanChangeJson.java b/src/main/java/io/ebeaninternal/server/deploy/BeanChangeJson.java index ae77429a0..e2a6938ff 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanChangeJson.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanChangeJson.java @@ -2,7 +2,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.PersistenceIOException; import io.ebean.bean.BeanDiffVisitor; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.util.ArrayStack; import java.io.IOException; @@ -82,10 +82,10 @@ class BeanChangeJson implements BeanDiffVisitor { void flush() { try { newJson.writeEndObject(); - newJson.gen().flush(); + newJson.flush(); if (oldJson != null) { oldJson.writeEndObject(); - oldJson.gen().flush(); + oldJson.flush(); } } catch (IOException e) { throw new PersistenceIOException(e); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java index 569e22403..ede034939 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanCollectionHelp.java @@ -7,8 +7,8 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.query.CQueryCollectionAdd; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; import java.util.Collection; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 620b6e1fd..1bc379e7e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -41,6 +41,8 @@ import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.api.SpiUpdatePlan; import io.ebeaninternal.api.TransactionEventTable.TableIUD; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.cache.CachedBeanData; import io.ebeaninternal.server.cache.CachedManyIds; @@ -71,8 +73,6 @@ import io.ebeaninternal.server.query.STreeType; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.rawsql.SpiRawSql; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.DataBind; import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.util.SortByClause; @@ -662,6 +662,10 @@ public class BeanDescriptor implements BeanType, STreeType { return properties; } + public BeanProperty propertyByIndex(int pos) { + return propertiesIndex[pos]; + } + /** * Initialise the Id properties first. *

    @@ -945,7 +949,7 @@ public class BeanDescriptor implements BeanType, STreeType { SpiJsonWriter jsonWriter = createJsonWriter(writer); jsonWriteForInsert(jsonWriter, request.getEntityBean()); - jsonWriter.gen().flush(); + jsonWriter.flush(); return beanChange(ChangeType.INSERT, request.getBeanId(), writer.toString(), null); @@ -959,6 +963,10 @@ public class BeanDescriptor implements BeanType, STreeType { return ebeanServer.jsonExtended().createJsonWriter(writer); } + SpiJsonReader createJsonReader(String json) { + return ebeanServer.jsonExtended().createJsonRead(this, json); + } + /** * Populate the diff for inserts with flattened non-null property values. */ @@ -3355,7 +3363,7 @@ public class BeanDescriptor implements BeanType, STreeType { throw new IllegalStateException("Unexpected - expect Element override"); } - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { throw new IllegalStateException("Unexpected - expect Element override"); } @@ -3371,11 +3379,11 @@ public class BeanDescriptor implements BeanType, STreeType { jsonHelp.jsonWriteProperties(writeJson, bean); } - public T jsonRead(ReadJson jsonRead, String path) throws IOException { + public T jsonRead(SpiJsonReader jsonRead, String path) throws IOException { return jsonHelp.jsonRead(jsonRead, path); } - protected T jsonReadObject(ReadJson jsonRead, String path) throws IOException { + protected T jsonReadObject(SpiJsonReader jsonRead, String path) throws IOException { return jsonHelp.jsonReadObject(jsonRead, path); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java index ac131a884..51d6b9fbf 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java @@ -20,6 +20,7 @@ import io.ebeaninternal.server.transaction.DefaultPersistenceContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -272,6 +273,11 @@ final class BeanDescriptorCacheHelp { */ boolean manyPropLoad(BeanPropertyAssocMany many, BeanCollection bc, Object parentId, Boolean readOnly) { + if (many.isElementCollection()) { + // held as part of the bean cache so skip + return false; + } + CachedManyIds entry = manyPropGet(parentId, many.getName()); if (entry == null) { // not in cache so return unsuccessful @@ -298,9 +304,29 @@ final class BeanDescriptorCacheHelp { */ void manyPropPut(BeanPropertyAssocMany many, Object details, Object parentId) { - CachedManyIds entry = createManyIds(many, details); - if (entry != null) { - cachePutManyIds(parentId, many.getName(), entry); + if (many.isElementCollection()) { + CachedBeanData data = (CachedBeanData) beanCache.get(parentId); + if (data != null) { + try { + // add as JSON to bean cache + String asJson = many.jsonWriteCollection(details); + Map changes = new HashMap<>(); + changes.put(many.getName(), asJson); + + CachedBeanData newData = data.update(changes, data.getVersion()); + if (beanLog.isDebugEnabled()) { + beanLog.debug(" UPDATE {}({}) changes:{}", cacheName, parentId, changes); + } + beanCache.put(parentId, newData); + } catch (IOException e) { + logger.error("Error updating L2 cache", e); + } + } + } else { + CachedManyIds entry = createManyIds(many, details); + if (entry != null) { + cachePutManyIds(parentId, many.getName(), entry); + } } } @@ -730,38 +756,17 @@ final class BeanDescriptorCacheHelp { List> manyCollections = updateRequest.getUpdatedManyCollections(); if (manyCollections != null) { for (BeanPropertyAssocMany many : manyCollections) { - Object details = many.getValue(updateRequest.getEntityBean()); - CachedManyIds entry = createManyIds(many, details); - if (entry != null) { - changeSet.addManyPut(desc, many.getName(), id, entry); - } - } - } - - // check if the bean itself was updated - if (!updateRequest.isUpdatedManysOnly()) { - - boolean updateNaturalKey = false; - - Map changes = new LinkedHashMap<>(); - EntityBean bean = updateRequest.getEntityBean(); - boolean[] dirtyProperties = updateRequest.getDirtyProperties(); - for (int i = 0; i < dirtyProperties.length; i++) { - if (dirtyProperties[i]) { - BeanProperty property = desc.propertiesIndex[i]; - if (property.isCacheDataInclude()) { - Object val = property.getCacheDataValue(bean); - changes.put(property.getName(), val); - if (property.isNaturalKey()) { - updateNaturalKey = true; - changeSet.addNaturalKeyPut(desc, id, val); - } + if (!many.isElementCollection()) { + Object details = many.getValue(updateRequest.getEntityBean()); + CachedManyIds entry = createManyIds(many, details); + if (entry != null) { + changeSet.addManyPut(desc, many.getName(), id, entry); } } } - - changeSet.addBeanUpdate(desc, id, changes, updateNaturalKey, updateRequest.getVersion()); } + + updateRequest.addBeanUpdate(changeSet); } /** diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java index cb17a9492..6d24e4569 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbedded.java @@ -3,9 +3,9 @@ package io.ebeaninternal.server.deploy; import io.ebean.PersistenceIOException; import io.ebean.SqlUpdate; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import java.io.IOException; @@ -56,12 +56,12 @@ class BeanDescriptorElementEmbedded extends BeanDescriptorElement { } @Override - public T jsonRead(ReadJson jsonRead, String path) throws IOException { + public T jsonRead(SpiJsonReader jsonRead, String path) throws IOException { return readJsonElement(jsonRead, path); } @SuppressWarnings("unchecked") - T readJsonElement(ReadJson jsonRead, String path) throws IOException { + T readJsonElement(SpiJsonReader jsonRead, String path) throws IOException { return (T)targetDescriptor.jsonRead(jsonRead, path); } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java index 49b85d699..c30ff9a33 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementEmbeddedMap.java @@ -3,9 +3,9 @@ package io.ebeaninternal.server.deploy; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.ScalarType; import java.io.IOException; @@ -47,7 +47,7 @@ class BeanDescriptorElementEmbeddedMap extends BeanDescriptorElementEmbedded< } @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { JsonParser parser = readJson.getParser(); ElementCollector add = elementHelp.createCollector(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java index 1b7ac70ea..236d664d3 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalar.java @@ -5,9 +5,9 @@ import com.fasterxml.jackson.core.JsonToken; import io.ebean.PersistenceIOException; import io.ebean.SqlUpdate; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.ScalarType; import java.io.IOException; @@ -38,7 +38,7 @@ class BeanDescriptorElementScalar extends BeanDescriptorElement { } @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { JsonParser parser = readJson.getParser(); ElementCollector add = elementHelp.createCollector(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java index 9eb87ba0b..96cb172f0 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorElementScalarMap.java @@ -3,9 +3,9 @@ package io.ebeaninternal.server.deploy; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.ScalarType; import java.io.IOException; @@ -51,7 +51,7 @@ class BeanDescriptorElementScalarMap extends BeanDescriptorElement { } @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { JsonParser parser = readJson.getParser(); ElementCollector add = elementHelp.createCollector(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java index 8d90a3af5..ca895e92a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorJsonHelp.java @@ -5,8 +5,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import io.ebean.bean.EntityBean; import io.ebean.text.json.EJson; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.IOException; import java.util.LinkedHashMap; @@ -70,7 +70,7 @@ public class BeanDescriptorJsonHelp { } @SuppressWarnings("unchecked") - public T jsonRead(ReadJson jsonRead, String path) throws IOException { + public T jsonRead(SpiJsonReader jsonRead, String path) throws IOException { JsonParser parser = jsonRead.getParser(); //noinspection StatementWithEmptyBody @@ -116,14 +116,14 @@ public class BeanDescriptorJsonHelp { return (T) inheritInfo.readType(discValue).desc().jsonReadObject(jsonRead, path); } - protected T jsonReadObject(ReadJson readJson, String path) throws IOException { + protected T jsonReadObject(SpiJsonReader readJson, String path) throws IOException { EntityBean bean = desc.createEntityBeanForJson(); return jsonReadProperties(readJson, bean, path); } @SuppressWarnings("unchecked") - protected T jsonReadProperties(ReadJson readJson, EntityBean bean, String path) throws IOException { + protected T jsonReadProperties(SpiJsonReader readJson, EntityBean bean, String path) throws IOException { if (path != null) { readJson.pushPath(path); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java index 338bfb5a9..9b751a16e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelp.java @@ -7,7 +7,7 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.EntityBean; import io.ebean.common.BeanList; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java index 8191bd0c6..0e473e4eb 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanListHelpElement.java @@ -2,7 +2,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; /** * Helper for element collection List. diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java index b45bbc98b..72feb6d80 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelp.java @@ -7,7 +7,7 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.EntityBean; import io.ebean.common.BeanMap; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.IOException; import java.util.LinkedHashMap; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java index 0531839e0..71cdfb3fa 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanMapHelpElement.java @@ -3,7 +3,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; import io.ebean.common.BeanMap; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; public class BeanMapHelpElement extends BeanMapHelp { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 5ea987763..8fa2b9af8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -13,6 +13,8 @@ import io.ebean.util.SplitName; import io.ebean.util.StringHelper; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.core.InternString; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedWhenCreated; @@ -25,8 +27,6 @@ import io.ebeaninternal.server.properties.BeanPropertySetter; import io.ebeaninternal.server.query.STreeProperty; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.DataBind; import io.ebeaninternal.server.type.ScalarType; import io.ebeaninternal.server.type.ScalarTypeBoolean; @@ -1453,7 +1453,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { } } - public void jsonRead(ReadJson ctx, EntityBean bean) throws IOException { + public void jsonRead(SpiJsonReader ctx, EntityBean bean) throws IOException { JsonToken event = ctx.nextToken(); if (JsonToken.VALUE_NULL == event) { diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 2ef769116..d3c3e8e8f 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -1,5 +1,7 @@ package io.ebeaninternal.server.deploy; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; import io.ebean.SqlUpdate; import io.ebean.Transaction; import io.ebean.bean.BeanCollection; @@ -7,22 +9,24 @@ import io.ebean.bean.BeanCollection.ModifyListenMode; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.BeanCollectionLoader; import io.ebean.bean.EntityBean; +import io.ebean.bean.PersistenceContext; import io.ebean.text.PathProperties; import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.id.ImportedId; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany; import io.ebeaninternal.server.el.ElPropertyChainBuilder; import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.query.STreePropertyAssocMany; import io.ebeaninternal.server.query.SqlBeanLoad; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.persistence.PersistenceException; import java.io.IOException; +import java.io.StringWriter; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @@ -804,7 +808,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST if (value != null) { ctx.pushParentBeanMany(bean); if (help != null) { - help.jsonWrite(ctx, name, value, include != null); + jsonWriteCollection(ctx, name, value, include != null); } else { if (isTransient && targetDescriptor == null) { ctx.writeValueUsingObjectMapper(name, value); @@ -820,7 +824,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST } @Override - public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException { + public void jsonRead(SpiJsonReader readJson, EntityBean parentBean) throws IOException { jsonHelp.jsonRead(readJson, parentBean); } @@ -909,10 +913,69 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST elementDescriptor.jsonWriteElement(ctx, element); } + /** + * A Many (element collection) property in bean cache to held as JSON. + */ + @Override + public void setCacheDataValue(EntityBean bean, Object cacheData, PersistenceContext context) { + try { + String asJson = (String) cacheData; + Object collection = jsonReadCollection(asJson); + setValue(bean, collection); + } catch (Exception e) { + logger.error("Error setting value from L2 cache", e); + } + } + + @Override + public Object getCacheDataValue(EntityBean bean) { + try { + Object collection = getValue(bean); + if (collection == null) { + return null; + } + return jsonWriteCollection(collection); + } catch (Exception e) { + logger.error("Error building value element collection json for L2 cache", e); + return null; + } + } + + /** + * Write the collection to JSON. + */ + public String jsonWriteCollection(Object value) throws IOException { + StringWriter writer = new StringWriter(300); + SpiJsonWriter ctx = descriptor.createJsonWriter(writer); + help.jsonWrite(ctx, null, value, false); + ctx.flush(); + return writer.toString(); + } + + /** + * Read the collection as JSON. + */ + public Object jsonReadCollection(String json) throws IOException { + SpiJsonReader ctx = descriptor.createJsonReader(json); + JsonParser parser = ctx.getParser(); + JsonToken event = parser.nextToken(); + if (JsonToken.VALUE_NULL == event) { + return null; + } + return jsonReadCollection(ctx, null); + } + + /** + * Write the collection to JSON. + */ + public void jsonWriteCollection(SpiJsonWriter ctx, String name, Object value, boolean explicitInclude) throws IOException { + help.jsonWrite(ctx, name, value, explicitInclude); + } + /** * Read the collection (JSON Array) containing entity beans. */ - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { if (elementDescriptor != null && manyType.isMap()) { return elementDescriptor.jsonReadCollection(readJson, parentBean); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java index b4962a9e6..11b3f74bc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonHelp.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.api.json.SpiJsonReader; import java.io.IOException; @@ -35,7 +35,7 @@ class BeanPropertyAssocManyJsonHelp { /** * Read the JSON for this property. */ - public void jsonRead(ReadJson readJson, EntityBean parentBean) throws IOException { + public void jsonRead(SpiJsonReader readJson, EntityBean parentBean) throws IOException { if (!this.many.jsonDeserialize) { return; @@ -61,7 +61,7 @@ class BeanPropertyAssocManyJsonHelp { /** * Read a Transient property using Jackson ObjectMapper. */ - private void jsonReadTransientUsingObjectMapper(ReadJson readJson, EntityBean parentBean) throws IOException { + private void jsonReadTransientUsingObjectMapper(SpiJsonReader readJson, EntityBean parentBean) throws IOException { if (jsonTransient == null) { throw new IllegalStateException("Jackson ObjectMapper is required to read this Transient property " + many.getFullBeanName()); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java index fd1b9fe1d..5b05b3261 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyJsonTransient.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.databind.type.CollectionType; import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.text.json.ReadJson; +import io.ebeaninternal.api.json.SpiJsonReader; import java.io.IOException; import java.util.LinkedHashMap; @@ -19,7 +19,7 @@ class BeanPropertyAssocManyJsonTransient { /** * Use Jackson ObjectMapper to read the transient 'many' property. */ - void jsonReadUsingObjectMapper(BeanPropertyAssocMany many, ReadJson readJson, EntityBean parentBean) throws IOException { + void jsonReadUsingObjectMapper(BeanPropertyAssocMany many, SpiJsonReader readJson, EntityBean parentBean) throws IOException { ObjectMapper mapper = readJson.getObjectMapper(); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index c4f28fd60..4cea3315a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -9,6 +9,8 @@ import io.ebean.bean.EntityBean; import io.ebean.bean.PersistenceContext; import io.ebean.util.SplitName; import io.ebeaninternal.api.SpiQuery; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.cache.CacheChangeSet; import io.ebeaninternal.server.cache.CachedBeanData; import io.ebeaninternal.server.core.DefaultSqlUpdate; @@ -19,8 +21,6 @@ import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.query.STreePropertyAssocOne; import io.ebeaninternal.server.query.SqlBeanLoad; import io.ebeaninternal.server.query.SqlJoinType; -import io.ebeaninternal.server.text.json.ReadJson; -import io.ebeaninternal.server.text.json.SpiJsonWriter; import io.ebeaninternal.server.type.ScalarType; import javax.persistence.PersistenceException; @@ -740,7 +740,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr } @Override - public void jsonRead(ReadJson readJson, EntityBean bean) throws IOException { + public void jsonRead(SpiJsonReader readJson, EntityBean bean) throws IOException { if (jsonDeserialize && targetDescriptor != null) { T assocBean = targetDescriptor.jsonRead(readJson, name); setValue(bean, assocBean); diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java index f00b401cd..a66d996b1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertySimpleCollection.java @@ -2,8 +2,8 @@ package io.ebeaninternal.server.deploy; import io.ebean.SqlUpdate; import io.ebean.bean.EntityBean; +import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertySimpleCollection; -import io.ebeaninternal.server.text.json.ReadJson; import java.io.IOException; @@ -19,7 +19,7 @@ public class BeanPropertySimpleCollection extends BeanPropertyAssocMany { } @Override - public Object jsonReadCollection(ReadJson readJson, EntityBean parentBean) throws IOException { + public Object jsonReadCollection(SpiJsonReader readJson, EntityBean parentBean) throws IOException { return elementDescriptor.jsonReadCollection(readJson, parentBean); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java index 197cbae0a..482ccce62 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelp.java @@ -7,7 +7,7 @@ import io.ebean.bean.BeanCollection; import io.ebean.bean.BeanCollectionAdd; import io.ebean.bean.EntityBean; import io.ebean.common.BeanSet; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import java.io.IOException; import java.util.LinkedHashSet; diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java index c490c76e1..94ac9e5a5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanSetHelpElement.java @@ -2,7 +2,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; /** * Helper for element collection List. diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java index 6c95550da..8d23b23de 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpList.java @@ -1,5 +1,8 @@ package io.ebeaninternal.server.deploy; +import io.ebean.bean.BeanCollection; +import io.ebean.common.BeanList; + import java.util.ArrayList; import java.util.List; @@ -26,7 +29,9 @@ class ElementHelpList implements ElementHelp { @Override public Object collection() { - return list; + BeanList beanList = new BeanList<>(list); + beanList.setModifyListening(BeanCollection.ModifyListenMode.ALL); + return beanList; } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java index 2d970a48f..6436f6d53 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpMap.java @@ -1,5 +1,8 @@ package io.ebeaninternal.server.deploy; +import io.ebean.bean.BeanCollection; +import io.ebean.common.BeanMap; + import java.util.LinkedHashMap; import java.util.Map; @@ -26,7 +29,9 @@ class ElementHelpMap implements ElementHelp { @Override public Object collection() { - return map; + BeanMap beanMap = new BeanMap<>(map); + beanMap.setModifyListening(BeanCollection.ModifyListenMode.ALL); + return beanMap; } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java index 53a47de89..9f0e7602d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java +++ b/src/main/java/io/ebeaninternal/server/deploy/ElementHelpSet.java @@ -1,5 +1,8 @@ package io.ebeaninternal.server.deploy; +import io.ebean.bean.BeanCollection; +import io.ebean.common.BeanSet; + import java.util.LinkedHashSet; import java.util.Set; @@ -26,7 +29,9 @@ class ElementHelpSet implements ElementHelp { @Override public Object collection() { - return set; + BeanSet beanSet = new BeanSet<>(set); + beanSet.setModifyListening(BeanCollection.ModifyListenMode.ALL); + return beanSet; } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index 24f3c96aa..68d3171d4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -218,7 +218,7 @@ class AnnotationAssocManys extends AnnotationParser { elementDescriptor.setProperties(new String[]{"value"}); } else { elementDescriptor.setProperties(new String[]{"key", "value"}); - String dbKeyColumn = "key"; + String dbKeyColumn = "mkey"; MapKeyColumn mapKeyColumn = get(prop, MapKeyColumn.class); if (mapKeyColumn != null) { dbKeyColumn = mapKeyColumn.name(); diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java index 9f892c5e8..2c7bde442 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyBase.java @@ -6,12 +6,18 @@ import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.core.PersistRequestBean; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; /** * Base for saving entity bean collections and element collections. */ abstract class SaveManyBase { + private static final Logger log = LoggerFactory.getLogger(SaveManyBase.class); + final PersistRequestBean request; final SpiEbeanServer server; final boolean insertedParent; @@ -48,4 +54,17 @@ abstract class SaveManyBase { } c.modifyReset(); } + + void postElementCollectionUpdate() { + if (!insertedParent) { + if (request.postElementCollectionUpdate()) { + try { + String asJson = many.jsonWriteCollection(value); + request.addCollectionChange(many.getName(), asJson); + } catch (IOException e) { + log.error("Error build element collection entry for L2 cache", e); + } + } + } + } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java index 402a5e80a..94097fd81 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollection.java @@ -49,8 +49,6 @@ class SaveManyElementCollection extends SaveManyBase { transaction.depth(-1); resetModifyState(); - if (!insertedParent) { - request.postElementCollectionUpdate(); - } + postElementCollectionUpdate(); } } diff --git a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java index e19b7e314..f61ac4e0f 100644 --- a/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java +++ b/src/main/java/io/ebeaninternal/server/persist/SaveManyElementCollectionMap.java @@ -50,8 +50,6 @@ class SaveManyElementCollectionMap extends SaveManyBase { transaction.depth(-1); resetModifyState(); - if (!insertedParent) { - request.postElementCollectionUpdate(); - } + postElementCollectionUpdate(); } } diff --git a/src/main/java/io/ebeaninternal/server/text/json/DJsonBeanReader.java b/src/main/java/io/ebeaninternal/server/text/json/DJsonBeanReader.java index 23511f17d..ecfa3af8c 100644 --- a/src/main/java/io/ebeaninternal/server/text/json/DJsonBeanReader.java +++ b/src/main/java/io/ebeaninternal/server/text/json/DJsonBeanReader.java @@ -1,10 +1,11 @@ package io.ebeaninternal.server.text.json; +import com.fasterxml.jackson.core.JsonParser; import io.ebean.PersistenceIOException; import io.ebean.bean.PersistenceContext; import io.ebean.text.json.JsonBeanReader; +import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.server.deploy.BeanDescriptor; -import com.fasterxml.jackson.core.JsonParser; import java.io.IOException; @@ -18,9 +19,9 @@ public class DJsonBeanReader implements JsonBeanReader { private final BeanDescriptor desc; - private final ReadJson readJson; + private final SpiJsonReader readJson; - public DJsonBeanReader(BeanDescriptor desc, ReadJson readJson) { + public DJsonBeanReader(BeanDescriptor desc, SpiJsonReader readJson) { this.desc = desc; this.readJson = readJson; } diff --git a/src/main/java/io/ebeaninternal/server/text/json/DJsonContext.java b/src/main/java/io/ebeaninternal/server/text/json/DJsonContext.java index cc4302d20..dec96b5df 100644 --- a/src/main/java/io/ebeaninternal/server/text/json/DJsonContext.java +++ b/src/main/java/io/ebeaninternal/server/text/json/DJsonContext.java @@ -16,6 +16,8 @@ import io.ebean.text.json.JsonWriteBeanVisitor; import io.ebean.text.json.JsonWriteOptions; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.api.SpiJsonContext; +import io.ebeaninternal.api.json.SpiJsonReader; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.type.TypeManager; import io.ebeaninternal.util.ParamTypeHelper; @@ -119,7 +121,7 @@ public class DJsonContext implements SpiJsonContext { public T toBean(Class cls, JsonParser parser, JsonReadOptions options) throws JsonIOException { BeanDescriptor desc = getDescriptor(cls); - ReadJson readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); + SpiJsonReader readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); try { return desc.jsonRead(readJson, null); } catch (IOException e) { @@ -131,7 +133,7 @@ public class DJsonContext implements SpiJsonContext { public DJsonBeanReader createBeanReader(Class cls, JsonParser parser, JsonReadOptions options) throws JsonIOException { BeanDescriptor desc = getDescriptor(cls); - ReadJson readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); + SpiJsonReader readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); return new DJsonBeanReader<>(desc, readJson); } @@ -139,7 +141,7 @@ public class DJsonContext implements SpiJsonContext { public DJsonBeanReader createBeanReader(BeanType beanType, JsonParser parser, JsonReadOptions options) throws JsonIOException { BeanDescriptor desc = (BeanDescriptor) beanType; - ReadJson readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); + SpiJsonReader readJson = new ReadJson(desc, parser, options, determineObjectMapper(options)); return new DJsonBeanReader<>(desc, readJson); } @@ -172,7 +174,7 @@ public class DJsonContext implements SpiJsonContext { public List toList(Class cls, JsonParser src, JsonReadOptions options) throws JsonIOException { BeanDescriptor desc = getDescriptor(cls); - ReadJson readJson = new ReadJson(desc, src, options, determineObjectMapper(options)); + SpiJsonReader readJson = new ReadJson(desc, src, options, determineObjectMapper(options)); try { JsonToken currentToken = src.getCurrentToken(); @@ -304,7 +306,7 @@ public class DJsonContext implements SpiJsonContext { private String toJsonString(Object value, JsonWriteOptions options) throws JsonIOException { StringWriter writer = new StringWriter(500); - try (JsonGenerator gen = createGenerator(writer)){ + try (JsonGenerator gen = createGenerator(writer)) { toJsonInternal(value, gen, options); } catch (IOException e) { throw new JsonIOException(e); @@ -342,6 +344,14 @@ public class DJsonContext implements SpiJsonContext { } } + @Override + public SpiJsonReader createJsonRead(BeanType beanType, String json) { + + BeanDescriptor desc = (BeanDescriptor) beanType; + JsonParser parser = createParser(new StringReader(json)); + return new ReadJson(desc, parser, null, defaultObjectMapper); + } + @Override public SpiJsonWriter createJsonWriter(Writer writer) { JsonGenerator generator = createGenerator(writer); diff --git a/src/main/java/io/ebeaninternal/server/text/json/ReadJson.java b/src/main/java/io/ebeaninternal/server/text/json/ReadJson.java index a495ed3ba..8b91c86b5 100644 --- a/src/main/java/io/ebeaninternal/server/text/json/ReadJson.java +++ b/src/main/java/io/ebeaninternal/server/text/json/ReadJson.java @@ -1,17 +1,18 @@ package io.ebeaninternal.server.text.json; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.databind.ObjectMapper; import io.ebean.bean.EntityBean; import io.ebean.bean.EntityBeanIntercept; import io.ebean.bean.PersistenceContext; import io.ebean.text.json.JsonReadBeanVisitor; import io.ebean.text.json.JsonReadOptions; import io.ebeaninternal.api.LoadContext; +import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.loadcontext.DLoadContext; import io.ebeaninternal.server.transaction.DefaultPersistenceContext; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.Map; @@ -19,7 +20,7 @@ import java.util.Map; /** * Context for JSON read processing. */ -public class ReadJson { +public class ReadJson implements SpiJsonReader { private final BeanDescriptor rootDesc; @@ -100,6 +101,7 @@ public class ReadJson { /** * Return the persistence context being used if any. */ + @Override public PersistenceContext getPersistenceContext() { return persistenceContext; } @@ -107,13 +109,15 @@ public class ReadJson { /** * Return a new instance of ReadJson using the existing context but with a new JsonParser. */ - public ReadJson forJson(JsonParser moreJson, boolean resetContext) { + @Override + public SpiJsonReader forJson(JsonParser moreJson, boolean resetContext) { return new ReadJson(moreJson, this, resetContext); } /** * Add the bean to the persistence context. */ + @Override public void persistenceContextPut(Object beanId, T currentBean) { persistenceContextPutIfAbsent(beanId, (EntityBean) currentBean, rootDesc); @@ -123,6 +127,7 @@ public class ReadJson { * Put the bean into the persistence context. If there is already a matching bean in the * persistence context then return that instance else return null. */ + @Override public Object persistenceContextPutIfAbsent(Object id, EntityBean bean, BeanDescriptor beanDesc) { if (persistenceContext == null) { @@ -153,6 +158,7 @@ public class ReadJson { /** * Return the objectMapper used for this request. */ + @Override public ObjectMapper getObjectMapper() { if (objectMapper == null) { throw new IllegalStateException( @@ -165,6 +171,7 @@ public class ReadJson { /** * Return the JsonParser. */ + @Override public JsonParser getParser() { return parser; } @@ -172,6 +179,7 @@ public class ReadJson { /** * Return the next JsonToken from the underlying parser. */ + @Override public JsonToken nextToken() throws IOException { return parser.nextToken(); } @@ -179,6 +187,7 @@ public class ReadJson { /** * Push the path onto the stack (traversing a 1-M or M-1 etc) */ + @Override public void pushPath(String path) { if (pathStack != null) { pathStack.pushPathKey(path); @@ -188,6 +197,7 @@ public class ReadJson { /** * Pop the path stack. */ + @Override public void popPath() { if (pathStack != null) { pathStack.pop(); @@ -198,6 +208,7 @@ public class ReadJson { * If there is a JsonReadBeanVisitor registered to the current path then * call it's visit method with the bean and unmappedProperties. */ + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public void beanVisitor(Object bean, Map unmappedProperties) { if (visitorMap != null) { @@ -213,6 +224,7 @@ public class ReadJson { *

    * Typically this is used to read Transient properties where the type is unknown to Ebean. */ + @Override public Object readValueUsingObjectMapper(Class propertyType) throws IOException { return getObjectMapper().readValue(parser, propertyType); } diff --git a/src/main/java/io/ebeaninternal/server/text/json/WriteJson.java b/src/main/java/io/ebeaninternal/server/text/json/WriteJson.java index 20c7d3f28..2607974fa 100644 --- a/src/main/java/io/ebeaninternal/server/text/json/WriteJson.java +++ b/src/main/java/io/ebeaninternal/server/text/json/WriteJson.java @@ -9,6 +9,7 @@ import io.ebean.text.json.EJson; import io.ebean.text.json.JsonIOException; import io.ebean.text.json.JsonWriteBeanVisitor; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.json.SpiJsonWriter; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.util.ArrayStack; @@ -89,6 +90,11 @@ public class WriteJson implements SpiJsonWriter { return generator; } + @Override + public void flush() throws IOException { + generator.flush(); + } + @Override public void writeStartObject(String key) { try { @@ -373,7 +379,9 @@ public class WriteJson implements SpiJsonWriter { public void beginAssocMany(String key) { try { pathStack.pushPathKey(key); - generator.writeFieldName(key); + if (key != null) { + generator.writeFieldName(key); + } generator.writeStartArray(); } catch (IOException e) { throw new JsonIOException(e); diff --git a/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertSimple.java b/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertSimple.java index 92618f94f..cd48d4247 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertSimple.java +++ b/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertSimple.java @@ -5,7 +5,7 @@ import io.ebean.Ebean; import io.ebean.EbeanServer; import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import org.junit.Test; import org.tests.model.basic.Customer; import org.tests.model.basic.Order; @@ -57,7 +57,7 @@ public class TestDiffHelpInsertSimple extends BaseTestCase { SpiJsonWriter jsonWriter = spiEbeanServer().jsonExtended().createJsonWriter(buffer); orderDesc.jsonWriteForInsert(jsonWriter, (EntityBean) order1); - jsonWriter.gen().flush(); + jsonWriter.flush(); String asJson = buffer.toString(); diff --git a/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertWithEmbedded.java b/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertWithEmbedded.java index 7e04187dd..f2a03c63d 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertWithEmbedded.java +++ b/src/test/java/io/ebeaninternal/server/deploy/TestDiffHelpInsertWithEmbedded.java @@ -5,7 +5,7 @@ import io.ebean.Ebean; import io.ebean.EbeanServer; import io.ebean.bean.EntityBean; import io.ebeaninternal.api.SpiEbeanServer; -import io.ebeaninternal.server.text.json.SpiJsonWriter; +import io.ebeaninternal.api.json.SpiJsonWriter; import org.junit.Test; import org.tests.model.embedded.EMain; import org.tests.model.embedded.Eembeddable; @@ -44,7 +44,7 @@ public class TestDiffHelpInsertWithEmbedded extends BaseTestCase { SpiJsonWriter jsonWriter = spiEbeanServer().jsonExtended().createJsonWriter(buffer); emainDesc.jsonWriteForInsert(jsonWriter, emain1); - jsonWriter.gen().flush(); + jsonWriter.flush(); return buffer.toString(); } diff --git a/src/test/java/org/tests/model/elementcollection/EcPerson.java b/src/test/java/org/tests/model/elementcollection/EcPerson.java index 00550b5c6..763b137ab 100644 --- a/src/test/java/org/tests/model/elementcollection/EcPerson.java +++ b/src/test/java/org/tests/model/elementcollection/EcPerson.java @@ -1,5 +1,7 @@ package org.tests.model.elementcollection; +import io.ebean.annotation.Cache; + import javax.persistence.CollectionTable; import javax.persistence.Column; import javax.persistence.ElementCollection; @@ -10,6 +12,7 @@ import javax.persistence.Version; import java.util.ArrayList; import java.util.List; +@Cache @Entity public class EcPerson { diff --git a/src/test/java/org/tests/model/elementcollection/EcblPerson.java b/src/test/java/org/tests/model/elementcollection/EcblPerson.java index 982071e13..c4998d855 100644 --- a/src/test/java/org/tests/model/elementcollection/EcblPerson.java +++ b/src/test/java/org/tests/model/elementcollection/EcblPerson.java @@ -1,5 +1,7 @@ package org.tests.model.elementcollection; +import io.ebean.annotation.Cache; + import javax.persistence.CollectionTable; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -9,6 +11,7 @@ import javax.persistence.Version; import java.util.ArrayList; import java.util.List; +@Cache @Entity public class EcblPerson { diff --git a/src/test/java/org/tests/model/elementcollection/EcbmPerson.java b/src/test/java/org/tests/model/elementcollection/EcbmPerson.java index 7a236bb85..992178c54 100644 --- a/src/test/java/org/tests/model/elementcollection/EcbmPerson.java +++ b/src/test/java/org/tests/model/elementcollection/EcbmPerson.java @@ -1,5 +1,7 @@ package org.tests.model.elementcollection; +import io.ebean.annotation.Cache; + import javax.persistence.CollectionTable; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -9,7 +11,7 @@ import javax.persistence.Version; import java.util.LinkedHashMap; import java.util.Map; - +@Cache @Entity public class EcbmPerson { diff --git a/src/test/java/org/tests/model/elementcollection/EcmPerson.java b/src/test/java/org/tests/model/elementcollection/EcmPerson.java index 8be26fa50..fafb073e1 100644 --- a/src/test/java/org/tests/model/elementcollection/EcmPerson.java +++ b/src/test/java/org/tests/model/elementcollection/EcmPerson.java @@ -1,5 +1,7 @@ package org.tests.model.elementcollection; +import io.ebean.annotation.Cache; + import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Entity; @@ -9,6 +11,7 @@ import javax.persistence.Version; import java.util.LinkedHashMap; import java.util.Map; +@Cache @Entity public class EcmPerson { diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java new file mode 100644 index 000000000..a73220ce1 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java @@ -0,0 +1,80 @@ +package org.tests.model.elementcollection; + +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionBasicCache { + + @Test + public void test() { + + EcPerson person = new EcPerson("Cache1"); + person.getPhoneNumbers().add("021 1234"); + person.getPhoneNumbers().add("021 4321"); + Ebean.save(person); + + EcPerson one = Ebean.find(EcPerson.class) + .setId(person.getId()) + .findOne(); + + one.getPhoneNumbers().size(); + + LoggedSqlCollector.start(); + + EcPerson two = Ebean.find(EcPerson.class) + .setId(person.getId()) + .findOne(); + + two.setName("CacheMod"); + two.getPhoneNumbers().add("027 234234"); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit containing phone numbers + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // no change + + EcPerson three = Ebean.find(EcPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(three.getName()).isEqualTo("CacheMod"); + assertThat(three.getPhoneNumbers()).contains("021 1234", "021 4321", "027 234234"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + three.getPhoneNumbers().add("09 6534"); + Ebean.save(three); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); // cache hit + + EcPerson four = Ebean.find(EcPerson.class) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + assertThat(four.getName()).isEqualTo("CacheMod"); + assertThat(four.getPhoneNumbers()).contains("021 1234", "021 4321", "027 234234", "09 6534"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + Ebean.delete(four); + + LoggedSqlCollector.stop(); + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java new file mode 100644 index 000000000..137e8e495 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java @@ -0,0 +1,85 @@ +package org.tests.model.elementcollection; + +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionBasicMapCache { + + @Test + public void test() { + + EcmPerson person = new EcmPerson("CacheMap"); + person.getPhoneNumbers().put("home", "021 1234"); + person.getPhoneNumbers().put("work", "021 4321"); + Ebean.save(person); + + + EcmPerson one = Ebean.find(EcmPerson.class) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + one.getPhoneNumbers().size(); + + LoggedSqlCollector.start(); + + EcmPerson two = Ebean.find(EcmPerson.class) + .setId(person.getId()) + .findOne(); + + two.setName("CacheMod"); + two.getPhoneNumbers().put("mob", "027 234234"); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit containing phone numbers + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // no change + + EcmPerson three = Ebean.find(EcmPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(three.getName()).isEqualTo("CacheMod"); + assertThat(three.getPhoneNumbers().toString()).contains("021 1234", "021 4321", "027 234234"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + three.getPhoneNumbers().put("oth", "09 6534"); + three.getPhoneNumbers().remove("home"); + three.getPhoneNumbers().remove("work"); + Ebean.save(three); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); // cache hit + + EcmPerson four = Ebean.find(EcmPerson.class) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + assertThat(four.getName()).isEqualTo("CacheMod"); + assertThat(four.getPhoneNumbers().toString()).contains("027 234234", "09 6534"); + assertThat(four.getPhoneNumbers()).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + Ebean.delete(four); + + LoggedSqlCollector.stop(); + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java new file mode 100644 index 000000000..c9cbaf4d4 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java @@ -0,0 +1,88 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionEmbeddedListCache extends BaseTestCase { + + @Test + public void test() { + + EcblPerson person = new EcblPerson("CacheL"); + person.getPhoneNumbers().add(new EcPhone("64", "021","1234")); + person.getPhoneNumbers().add(new EcPhone("64","021","4321")); + Ebean.save(person); + + EcblPerson one = Ebean.find(EcblPerson.class) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + LoggedSqlCollector.start(); + + one.getPhoneNumbers().size(); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); + + EcblPerson two = Ebean.find(EcblPerson.class) + .setId(person.getId()) + .findOne(); + + two.getPhoneNumbers().size(); + assertThat(two.getPhoneNumbers().toString()).contains("64-021-1234", "64-021-4321"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + two.getPhoneNumbers().add(new EcPhone("61", "07", "11")); + two.getPhoneNumbers().remove(1); + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + + EcblPerson three = Ebean.find(EcblPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(three.getPhoneNumbers().toString()).contains("61-07-11", "64-021-1234"); + assertThat(three.getPhoneNumbers()).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + + three.setName("mod-3"); + three.getPhoneNumbers().remove(0); + + Ebean.save(three); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + + EcblPerson four = Ebean.find(EcblPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(four.getPhoneNumbers().toString()).contains("61-07-11"); + assertThat(four.getPhoneNumbers()).hasSize(1); + + + Ebean.delete(four); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + + + LoggedSqlCollector.stop(); + } +} diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java index ca342342c..50b37480c 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java @@ -90,7 +90,7 @@ public class TestElementCollectionEmbeddedMap extends BaseTestCase { assertThat(sql).hasSize(3); assertThat(sql.get(0)).contains("update ecbm_person set name=?, version=? where id=? and version=?"); assertThat(sql.get(1)).contains("delete from ecbm_person_phone_numbers where person_id=?"); - assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,key,country_code,area,number)"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); updateNothing(bean); } @@ -113,7 +113,7 @@ public class TestElementCollectionEmbeddedMap extends BaseTestCase { List sql = LoggedSqlCollector.current(); assertThat(sql).hasSize(2); assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); - assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,key,country_code,area,number) values (?,?,?,?,?)"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); delete(bean); } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java new file mode 100644 index 000000000..1c29bfc55 --- /dev/null +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java @@ -0,0 +1,89 @@ +package org.tests.model.elementcollection; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestElementCollectionEmbeddedMapCache extends BaseTestCase { + + @Test + public void test() { + + EcbmPerson person = new EcbmPerson("Cache1"); + person.getPhoneNumbers().put("home", new EcPhone("64", "021", "1234")); + person.getPhoneNumbers().put("work", new EcPhone("64", "021", "4321")); + Ebean.save(person); + + + EcbmPerson one = Ebean.find(EcbmPerson.class) + .setId(person.getId()) + .fetch("phoneNumbers") + .findOne(); + + LoggedSqlCollector.start(); + + one.getPhoneNumbers().size(); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); + + EcbmPerson two = Ebean.find(EcbmPerson.class) + .setId(person.getId()) + .findOne(); + + two.getPhoneNumbers().size(); + assertThat(two.getPhoneNumbers().toString()).contains("64-021-1234", "64-021-4321"); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + two.getPhoneNumbers().put("mob", new EcPhone("61", "07", "11")); + two.getPhoneNumbers().remove("home"); + + Ebean.save(two); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + + EcbmPerson three = Ebean.find(EcbmPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(three.getPhoneNumbers().toString()).contains("61-07-11", "64-021-4321"); + assertThat(three.getPhoneNumbers()).hasSize(2); + + sql = LoggedSqlCollector.current(); + assertThat(sql).isEmpty(); // cache hit + + + three.setName("mod-3"); + three.getPhoneNumbers().remove("work"); + + Ebean.save(three); + + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + + EcbmPerson four = Ebean.find(EcbmPerson.class) + .setId(person.getId()) + .findOne(); + + assertThat(four.getPhoneNumbers().toString()).contains("61-07-11"); + assertThat(four.getPhoneNumbers()).hasSize(1); + + + Ebean.delete(four); + sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(2); + + + LoggedSqlCollector.stop(); + } +} diff --git a/src/test/java/org/tests/text/json/TestJsonBeanDescriptorParse.java b/src/test/java/org/tests/text/json/TestJsonBeanDescriptorParse.java index ebce7d3a2..eaf1825fc 100644 --- a/src/test/java/org/tests/text/json/TestJsonBeanDescriptorParse.java +++ b/src/test/java/org/tests/text/json/TestJsonBeanDescriptorParse.java @@ -1,15 +1,16 @@ package org.tests.text.json; +import com.fasterxml.jackson.core.JsonParser; import io.ebean.BaseTestCase; import io.ebean.BeanState; import io.ebean.Ebean; import io.ebeaninternal.api.SpiEbeanServer; +import io.ebeaninternal.api.json.SpiJsonReader; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.text.json.ReadJson; -import org.tests.model.basic.Customer; -import com.fasterxml.jackson.core.JsonParser; import org.junit.Assert; import org.junit.Test; +import org.tests.model.basic.Customer; import java.io.IOException; import java.io.StringReader; @@ -28,7 +29,7 @@ public class TestJsonBeanDescriptorParse extends BaseTestCase { StringReader reader = new StringReader("{\"id\":123,\"name\":\"Hello rob\"}"); JsonParser parser = server.json().createParser(reader); - ReadJson readJson = new ReadJson(descriptor, parser, null, null); + SpiJsonReader readJson = new ReadJson(descriptor, parser, null, null); Customer customer = descriptor.jsonRead(readJson, null); From aa004f11af735b5ccb51ca33cfd4ca1fc807d42b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 01:49:28 +1300 Subject: [PATCH 0211/1036] [maven-release-plugin] prepare release ebean-11.15.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index abf1a3e82..21b0f6984 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.2-SNAPSHOT + 11.15.2 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.15.2 From 6b136248fa2c6366c47350471a265276a4b0b6ae Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 01:49:43 +1300 Subject: [PATCH 0212/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 21b0f6984..e12095e0b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.2 + 11.15.3-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.15.2 + HEAD From b8c4e1c3d3bcbebbb9abfd98f23f79631c4437da Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 10:22:12 +1300 Subject: [PATCH 0213/1036] #1357 - Regression in 11.15.2 - for nested Ebean.beginTransaction(TxScope.requiresNew()); ... where closed via ebeanServer.endTransaction(); rather than transaction.end() --- .../server/core/DefaultServer.java | 2 +- .../TestTransactionalRequiresNew.java | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index c131f6722..1a904843b 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -843,7 +843,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { */ @Override public void endTransaction() { - Transaction transaction = currentTransaction(); + Transaction transaction = transactionManager.getInScope(); if (transaction != null) { transaction.end(); } diff --git a/src/test/java/org/tests/transaction/TestTransactionalRequiresNew.java b/src/test/java/org/tests/transaction/TestTransactionalRequiresNew.java index 03e353f39..7e0415575 100644 --- a/src/test/java/org/tests/transaction/TestTransactionalRequiresNew.java +++ b/src/test/java/org/tests/transaction/TestTransactionalRequiresNew.java @@ -2,7 +2,9 @@ package org.tests.transaction; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.EbeanServer; import io.ebean.Transaction; +import io.ebean.TxScope; import io.ebean.annotation.Transactional; import io.ebean.annotation.TxType; import org.junit.Test; @@ -11,6 +13,7 @@ import org.slf4j.LoggerFactory; import java.sql.Connection; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; @@ -66,5 +69,64 @@ public class TestTransactionalRequiresNew extends BaseTestCase { } } + @Test + public void testDifferentCreation1() { + EbeanServer server = server(); + try(Transaction txn = server.beginTransaction()) { + String txnName = txn.toString(); + Ebean.beginTransaction(TxScope.requiresNew()); + try { + Ebean.commitTransaction(); + } finally { + Ebean.endTransaction(); + } + assertThat(txn.toString()).isEqualTo(txnName); + } + } + + @Test + public void testDifferentCreation2() { + EbeanServer server = server(); + try (Transaction txn = server.beginTransaction()) { + String txnName = txn.toString(); + server.beginTransaction(TxScope.requiresNew()); + try { + server.commitTransaction(); + } finally { + server.endTransaction(); + } + assertThat(txn.toString()).isEqualTo(txnName); + } + } + + @Test + public void testDifferentCreation3() { + EbeanServer server = server(); + try (Transaction txn = server.beginTransaction()) { + String txnName = txn.toString(); + Transaction txn2 = Ebean.beginTransaction(TxScope.requiresNew()); + try { + txn2.commit(); + } finally { + txn2.end(); + } + assertThat(txn.toString()).isEqualTo(txnName); + } + } + + @Test + public void testDifferentCreation4() { + EbeanServer server = server(); + try (Transaction txn = server.beginTransaction()) { + String txnName = txn.toString(); + server.beginTransaction(TxScope.requiresNew()); + try { + Transaction.current().commitAndContinue(); + } finally { + Transaction.current().end(); + } + assertThat(txn.toString()).isEqualTo(txnName); + } + } } From 04e0069eb39584c16726c6f6cd1d571fdc2f1011 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 14:35:25 +1300 Subject: [PATCH 0214/1036] [maven-release-plugin] prepare release ebean-11.15.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e12095e0b..f7fbed665 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.3-SNAPSHOT + 11.15.3 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.15.3 From 9a3362e84226ce1d15cbbc5fda589e1af6b4fd1c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 29 Mar 2018 14:35:40 +1300 Subject: [PATCH 0215/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index f7fbed665..6e233810e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.3 + 11.15.4-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.15.3 + HEAD From 05aff53241a91400b79d441846d2ce06ca3281e6 Mon Sep 17 00:00:00 2001 From: Roman Parshikov Date: Tue, 3 Apr 2018 17:17:46 +0800 Subject: [PATCH 0216/1036] Fix Maven links in README (#1358) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index db3cf331e..65f85b8e7 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Goto [https://ebean-orm.github.io/](http://ebean-orm.github.io/ "Ebean ORM's Web [Maven central - all related projects](http://search.maven.org/#search%7Cga%7C1%7Cebean "maven central all related projects") ## Current versions -* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.ebean/ebean) - ebean -* [![Maven Central : ebean-agent](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean-agent/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.avaje.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/org.avaje.ebean/ebean-maven-plugin) - ebean-maven-plugin +* [![Maven Central : ebean](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.ebean/ebean) - ebean +* [![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 dd6f223ae11fd14474dd1abad85b7c9ce8212049 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 5 Apr 2018 21:35:29 +1200 Subject: [PATCH 0217/1036] #1360 - ENH: Add transaction.setNestedUseSavepoint() ... such that nested transactions are actually Savepoints --- src/main/java/io/ebean/Transaction.java | 18 ++- .../io/ebeaninternal/api/SpiTransaction.java | 5 + .../api/SpiTransactionProxy.java | 12 +- .../ImplicitReadOnlyTransaction.java | 10 ++ .../server/transaction/JdbcTransaction.java | 12 ++ .../server/transaction/NoTransaction.java | 10 ++ .../transaction/SavepointTransaction.java | 107 ++++++++++++++++++ .../transaction/TransactionManager.java | 53 ++++++--- .../transaction/TestNestedSubTransaction.java | 42 +++++++ 9 files changed, 250 insertions(+), 19 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java diff --git a/src/main/java/io/ebean/Transaction.java b/src/main/java/io/ebean/Transaction.java index 743fcc138..cd4a4bbc5 100644 --- a/src/main/java/io/ebean/Transaction.java +++ b/src/main/java/io/ebean/Transaction.java @@ -23,6 +23,7 @@ public interface Transaction extends AutoCloseable { * This returns the current transaction for the 'default server'. If you are using * multiple EbeanServer's then use {@link EbeanServer#currentTransaction()}. *

    + * * @see Ebean#currentTransaction() * @see EbeanServer#currentTransaction() */ @@ -136,6 +137,18 @@ public interface Transaction extends AutoCloseable { */ void rollback(Throwable e) throws PersistenceException; + /** + * Set when we want nested transactions to use Savepoint's. + *

    + * This means that for a nested transaction: + *

      + *
    • begin transaction maps to creating a savepoint
    • + *
    • commit transaction maps to releasing a savepoint
    • + *
    • rollback transaction maps to rollback a savepoint
    • + *
    + */ + void setNestedUseSavepoint(); + /** * Mark the transaction for rollback only. */ @@ -151,7 +164,6 @@ public interface Transaction extends AutoCloseable { */ void end(); - /** * Synonym for end() to support AutoClosable. */ @@ -227,7 +239,7 @@ public interface Transaction extends AutoCloseable { * Refer to {@link ServerConfig#setSkipCacheAfterWrite(boolean)} for configuring the default behavior * for using the L2 bean cache in transactions spanning multiple query/persist requests. *

    - *

    + * *

    {@code
        *
        *   // assume Customer has L2 bean caching enabled ...
    @@ -309,7 +321,7 @@ public interface Transaction extends AutoCloseable {
        * 

    * Example: batch processing executing every 3 rows *

    - *

    + * *

    {@code
        *
        * String data = "This is a simple test of the batch processing"
    diff --git a/src/main/java/io/ebeaninternal/api/SpiTransaction.java b/src/main/java/io/ebeaninternal/api/SpiTransaction.java
    index 715b9387f..e134986c5 100644
    --- a/src/main/java/io/ebeaninternal/api/SpiTransaction.java
    +++ b/src/main/java/io/ebeaninternal/api/SpiTransaction.java
    @@ -319,4 +319,9 @@ public interface SpiTransaction extends Transaction {
        * Return the profile location for this transaction.
        */
       ProfileLocation getProfileLocation();
    +
    +  /**
    +   * Return true when nested transactions should create Savepoints.
    +   */
    +  boolean isNestedUseSavepoint();
     }
    diff --git a/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java b/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java
    index b9907aa3a..02057236c 100644
    --- a/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java
    +++ b/src/main/java/io/ebeaninternal/api/SpiTransactionProxy.java
    @@ -21,7 +21,7 @@ import java.sql.SQLException;
     /**
      * Proxy for an underlying SpiTransaction (most of the API).
      */
    -abstract class SpiTransactionProxy implements SpiTransaction {
    +public abstract class SpiTransactionProxy implements SpiTransaction {
     
       protected SpiTransaction transaction;
     
    @@ -50,6 +50,16 @@ abstract class SpiTransactionProxy implements SpiTransaction {
         return transaction.isRollbackOnly();
       }
     
    +  @Override
    +  public void setNestedUseSavepoint() {
    +    transaction.setNestedUseSavepoint();
    +  }
    +
    +  @Override
    +  public boolean isNestedUseSavepoint() {
    +    return transaction.isNestedUseSavepoint();
    +  }
    +
       @Override
       public long profileOffset() {
         return transaction.profileOffset();
    diff --git a/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java
    index 0e95880cb..d23fde6d5 100644
    --- a/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java
    +++ b/src/main/java/io/ebeaninternal/server/transaction/ImplicitReadOnlyTransaction.java
    @@ -231,6 +231,16 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
       public void markNotQueryOnly() {
       }
     
    +  @Override
    +  public boolean isNestedUseSavepoint() {
    +    return false;
    +  }
    +
    +  @Override
    +  public void setNestedUseSavepoint() {
    +
    +  }
    +
       @Override
       public boolean isReadOnly() {
         if (!isActive()) {
    diff --git a/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java
    index 322f70725..57c546bdc 100644
    --- a/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java
    +++ b/src/main/java/io/ebeaninternal/server/transaction/JdbcTransaction.java
    @@ -77,6 +77,8 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
     
       protected boolean rollbackOnly;
     
    +  protected boolean nestedUseSavepoint;
    +
       /**
        * The underlying Connection.
        */
    @@ -1117,6 +1119,16 @@ public class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
         this.rollbackOnly = true;
       }
     
    +  @Override
    +  public boolean isNestedUseSavepoint() {
    +    return nestedUseSavepoint;
    +  }
    +
    +  @Override
    +  public void setNestedUseSavepoint() {
    +    this.nestedUseSavepoint = true;
    +  }
    +
       /**
        * Rollback the transaction.
        */
    diff --git a/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java
    index 9ee156066..62ace0ede 100644
    --- a/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java
    +++ b/src/main/java/io/ebeaninternal/server/transaction/NoTransaction.java
    @@ -37,6 +37,16 @@ class NoTransaction implements SpiTransaction {
         return null;
       }
     
    +  @Override
    +  public boolean isNestedUseSavepoint() {
    +    return false;
    +  }
    +
    +  @Override
    +  public void setNestedUseSavepoint() {
    +
    +  }
    +
       @Override
       public boolean isActive() {
         // always false
    diff --git a/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java b/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java
    new file mode 100644
    index 000000000..4d6525c55
    --- /dev/null
    +++ b/src/main/java/io/ebeaninternal/server/transaction/SavepointTransaction.java
    @@ -0,0 +1,107 @@
    +package io.ebeaninternal.server.transaction;
    +
    +import io.ebeaninternal.api.SpiTransaction;
    +import io.ebeaninternal.api.SpiTransactionProxy;
    +import io.ebeaninternal.server.lib.util.Str;
    +
    +import javax.persistence.PersistenceException;
    +import java.sql.Connection;
    +import java.sql.SQLException;
    +import java.sql.Savepoint;
    +
    +/**
    + * A nested transaction that represents a Savepoint.
    + */
    +class SavepointTransaction extends SpiTransactionProxy {
    +
    +  private static final int STATE_COMMITTED = 1;
    +  private static final int STATE_ROLLED_BACK = 2;
    +
    +  private final TransactionManager manager;
    +  private final Savepoint savepoint;
    +  private final Connection connection;
    +  private final String logPrefix;
    +
    +  private boolean rollbackOnly;
    +  private int state;
    +
    +  SavepointTransaction(SpiTransaction transaction, TransactionManager manager) throws SQLException {
    +    this.manager = manager;
    +    this.transaction = transaction;
    +    this.connection = transaction.getInternalConnection();
    +    this.savepoint = connection.setSavepoint();
    +    int savepointId = savepoint.getSavepointId();
    +    this.logPrefix = "txn[" + transaction.getId() + "-sp" + savepointId + "] ";
    +  }
    +
    +  @Override
    +  public String getLogPrefix() {
    +    return logPrefix;
    +  }
    +
    +  @Override
    +  public void logSql(String msg) {
    +    TransactionManager.SQL_LOGGER.debug(Str.add(logPrefix, msg));
    +  }
    +
    +  @Override
    +  public void logSummary(String msg) {
    +    TransactionManager.SUM_LOGGER.debug(Str.add(logPrefix, msg));
    +  }
    +
    +  @Override
    +  public void setRollbackOnly() {
    +    this.rollbackOnly = true;
    +  }
    +
    +  @Override
    +  public void commit() {
    +    if (rollbackOnly) {
    +      rollbackSavepoint(null);
    +    } else {
    +      commitSavepoint();
    +    }
    +  }
    +
    +  @Override
    +  public void rollback() throws PersistenceException {
    +    rollbackSavepoint(null);
    +  }
    +
    +  @Override
    +  public void rollback(Throwable e) throws PersistenceException {
    +    rollbackSavepoint(e);
    +  }
    +
    +  private void commitSavepoint() {
    +    try {
    +      connection.releaseSavepoint(savepoint);
    +      state = STATE_COMMITTED;
    +      manager.notifyOfCommit(this);
    +    } catch (SQLException e) {
    +      throw new PersistenceException("Error trying to commit/release Savepoint", e);
    +    }
    +  }
    +
    +  private void rollbackSavepoint(Throwable cause) throws PersistenceException {
    +    try {
    +      connection.rollback(savepoint);
    +      state = STATE_ROLLED_BACK;
    +      manager.notifyOfRollback(this, cause);
    +    } catch (SQLException e) {
    +      throw new PersistenceException("Error trying to rollback Savepoint", e);
    +    }
    +  }
    +
    +  @Override
    +  public void end() {
    +    if (state == 0) {
    +      rollback();
    +    }
    +  }
    +
    +  @Override
    +  public void close() {
    +    end();
    +  }
    +}
    diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java
    index c76358829..0f5e26086 100644
    --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java
    +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java
    @@ -582,27 +582,42 @@ public class TransactionManager implements SpiTransactionManager {
     
         txScope = initTxScope(txScope);
     
    -    boolean setToScope = false;
         ScopedTransaction txnContainer = getActiveScoped();
    +
    +    boolean setToScope;
    +    boolean nestedSavepoint;
    +    SpiTransaction transaction;
         if (txnContainer == null) {
    -      setToScope = true;
           txnContainer = createScopedTransaction();
    +      setToScope = true;
    +      transaction = null;
    +      nestedSavepoint = false;
    +    } else {
    +      setToScope = false;
    +      transaction = txnContainer.current();
    +      nestedSavepoint = transaction.isNestedUseSavepoint();
         }
     
    -    SpiTransaction transaction = txnContainer.current();
    -
         TxType type = txScope.getType();
    -    boolean createTransaction = isCreateNewTransaction(transaction, type);
    -    if (createTransaction) {
    -      switch (type) {
    -        case SUPPORTS:
    -        case NOT_SUPPORTED:
    -        case NEVER:
    -          transaction = NoTransaction.INSTANCE;
    -          break;
    -        default:
    -          transaction = createTransaction(true, txScope.getIsolationLevel());
    -          initNewTransaction(transaction, txScope);
    +
    +    boolean createTransaction;
    +    if (nestedSavepoint && (type == TxType.REQUIRED || type == TxType.REQUIRES_NEW)) {
    +      createTransaction = true;
    +      transaction = createSavepoint(transaction, this);
    +
    +    } else {
    +      createTransaction = isCreateNewTransaction(transaction, type);
    +      if (createTransaction) {
    +        switch (type) {
    +          case SUPPORTS:
    +          case NOT_SUPPORTED:
    +          case NEVER:
    +            transaction = NoTransaction.INSTANCE;
    +            break;
    +          default:
    +            transaction = createTransaction(true, txScope.getIsolationLevel());
    +            initNewTransaction(transaction, txScope);
    +        }
           }
         }
     
    @@ -613,6 +628,14 @@ public class TransactionManager implements SpiTransactionManager {
         return txnContainer;
       }
     
    +  private SpiTransaction createSavepoint(SpiTransaction transaction, TransactionManager manager) {
    +    try {
    +      return new SavepointTransaction(transaction, manager);
    +    } catch (SQLException e) {
    +      throw new PersistenceException("Error creating nested Savepoint Transaction", e);
    +    }
    +  }
    +
       private void initNewTransaction(SpiTransaction transaction, TxScope txScope) {
     
         if (txScope.isSkipCache()) {
    diff --git a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    index f7e9e62e2..9b58bd07b 100644
    --- a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    +++ b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    @@ -56,6 +56,48 @@ public class TestNestedSubTransaction extends BaseTestCase {
         }
       }
     
    +  @Test
    +  public void nestedUseSavepoint() {
    +
    +    EbeanServer server = server();
    +
    +    EBasic bean = new EBasic("start1");
    +
    +    try (Transaction txn0 = server.beginTransaction()) {
    +      txn0.setRollbackOnly();
    +      txn0.setNestedUseSavepoint();
    +
    +      server.save(bean);
    +
    +      try (Transaction txn1 = server.beginTransaction()) {
    +        bean.setName("updateNested");
    +        server.save(bean);
    +        txn1.commit();
    +      }
    +
    +      EBasic fresh = server.find(EBasic.class, bean.getId());
    +      assertNotNull(fresh);
    +      assertThat(fresh.getName()).isEqualTo("updateNested");
    +
    +      try (Transaction txn2 = server.beginTransaction()) {
    +        bean.setName("barney");
    +        Ebean.save(bean);
    +        txn2.rollback();
    +      }
    +
    +      fresh = server.find(EBasic.class)
    +        .setId(bean.getId())
    +        .setPersistenceContextScope(PersistenceContextScope.QUERY)
    +        .findOne();
    +
    +      assertNotNull(fresh);
    +      assertThat(fresh.getName()).isEqualTo("updateNested");
    +
    +    } finally {
    +      cleanup(bean);
    +    }
    +  }
    +
       private void cleanup(EBasic bean) {
         Ebean.delete(EBasic.class, bean.getId());
       }
    
    From e49a0c9ffb7463b9704058b34d7f1876c7a7ee02 Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 5 Apr 2018 21:48:54 +1200
    Subject: [PATCH 0218/1036] #1360 - ENH: Add
     transaction.setNestedUseSavepoint() ... such that nested transactions are
     actually Savepoints
    
    Additional tests
    ---
     .../transaction/TestNestedSubTransaction.java | 110 ++++++++++++++++++
     1 file changed, 110 insertions(+)
    
    diff --git a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    index 9b58bd07b..9c99b5f86 100644
    --- a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    +++ b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java
    @@ -5,11 +5,13 @@ import io.ebean.Ebean;
     import io.ebean.EbeanServer;
     import io.ebean.PersistenceContextScope;
     import io.ebean.Transaction;
    +import io.ebean.TxScope;
     import org.junit.Test;
     import org.tests.model.basic.EBasic;
     
     import static org.assertj.core.api.Assertions.assertThat;
     import static org.junit.Assert.assertNotNull;
    +import static org.junit.Assert.assertNull;
     
     public class TestNestedSubTransaction extends BaseTestCase {
     
    @@ -56,6 +58,114 @@ public class TestNestedSubTransaction extends BaseTestCase {
         }
       }
     
    +
    +  @Test
    +  public void nestedUseSavepoint_doubleNested_rollbackCommit() {
    +
    +    EbeanServer server = server();
    +
    +    EBasic bean = new EBasic("start2");
    +
    +    try (Transaction txn0 = server.beginTransaction()) {
    +      txn0.setRollbackOnly();
    +      txn0.setNestedUseSavepoint();
    +
    +      server.save(bean);
    +
    +      try (Transaction txn1 = server.beginTransaction()) {
    +        bean.setName("updateNested");
    +        server.save(bean);
    +
    +        try (Transaction txn2 = server.beginTransaction()) {
    +          bean.setName("barney");
    +          Ebean.save(bean);
    +          txn2.commit();
    +        }
    +
    +        txn1.rollback();
    +      }
    +
    +      EBasic fresh = server.find(EBasic.class)
    +        .setId(bean.getId())
    +        .setPersistenceContextScope(PersistenceContextScope.QUERY)
    +        .findOne();
    +
    +      assertNotNull(fresh);
    +      assertThat(fresh.getName()).isEqualTo("start2");
    +    }
    +  }
    +
    +  @Test
    +  public void nestedUseSavepoint_doubleNested_commitRollback() {
    +
    +    EbeanServer server = server();
    +
    +    EBasic bean = new EBasic("start3");
    +
    +    try (Transaction txn0 = server.beginTransaction()) {
    +      txn0.setRollbackOnly();
    +      txn0.setNestedUseSavepoint();
    +
    +      server.save(bean);
    +
    +      try (Transaction txn1 = server.beginTransaction()) {
    +        bean.setName("updateNested3");
    +        server.save(bean);
    +
    +        try (Transaction txn2 = server.beginTransaction()) {
    +          bean.setName("barney3");
    +          Ebean.save(bean);
    +          txn2.rollback();
    +        }
    +
    +        txn1.commit();
    +      }
    +
    +      EBasic fresh = server.find(EBasic.class)
    +        .setId(bean.getId())
    +        .setPersistenceContextScope(PersistenceContextScope.QUERY)
    +        .findOne();
    +
    +      assertNotNull(fresh);
    +      assertThat(fresh.getName()).isEqualTo("updateNested3");
    +    }
    +  }
    +
    +  @Test
    +  public void nestedUseSavepoint_nested_RequiresNew() {
    +
    +    EbeanServer server = server();
    +
    +    EBasic bean = new EBasic("start4");
    +
    +    try (Transaction txn0 = server.beginTransaction()) {
    +      txn0.setRollbackOnly();
    +      txn0.setNestedUseSavepoint();
    +
    +      server.save(bean);
    +
    +      try (Transaction txn1 = server.beginTransaction(TxScope.requiresNew())) {
    +        bean.setName("updateNested4");
    +        server.save(bean);
    +        txn1.commit();
    +      }
    +
    +      EBasic fresh = server.find(EBasic.class)
    +        .setId(bean.getId())
    +        .setPersistenceContextScope(PersistenceContextScope.QUERY)
    +        .findOne();
    +
    +      assertNotNull(fresh);
    +      assertThat(fresh.getName()).isEqualTo("updateNested4");
    +    }
    +
    +    EBasic after = server.find(EBasic.class)
    +      .setId(bean.getId())
    +      .findOne();
    +
    +    assertNull(after);
    +  }
    +
       @Test
       public void nestedUseSavepoint() {
     
    
    From 4167dfc4af5a16fa79a92e7b91f2ad53be87838e Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 5 Apr 2018 22:23:03 +1200
    Subject: [PATCH 0219/1036] [maven-release-plugin] prepare release
     ebean-11.15.4
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index 6e233810e..b7b5b3e57 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.4-SNAPSHOT
    +  11.15.4
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    HEAD
    +    ebean-11.15.4
       
     
       
    
    From b0d3921264cdeb79d5570d170820465ee296325c Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 5 Apr 2018 22:23:18 +1200
    Subject: [PATCH 0220/1036] [maven-release-plugin] prepare for next development
     iteration
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index b7b5b3e57..1b3964328 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.4
    +  11.15.5-SNAPSHOT
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    ebean-11.15.4
    +    HEAD
       
     
       
    
    From a8434f22fff40e3563c5551540973cc6369b7925 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Andr=C3=A9=20Camilo?= 
    Date: Thu, 12 Apr 2018 09:38:09 +0100
    Subject: [PATCH 0221/1036] Inheritance - Add support for @DiscriminatorValue
     to be optional (#1361)
    
    ---
     .../java/io/ebeaninternal/server/deploy/InheritInfo.java     | 3 ++-
     .../io/ebeaninternal/server/deploy/parse/DeployInherit.java  | 2 ++
     .../ebeaninternal/server/deploy/parse/DeployInheritInfo.java | 5 +++--
     3 files changed, 7 insertions(+), 3 deletions(-)
    
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java b/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java
    index d93d74fdc..8c536d6ca 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/InheritInfo.java
    @@ -6,6 +6,7 @@ import io.ebeaninternal.server.deploy.id.IdBinder;
     import io.ebeaninternal.server.deploy.parse.DeployInheritInfo;
     import io.ebeaninternal.server.query.SqlTreeProperties;
     
    +import java.lang.reflect.Modifier;
     import javax.persistence.PersistenceException;
     import java.sql.SQLException;
     import java.util.ArrayList;
    @@ -291,7 +292,7 @@ public class InheritInfo {
        * Return true if this is considered a concrete type in the inheritance hierarchy.
        */
       public boolean isConcrete() {
    -    return discriminatorValue != null;
    +    return !Modifier.isAbstract(type.getModifiers());
       }
     
       /**
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    index f7fe0d56c..ce6bc1853 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    @@ -126,6 +126,8 @@ public class DeployInherit {
         DiscriminatorValue dv = AnnotationUtil.findAnnotation(cls, DiscriminatorValue.class); // do not search recursive
         if (dv != null) {
           info.setDiscriminatorValue(dv.value());
    +    } else {
    +      info.setDiscriminatorValue(cls.getSimpleName());
         }
     
         return info;
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInheritInfo.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInheritInfo.java
    index a62d84692..4c645457d 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInheritInfo.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInheritInfo.java
    @@ -2,6 +2,7 @@ package io.ebeaninternal.server.deploy.parse;
     
     import io.ebeaninternal.server.deploy.InheritInfo;
     
    +import java.lang.reflect.Modifier;
     import javax.persistence.DiscriminatorType;
     import java.sql.Types;
     import java.util.ArrayList;
    @@ -64,7 +65,7 @@ public class DeployInheritInfo {
        * Return true if this is abstract node.
        */
       public boolean isAbstract() {
    -    return (discriminatorObjectValue == null);
    +    return Modifier.isAbstract(type.getModifiers());
       }
     
       /**
    @@ -205,7 +206,7 @@ public class DeployInheritInfo {
       }
     
       private void appendDiscriminator(List list) {
    -    if (discriminatorObjectValue != null) {
    +    if (!isAbstract()) {
           list.add(discriminatorObjectValue);
         }
         for (DeployInheritInfo child : children) {
    
    From d570971fd17b418e92eefbaa23cb2993ccaa7067 Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 12 Apr 2018 20:44:39 +1200
    Subject: [PATCH 0222/1036] #1363 - Update ebean-migration to 11.5.2
    
    ---
     pom.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/pom.xml b/pom.xml
    index 1b3964328..c30af3e07 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -130,7 +130,7 @@
         
           io.ebean
           ebean-migration
    -      11.5.1
    +      11.5.2
         
     
         
    
    From 12108ada38e45851cb5945d584d5f6affcc6bd83 Mon Sep 17 00:00:00 2001
    From: Rob Bygrave 
    Date: Wed, 18 Apr 2018 20:47:59 +1200
    Subject: [PATCH 0223/1036] #1363 - Update ebean-migration to 11.5.4
    
    ---
     pom.xml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/pom.xml b/pom.xml
    index c30af3e07..3be1f405c 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -130,7 +130,7 @@
         
           io.ebean
           ebean-migration
    -      11.5.2
    +      11.5.4
         
     
         
    
    From 756f867ed2ddb80a7785abe3985a82545b4f560b Mon Sep 17 00:00:00 2001
    From: Rob Bygrave 
    Date: Wed, 18 Apr 2018 21:24:37 +1200
    Subject: [PATCH 0224/1036] #1365 - Regression: property
     ebean.namingConvention=io.ebean.config.MatchingNamingConvention ... no longer
     works
    
    ---
     src/main/java/io/ebean/config/ServerConfig.java     | 2 +-
     src/test/java/io/ebean/config/ServerConfigTest.java | 3 +++
     2 files changed, 4 insertions(+), 1 deletion(-)
    
    diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java
    index 8ef5bf831..5b14d2bfc 100644
    --- a/src/main/java/io/ebean/config/ServerConfig.java
    +++ b/src/main/java/io/ebean/config/ServerConfig.java
    @@ -2871,7 +2871,7 @@ public class ServerConfig {
       }
     
       private NamingConvention createNamingConvention(PropertiesWrapper properties, NamingConvention namingConvention) {
    -    NamingConvention nc = properties.createInstance(NamingConvention.class, "namingconvention", null);
    +    NamingConvention nc = properties.createInstance(NamingConvention.class, "namingConvention", null);
         return (nc != null) ? nc : namingConvention;
       }
     
    diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java
    index 03c86481d..b404b7451 100644
    --- a/src/test/java/io/ebean/config/ServerConfigTest.java
    +++ b/src/test/java/io/ebean/config/ServerConfigTest.java
    @@ -65,6 +65,8 @@ public class ServerConfigTest {
         props.setProperty("notifyL2CacheInForeground", "true");
         props.setProperty("idType", "SEQUENCE");
         props.setProperty("mappingLocations", "classpath:/foo;bar");
    +    props.setProperty("namingConvention", "io.ebean.config.MatchingNamingConvention");
    +
     
         serverConfig.loadFromProperties(props);
     
    @@ -72,6 +74,7 @@ public class ServerConfigTest {
         assertTrue(serverConfig.isNotifyL2CacheInForeground());
         assertTrue(serverConfig.isDbOffline());
         assertTrue(serverConfig.isAutoReadOnlyDataSource());
    +    assertThat(serverConfig.getNamingConvention()).isInstanceOf(MatchingNamingConvention.class);
     
         assertEquals(IdType.SEQUENCE, serverConfig.getIdType());
         assertEquals(PersistBatch.INSERT, serverConfig.getPersistBatch());
    
    From 49d9d88fbe790c62da19ad431fd4cdfbd3ac6e61 Mon Sep 17 00:00:00 2001
    From: Roland Praml 
    Date: Fri, 27 Apr 2018 04:44:18 +0200
    Subject: [PATCH 0225/1036] FIX: load all props from cache when inheritance is
     involved (#1366)
    
    ---
     .../server/cache/CachedBeanDataToBean.java    |  4 ++
     .../org/tests/cache/TestCacheManyToOne.java   | 39 ++++++++++++++++
     .../tests/model/basic/OCachedInhChildA.java   | 30 +++++++++++++
     .../tests/model/basic/OCachedInhChildB.java   | 29 ++++++++++++
     .../org/tests/model/basic/OCachedInhRoot.java | 44 +++++++++++++++++++
     5 files changed, 146 insertions(+)
     create mode 100644 src/test/java/org/tests/cache/TestCacheManyToOne.java
     create mode 100644 src/test/java/org/tests/model/basic/OCachedInhChildA.java
     create mode 100644 src/test/java/org/tests/model/basic/OCachedInhChildB.java
     create mode 100644 src/test/java/org/tests/model/basic/OCachedInhRoot.java
    
    diff --git a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java
    index 05b2a0d1f..bb3bc4b75 100644
    --- a/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java
    +++ b/src/main/java/io/ebeaninternal/server/cache/CachedBeanDataToBean.java
    @@ -15,6 +15,10 @@ public class CachedBeanDataToBean {
         EntityBeanIntercept ebi = bean._ebean_getIntercept();
     
         BeanProperty idProperty = desc.getIdProperty();
    +    if (desc.getInheritInfo() != null) {
    +        desc = desc.getInheritInfo().readType(bean.getClass()).desc();
    +    }
    +
         if (idProperty != null) {
           // load the id property
           loadProperty(bean, cacheBeanData, ebi, idProperty, context);
    diff --git a/src/test/java/org/tests/cache/TestCacheManyToOne.java b/src/test/java/org/tests/cache/TestCacheManyToOne.java
    new file mode 100644
    index 000000000..fd6e209b0
    --- /dev/null
    +++ b/src/test/java/org/tests/cache/TestCacheManyToOne.java
    @@ -0,0 +1,39 @@
    +package org.tests.cache;
    +
    +import io.ebean.BaseTestCase;
    +import io.ebean.Ebean;
    +import org.tests.model.basic.OCachedInhChildA;
    +import org.tests.model.basic.OCachedInhRoot;
    +import org.junit.Test;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +import static org.junit.Assert.assertNotNull;
    +
    +/**
    + * Test class testing deleting/invalidating of cached beans
    + */
    +public class TestCacheManyToOne extends BaseTestCase {
    +
    +  @Test
    +  public void crudInvoice() {
    +
    +    OCachedInhChildA bean = new OCachedInhChildA();
    +    bean.setName("Roland");
    +    bean.setChildAData("ChildData");
    +    Ebean.save(bean);
    +
    +    Ebean.find(OCachedInhRoot.class).select("id").where().idIn(bean.getId()).findEach(bean0 -> {
    +      assertNotNull(bean0);
    +      assertThat(bean0.getName()).isEqualTo("Roland");
    +      assertThat(((OCachedInhChildA)bean0).getChildAData()).isEqualTo("ChildData");
    +    });
    +
    +    Ebean.find(OCachedInhRoot.class).select("id").where().idIn(bean.getId()).findEach(bean1 -> {
    +      assertNotNull(bean1);
    +      assertThat(bean1.getName()).isEqualTo("Roland");
    +      // this will fail if the bean is loaded from cache and the wrong discriminator is used.
    +      assertThat(((OCachedInhChildA)bean1).getChildAData()).isEqualTo("ChildData");
    +    });
    +
    +  }
    +}
    diff --git a/src/test/java/org/tests/model/basic/OCachedInhChildA.java b/src/test/java/org/tests/model/basic/OCachedInhChildA.java
    new file mode 100644
    index 000000000..8ec183379
    --- /dev/null
    +++ b/src/test/java/org/tests/model/basic/OCachedInhChildA.java
    @@ -0,0 +1,30 @@
    +package org.tests.model.basic;
    +
    +import javax.persistence.DiscriminatorValue;
    +import javax.persistence.Entity;
    +
    +
    +/**
    + * Child bean A
    + */
    +@Entity
    +@DiscriminatorValue("childA")
    +public class OCachedInhChildA extends OCachedInhRoot {
    +
    +  String childAData;
    +
    +  /**
    +   * @return the childAData
    +   */
    +  public String getChildAData() {
    +    return childAData;
    +  }
    +
    +  /**
    +   * @param childAData
    +   *          the childAData to set
    +   */
    +  public void setChildAData(String childAData) {
    +    this.childAData = childAData;
    +  }
    +}
    diff --git a/src/test/java/org/tests/model/basic/OCachedInhChildB.java b/src/test/java/org/tests/model/basic/OCachedInhChildB.java
    new file mode 100644
    index 000000000..1ef25a2ca
    --- /dev/null
    +++ b/src/test/java/org/tests/model/basic/OCachedInhChildB.java
    @@ -0,0 +1,29 @@
    +package org.tests.model.basic;
    +
    +import javax.persistence.DiscriminatorValue;
    +import javax.persistence.Entity;
    +
    +
    +/**
    + * Child bean B
    + */
    +@Entity
    +@DiscriminatorValue("childB")
    +public class OCachedInhChildB extends OCachedInhRoot {
    +  String childBData;
    +
    +  /**
    +   * @return the childBData
    +   */
    +  public String getChildBData() {
    +    return childBData;
    +  }
    +
    +  /**
    +   * @param childBData
    +   *          the childBData to set
    +   */
    +  public void setChildBData(String childBData) {
    +    this.childBData = childBData;
    +  }
    +}
    diff --git a/src/test/java/org/tests/model/basic/OCachedInhRoot.java b/src/test/java/org/tests/model/basic/OCachedInhRoot.java
    new file mode 100644
    index 000000000..1027070cc
    --- /dev/null
    +++ b/src/test/java/org/tests/model/basic/OCachedInhRoot.java
    @@ -0,0 +1,44 @@
    +package org.tests.model.basic;
    +
    +import javax.persistence.Entity;
    +import javax.persistence.Id;
    +import javax.persistence.Inheritance;
    +import javax.persistence.Table;
    +
    +import io.ebean.annotation.Cache;
    +
    +/**
    + * Cached entity for inheritance.
    + *
    + * @author Roland Praml, FOCONIS AG
    + */
    +@Entity
    +@Table(name = "o_cached_inherit")
    +@Inheritance
    +@Cache
    +public abstract class OCachedInhRoot {
    +
    +  @Id
    +  Long id;
    +
    +  String name;
    +
    +  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;
    +  }
    +
    +
    +
    +}
    
    From 33031d1c698e8a81d1e7a9b5cd66d22fd62778ad Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Sun, 6 May 2018 20:21:10 +1200
    Subject: [PATCH 0226/1036] #1369 - BeanListener and/or BeanPersistAdapter not
     fired on delete of children when cascaded
    
    ---
     .../server/deploy/BeanDescriptor.java         | 10 +++-
     .../server/persist/DefaultPersister.java      | 18 ++++--
     src/test/java/org/tests/delete/DcDetail.java  | 51 ++++++++++++++++
     .../java/org/tests/delete/DcListener.java     | 28 +++++++++
     src/test/java/org/tests/delete/DcMaster.java  | 59 +++++++++++++++++++
     .../delete/TestDeleteCascadeWithListener.java | 51 ++++++++++++++++
     6 files changed, 211 insertions(+), 6 deletions(-)
     create mode 100644 src/test/java/org/tests/delete/DcDetail.java
     create mode 100644 src/test/java/org/tests/delete/DcListener.java
     create mode 100644 src/test/java/org/tests/delete/DcMaster.java
     create mode 100644 src/test/java/org/tests/delete/TestDeleteCascadeWithListener.java
    
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    index 1bc379e7e..e34020a10 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    @@ -1723,7 +1723,15 @@ public class BeanDescriptor implements BeanType, STreeType {
        * associated L2 bean caching.
        */
       public boolean isDeleteByStatement() {
    -    return deleteRecurseSkippable && !isBeanCaching();
    +    return persistListener == null
    +      && persistController == null
    +      && deleteRecurseSkippable && !isBeanCaching();
    +  }
    +
    +  public boolean isDeleteByBulk() {
    +    return persistListener == null
    +      && persistController == null
    +      && propertiesManyToMany.length == 0;
       }
     
       /**
    diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
    index c3cb2dcda..f7688d7a5 100644
    --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
    +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java
    @@ -588,10 +588,18 @@ public final class DefaultPersister implements Persister {
         }
       }
     
    -  private void deleteList(List beanList, Transaction t, boolean softDelete) {
    +  private void deleteList(List beanList, SpiTransaction t, boolean softDelete, boolean children) {
    +    if (children) {
    +      t.depth(-1);
    +      t.checkBatchEscalationOnCollection();
    +    }
         for (Object aBeanList : beanList) {
           deleteRecurse((EntityBean) aBeanList, t, softDelete);
         }
    +    if (children) {
    +      t.flushBatchOnCollection();
    +      t.depth(+1);
    +    }
       }
     
       /**
    @@ -675,7 +683,7 @@ public final class DefaultPersister implements Persister {
                 t.logSummary("-- DeleteById of " + descriptor.getName() + " ids[" + idList + "] requires fetch of foreign key values");
               }
               List beanList = server.findList(q, t);
    -          deleteList(beanList, t, softDelete);
    +          deleteList(beanList, t, softDelete, false);
               return beanList.size();
     
             } else {
    @@ -1012,7 +1020,7 @@ public final class DefaultPersister implements Persister {
           // cascade delete the beans in the collection
           BeanDescriptor targetDesc = many.getTargetDescriptor();
           if (!softDelete || targetDesc.isSoftDelete()) {
    -        if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isBeanCaching()) {
    +        if (targetDesc.isDeleteByStatement()) {
               // Just delete all the children with one statement
               IntersectionRow intRow = many.buildManyDeleteChildren(parentBean, excludeDetailIds);
               SqlUpdate sqlDelete = intRow.createDelete(server, softDelete);
    @@ -1037,13 +1045,13 @@ public final class DefaultPersister implements Persister {
        */
       private void deleteChildrenById(SpiTransaction t, BeanDescriptor targetDesc, List childIds, boolean softDelete) {
     
    -    if (targetDesc.propertiesManyToMany().length > 0) {
    +    if (!targetDesc.isDeleteByBulk()) {
           // convert into a list of reference objects and perform delete by object
           List refList = new ArrayList<>(childIds.size());
           for (Object id : childIds) {
             refList.add(targetDesc.createReference(id, null));
           }
    -      deleteList(refList, t, softDelete);
    +      deleteList(refList, t, softDelete, true);
     
         } else {
           // perform delete by statement if possible
    diff --git a/src/test/java/org/tests/delete/DcDetail.java b/src/test/java/org/tests/delete/DcDetail.java
    new file mode 100644
    index 000000000..e49cc58bc
    --- /dev/null
    +++ b/src/test/java/org/tests/delete/DcDetail.java
    @@ -0,0 +1,51 @@
    +package org.tests.delete;
    +
    +import javax.persistence.Entity;
    +import javax.persistence.Id;
    +import javax.persistence.ManyToOne;
    +
    +@Entity
    +public class DcDetail {
    +
    +  @Id
    +  long id;
    +
    +  @ManyToOne
    +  DcMaster master;
    +
    +  String description;
    +
    +  long version;
    +
    +  public long getId() {
    +    return id;
    +  }
    +
    +  public void setId(long id) {
    +    this.id = id;
    +  }
    +
    +  public DcMaster getMaster() {
    +    return master;
    +  }
    +
    +  public void setMaster(DcMaster master) {
    +    this.master = master;
    +  }
    +
    +  public String getDescription() {
    +    return description;
    +  }
    +
    +  public void setDescription(String description) {
    +    this.description = description;
    +  }
    +
    +  public long getVersion() {
    +    return version;
    +  }
    +
    +  public void setVersion(long version) {
    +    this.version = version;
    +  }
    +}
    diff --git a/src/test/java/org/tests/delete/DcListener.java b/src/test/java/org/tests/delete/DcListener.java
    new file mode 100644
    index 000000000..5e4191ab0
    --- /dev/null
    +++ b/src/test/java/org/tests/delete/DcListener.java
    @@ -0,0 +1,28 @@
    +package org.tests.delete;
    +
    +import io.ebean.event.AbstractBeanPersistListener;
    +
    +import java.util.ArrayList;
    +import java.util.Collections;
    +import java.util.List;
    +
    +public class DcListener extends AbstractBeanPersistListener {
    +
    +  static List deleted = Collections.synchronizedList(new ArrayList<>());
    +
    +  @Override
    +  public boolean isRegisterFor(Class cls) {
    +    return cls.equals(DcDetail.class);
    +  }
    +
    +  @Override
    +  public void deleted(Object bean) {
    +    deleted.add(bean);
    +  }
    +
    +  static List deletedBeans() {
    +    List copy = new ArrayList<>(deleted);
    +    deleted.clear();
    +    return copy;
    +  }
    +}
    diff --git a/src/test/java/org/tests/delete/DcMaster.java b/src/test/java/org/tests/delete/DcMaster.java
    new file mode 100644
    index 000000000..e1c8d0144
    --- /dev/null
    +++ b/src/test/java/org/tests/delete/DcMaster.java
    @@ -0,0 +1,59 @@
    +package org.tests.delete;
    +
    +import javax.persistence.CascadeType;
    +import javax.persistence.Entity;
    +import javax.persistence.Id;
    +import javax.persistence.OneToMany;
    +import javax.persistence.Version;
    +import java.util.List;
    +
    +@Entity
    +public class DcMaster {
    +
    +  @Id
    +  long id;
    +
    +  String name;
    +
    +  @OneToMany(mappedBy = "master", cascade = CascadeType.ALL)
    +  List details;
    +
    +  @Version
    +  long version;
    +
    +  public DcMaster(String name) {
    +    this.name = name;
    +  }
    +
    +  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 getDetails() {
    +    return details;
    +  }
    +
    +  public void setDetails(List details) {
    +    this.details = details;
    +  }
    +
    +  public long getVersion() {
    +    return version;
    +  }
    +
    +  public void setVersion(long version) {
    +    this.version = version;
    +  }
    +}
    diff --git a/src/test/java/org/tests/delete/TestDeleteCascadeWithListener.java b/src/test/java/org/tests/delete/TestDeleteCascadeWithListener.java
    new file mode 100644
    index 000000000..56d47e5ea
    --- /dev/null
    +++ b/src/test/java/org/tests/delete/TestDeleteCascadeWithListener.java
    @@ -0,0 +1,51 @@
    +package org.tests.delete;
    +
    +import io.ebean.BaseTestCase;
    +import io.ebean.Ebean;
    +import org.ebeantest.LoggedSqlCollector;
    +import org.junit.Test;
    +
    +import java.util.List;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +
    +public class TestDeleteCascadeWithListener extends BaseTestCase {
    +
    +  @Test
    +  public void test() {
    +
    +    DcMaster m0 = new DcMaster("m0");
    +    m0.getDetails().add(new DcDetail());
    +    m0.getDetails().add(new DcDetail());
    +    m0.getDetails().add(new DcDetail());
    +
    +    Ebean.save(m0);
    +
    +    DcMaster found = Ebean.find(DcMaster.class, m0.getId());
    +
    +    LoggedSqlCollector.start();
    +    Ebean.delete(found);
    +
    +    List sql = LoggedSqlCollector.stop();
    +    assertThat(sql).hasSize(5);
    +
    +    assertThat(sql.get(0)).contains("select t0.id from dc_detail t0 where master_id=?");
    +    assertThat(sql.get(1)).contains("delete from dc_detail where id=?");
    +    assertThat(sql.get(3)).contains("delete from dc_detail where id=?");
    +    assertThat(sql.get(4)).contains("delete from dc_master where id=? and version=?");
    +
    +    awaitListenerPropagation();
    +
    +    List beans = DcListener.deletedBeans();
    +    assertThat(beans).hasSize(3);
    +  }
    +
    +  private void awaitListenerPropagation() {
    +    try {
    +      Thread.sleep(200);
    +    } catch (InterruptedException e) {
    +      Thread.currentThread().interrupt();
    +      throw new RuntimeException(e);
    +    }
    +  }
    +}
    
    From 1a2ca63d65c70e4a06c47f7b65f4a2e5f3954569 Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Sun, 6 May 2018 20:50:40 +1200
    Subject: [PATCH 0227/1036] [maven-release-plugin] prepare release
     ebean-11.15.5
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index 3be1f405c..ba7bc573b 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.5-SNAPSHOT
    +  11.15.5
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    HEAD
    +    ebean-11.15.5
       
     
       
    
    From 111bac751460b02520bb2f25919ebf8af4ed3445 Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Sun, 6 May 2018 20:50:56 +1200
    Subject: [PATCH 0228/1036] [maven-release-plugin] prepare for next development
     iteration
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index ba7bc573b..82420d5e4 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.5
    +  11.15.6-SNAPSHOT
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    ebean-11.15.5
    +    HEAD
       
     
       
    
    From cfaedcdbc50a63001f9ba3330b9cb4136c5169af Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 10 May 2018 17:20:09 +1200
    Subject: [PATCH 0229/1036] #1371 - Regression in 11.15.5 with @Inheritance on
     abstract class with discriminatorType = INTEGER
    
    ---
     .../server/deploy/parse/DeployInherit.java    | 13 ++---
     .../abstrakt/AbstractBaseBlock.java           | 48 +++++++++++++++++++
     .../org/tests/inheritance/abstrakt/Block.java | 19 ++++++++
     .../abstrakt/TestInheritanceNum.java          | 18 +++++++
     4 files changed, 92 insertions(+), 6 deletions(-)
     create mode 100644 src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java
     create mode 100644 src/test/java/org/tests/inheritance/abstrakt/Block.java
     create mode 100644 src/test/java/org/tests/inheritance/abstrakt/TestInheritanceNum.java
    
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    index ce6bc1853..749d597f1 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployInherit.java
    @@ -123,13 +123,14 @@ public class DeployInherit {
           info.setColumnDefn(da.columnDefinition());
         }
     
    -    DiscriminatorValue dv = AnnotationUtil.findAnnotation(cls, DiscriminatorValue.class); // do not search recursive
    -    if (dv != null) {
    -      info.setDiscriminatorValue(dv.value());
    -    } else {
    -      info.setDiscriminatorValue(cls.getSimpleName());
    +    if (!info.isAbstract()) {
    +      DiscriminatorValue dv = AnnotationUtil.findAnnotation(cls, DiscriminatorValue.class); // do not search recursive
    +      if (dv != null) {
    +        info.setDiscriminatorValue(dv.value());
    +      } else {
    +        info.setDiscriminatorValue(cls.getSimpleName());
    +      }
         }
    -
         return info;
       }
     
    diff --git a/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java b/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java
    new file mode 100644
    index 000000000..334752405
    --- /dev/null
    +++ b/src/test/java/org/tests/inheritance/abstrakt/AbstractBaseBlock.java
    @@ -0,0 +1,48 @@
    +package org.tests.inheritance.abstrakt;
    +
    +import javax.persistence.DiscriminatorColumn;
    +import javax.persistence.DiscriminatorType;
    +import javax.persistence.Entity;
    +import javax.persistence.Id;
    +import javax.persistence.Inheritance;
    +import javax.persistence.Table;
    +import javax.persistence.Version;
    +
    +@Entity
    +@Table(name = "block")
    +@Inheritance
    +@DiscriminatorColumn(name = "case_type", discriminatorType = DiscriminatorType.INTEGER)
    +public abstract class AbstractBaseBlock {
    +
    +  @Id
    +  long id;
    +
    +  String name;
    +
    +  @Version
    +  long version;
    +
    +  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 long getVersion() {
    +    return version;
    +  }
    +
    +  public void setVersion(long version) {
    +    this.version = version;
    +  }
    +}
    diff --git a/src/test/java/org/tests/inheritance/abstrakt/Block.java b/src/test/java/org/tests/inheritance/abstrakt/Block.java
    new file mode 100644
    index 000000000..ea0297de1
    --- /dev/null
    +++ b/src/test/java/org/tests/inheritance/abstrakt/Block.java
    @@ -0,0 +1,19 @@
    +package org.tests.inheritance.abstrakt;
    +
    +import javax.persistence.DiscriminatorValue;
    +import javax.persistence.Entity;
    +
    +@Entity
    +@DiscriminatorValue(value = "2")
    +public class Block extends AbstractBaseBlock {
    +
    +  String notes;
    +
    +  public String getNotes() {
    +    return notes;
    +  }
    +
    +  public void setNotes(String notes) {
    +    this.notes = notes;
    +  }
    +}
    diff --git a/src/test/java/org/tests/inheritance/abstrakt/TestInheritanceNum.java b/src/test/java/org/tests/inheritance/abstrakt/TestInheritanceNum.java
    new file mode 100644
    index 000000000..42f36d263
    --- /dev/null
    +++ b/src/test/java/org/tests/inheritance/abstrakt/TestInheritanceNum.java
    @@ -0,0 +1,18 @@
    +package org.tests.inheritance.abstrakt;
    +
    +import io.ebean.BaseTestCase;
    +import io.ebean.Ebean;
    +import org.junit.Test;
    +
    +public class TestInheritanceNum extends BaseTestCase {
    +
    +  @Test
    +  public void basicIUD() {
    +
    +    Block block = new Block();
    +    block.setName("ibe");
    +    block.setNotes("try it");
    +
    +    Ebean.save(block);
    +  }
    +}
    
    From fc837b6472f885151b024b10b9711b309f945c4b Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 10 May 2018 17:22:04 +1200
    Subject: [PATCH 0230/1036] [maven-release-plugin] prepare release
     ebean-11.15.6
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index 82420d5e4..7d9f96601 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.6-SNAPSHOT
    +  11.15.6
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    HEAD
    +    ebean-11.15.6
       
     
       
    
    From f8c80c7fd219f12f1dda9a79ee8f75542396e474 Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Thu, 10 May 2018 17:22:18 +1200
    Subject: [PATCH 0231/1036] [maven-release-plugin] prepare for next development
     iteration
    
    ---
     pom.xml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/pom.xml b/pom.xml
    index 7d9f96601..1d881bfc1 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -9,7 +9,7 @@
     
       io.ebean
       ebean
    -  11.15.6
    +  11.15.7-SNAPSHOT
       jar
     
       ebean
    @@ -17,7 +17,7 @@
     
       
         scm:git:git@github.com:ebean-orm/ebean.git
    -    ebean-11.15.6
    +    HEAD
       
     
       
    
    From 0a49fc9b6299545947b759e67fc23973d541dc64 Mon Sep 17 00:00:00 2001
    From: Roland Praml 
    Date: Mon, 14 May 2018 11:12:42 +0200
    Subject: [PATCH 0232/1036] FIX: NPE when fetching inherited beans from cache
     (#1373)
    
    ---
     .../server/deploy/BeanDescriptor.java         | 11 ++++
     .../cache/TestInheritanceRefCache.java        | 64 +++++++++++++++++++
     .../org/tests/model/basic/cache/CInhRef.java  | 25 ++++++++
     3 files changed, 100 insertions(+)
     create mode 100644 src/test/java/org/tests/inheritance/cache/TestInheritanceRefCache.java
     create mode 100644 src/test/java/org/tests/model/basic/cache/CInhRef.java
    
    diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    index e34020a10..0a75df76c 100644
    --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java
    @@ -71,6 +71,7 @@ import io.ebeaninternal.server.query.STreePropertyAssocMany;
     import io.ebeaninternal.server.query.STreePropertyAssocOne;
     import io.ebeaninternal.server.query.STreeType;
     import io.ebeaninternal.server.query.SqlBeanLoad;
    +import io.ebeaninternal.server.querydefn.DefaultOrmQuery;
     import io.ebeaninternal.server.querydefn.OrmQueryDetail;
     import io.ebeaninternal.server.rawsql.SpiRawSql;
     import io.ebeaninternal.server.type.DataBind;
    @@ -1878,6 +1879,9 @@ public class BeanDescriptor implements BeanType, STreeType {
        * on first access (lazy load) or immediately (eager load)
        */
       public EntityBean createEntityBean(boolean isNew) {
    +    if (prototypeEntityBean == null) {
    +      throw new UnsupportedOperationException("cannot create entity bean for abstract entity " + getName());
    +    }
         try {
           EntityBean bean = (EntityBean) prototypeEntityBean._ebean_newInstance();
     
    @@ -1969,6 +1973,13 @@ public class BeanDescriptor implements BeanType, STreeType {
       public T createReference(Object id, PersistenceContext pc) {
     
         try {
    +      if (inheritInfo != null && !inheritInfo.isConcrete()) {
    +        // we actually need to do a query because we don't know the type without the discriminator
    +        // value, just select the id property and discriminator column (auto added)
    +        DefaultOrmQuery query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
    +        return query.select(getIdProperty().getName()).setId(id).findOne();
    +      }
    +
           EntityBean eb = createEntityBean();
           id = convertSetId(id, eb);
           EntityBeanIntercept ebi = eb._ebean_getIntercept();
    diff --git a/src/test/java/org/tests/inheritance/cache/TestInheritanceRefCache.java b/src/test/java/org/tests/inheritance/cache/TestInheritanceRefCache.java
    new file mode 100644
    index 000000000..1f45212eb
    --- /dev/null
    +++ b/src/test/java/org/tests/inheritance/cache/TestInheritanceRefCache.java
    @@ -0,0 +1,64 @@
    +package org.tests.inheritance.cache;
    +
    +import io.ebean.BaseTestCase;
    +import io.ebean.Ebean;
    +import org.tests.model.basic.cache.CInhOne;
    +import org.tests.model.basic.cache.CInhRef;
    +import org.junit.Test;
    +
    +import static org.assertj.core.api.Assertions.assertThat;
    +
    +import java.util.List;
    +
    +import org.ebeantest.LoggedSqlCollector;
    +
    +public class TestInheritanceRefCache extends BaseTestCase {
    +
    +  @Test
    +  public void test() {
    +
    +    CInhOne one = new CInhOne();
    +    one.setLicenseNumber("O12");
    +    one.setDriver("Jimmy");
    +    one.setNotes("Hello");
    +
    +    Ebean.save(one);
    +
    +    CInhRef ref = new CInhRef();
    +    ref.setRef(one);
    +
    +    Ebean.save(ref);
    +
    +    Integer id = ref.getId();
    +
    +    LoggedSqlCollector.start();
    +    CInhRef gotRef = Ebean.find(CInhRef.class).setId(id).findOne();
    +
    +    assertThat(gotRef).isInstanceOf(CInhRef.class);
    +    assertThat(gotRef.getRef()).isInstanceOf(CInhOne.class);
    +    List sql = LoggedSqlCollector.stop();
    +    assertThat(sql).hasSize(1);
    +    assertThat(sql.get(0)).contains("from cinh_ref").contains("left join cinh_root");
    +
    +    // fetch again - from cache (but fetch second bean from cache)
    +    LoggedSqlCollector.start();
    +    gotRef = Ebean.find(CInhRef.class).setId(id).findOne();
    +
    +    assertThat(gotRef).isInstanceOf(CInhRef.class);
    +    assertThat(gotRef.getRef()).isInstanceOf(CInhOne.class);
    +    sql = LoggedSqlCollector.stop();
    +    assertThat(sql).hasSize(1);
    +    assertThat(sql.get(0)).contains("from cinh_root");
    +
    +
    +    // fetch again - both from cache
    +    LoggedSqlCollector.start();
    +    gotRef = Ebean.find(CInhRef.class).setId(id).findOne();
    +
    +    assertThat(gotRef).isInstanceOf(CInhRef.class);
    +    assertThat(gotRef.getRef()).isInstanceOf(CInhOne.class);
    +    sql = LoggedSqlCollector.stop();
    +    assertThat(sql).hasSize(0);
    +
    +  }
    +}
    diff --git a/src/test/java/org/tests/model/basic/cache/CInhRef.java b/src/test/java/org/tests/model/basic/cache/CInhRef.java
    new file mode 100644
    index 000000000..63e918724
    --- /dev/null
    +++ b/src/test/java/org/tests/model/basic/cache/CInhRef.java
    @@ -0,0 +1,25 @@
    +package org.tests.model.basic.cache;
    +
    +import org.tests.model.basic.BasicDomain;
    +
    +import io.ebean.annotation.Cache;
    +
    +import javax.persistence.Entity;
    +import javax.persistence.ManyToOne;
    +
    +@Entity
    +@Cache(enableQueryCache = true)
    +public class CInhRef extends BasicDomain {
    +  private static final long serialVersionUID = -4673953370819311120L;
    +
    +  @ManyToOne(cascade = {})
    +  private CInhRoot ref;
    +
    +  public CInhRoot getRef() {
    +    return ref;
    +  }
    +
    +  public void setRef(CInhRoot ref) {
    +    this.ref = ref;
    +  }
    +}
    
    From 95737cd3c56f9adab311510fab0b4e3bac020a7d Mon Sep 17 00:00:00 2001
    From: rob bygrave 
    Date: Mon, 14 May 2018 21:23:13 +1200
    Subject: [PATCH 0233/1036] #1374 - Remove
     io.ebeaninternal.server.core.ServletContextListener - should be unused
    
    ---
     pom.xml                                       |  7 ----
     .../server/core/ServletContextListener.java   | 32 -------------------
     2 files changed, 39 deletions(-)
     delete mode 100644 src/main/java/io/ebeaninternal/server/core/ServletContextListener.java
    
    diff --git a/pom.xml b/pom.xml
    index 1d881bfc1..353b0f6c7 100644
    --- a/pom.xml
    +++ b/pom.xml
    @@ -169,13 +169,6 @@
           provided
         
     
    -    
    -      javax.servlet
    -      javax.servlet-api
    -      3.1.0
    -      provided
    -    
    -
         
           joda-time
           joda-time
    diff --git a/src/main/java/io/ebeaninternal/server/core/ServletContextListener.java b/src/main/java/io/ebeaninternal/server/core/ServletContextListener.java
    deleted file mode 100644
    index e77aa24f2..000000000
    --- a/src/main/java/io/ebeaninternal/server/core/ServletContextListener.java
    +++ /dev/null
    @@ -1,32 +0,0 @@
    -package io.ebeaninternal.server.core;
    -
    -import io.ebeaninternal.server.lib.ShutdownManager;
    -
    -import javax.servlet.ServletContextEvent;
    -
    -/**
    - * Listens for webserver server starting and stopping events.
    - * 

    - * Register this listener in the web.xml configuration file. This will listen - * for startup and shutdown events. - *

    - */ -public class ServletContextListener implements javax.servlet.ServletContextListener { - - /** - * The servlet container is stopping. - */ - @Override - public void contextDestroyed(ServletContextEvent event) { - ShutdownManager.shutdown(); - } - - /** - * Do nothing on startup. - */ - @Override - public void contextInitialized(ServletContextEvent event) { - - } - -} From 9dc5ca602c8a657bdd4872871038c7b90307cc9b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 21:32:48 +1200 Subject: [PATCH 0234/1036] #1372 - Missing @OneToOne mapping yields unusable error messages. --- .../io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java | 4 ++++ src/test/java/org/tests/model/basic/OrderAggregate.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 4cea3315a..25f84abe1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -310,6 +310,10 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr String discProperty = prefix + "." + discriminatorColumn; selectChain.add(discProperty); } + if (targetIdBinder == null) { + throw new IllegalStateException("No Id binding property for " + getFullBeanName() + + ". Probably a missing @OneToOne mapping annotation on this relationship?"); + } targetIdBinder.buildRawSqlSelectChain(prefix, selectChain); } else { diff --git a/src/test/java/org/tests/model/basic/OrderAggregate.java b/src/test/java/org/tests/model/basic/OrderAggregate.java index 364d94f2f..f67614b35 100644 --- a/src/test/java/org/tests/model/basic/OrderAggregate.java +++ b/src/test/java/org/tests/model/basic/OrderAggregate.java @@ -16,7 +16,7 @@ import javax.persistence.OneToOne; @Sql public class OrderAggregate { - @OneToOne + //@OneToOne Order order; Double maxAmount; From 89789f3347ce528ef2fb27ddba1d299474aa14ea Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 21:33:11 +1200 Subject: [PATCH 0235/1036] #1372 - Missing @OneToOne mapping yields unusable error messages. Restore mapping. --- src/test/java/org/tests/model/basic/OrderAggregate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/tests/model/basic/OrderAggregate.java b/src/test/java/org/tests/model/basic/OrderAggregate.java index f67614b35..364d94f2f 100644 --- a/src/test/java/org/tests/model/basic/OrderAggregate.java +++ b/src/test/java/org/tests/model/basic/OrderAggregate.java @@ -16,7 +16,7 @@ import javax.persistence.OneToOne; @Sql public class OrderAggregate { - //@OneToOne + @OneToOne Order order; Double maxAmount; From 53a80c7dd15713c18f9be007869e39a651f4025d Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 22:10:18 +1200 Subject: [PATCH 0236/1036] [maven-release-plugin] prepare release ebean-11.15.7 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 353b0f6c7..9dfe4b51a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.7-SNAPSHOT + 11.15.7 jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.15.7 From 927fa5f7d31d6268c9b78ec9601f48bdf0871359 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 22:10:34 +1200 Subject: [PATCH 0237/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9dfe4b51a..8e656ace1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.15.7 + 11.15.8-SNAPSHOT jar ebean @@ -17,7 +17,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.15.7 + HEAD From 0e9782e6b32cf971ba2cee54903d0297603d0f18 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 22:15:58 +1200 Subject: [PATCH 0238/1036] #1376 - Bump dependency - jackson-core from 2.9.0 to 2.9.5 --- pom.xml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8e656ace1..0cbd3d6b1 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,10 @@ ebean http://ebean-orm.github.io/ + + 2.9.5 + + scm:git:git@github.com:ebean-orm/ebean.git HEAD @@ -143,14 +147,14 @@ com.fasterxml.jackson.core jackson-core - 2.9.0 + ${jackson-core.version} com.fasterxml.jackson.core jackson-databind - 2.9.0 + ${jackson-core.version} provided From cdfcbeec43eee129d93e729792ba331a1d70103b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 14 May 2018 22:17:27 +1200 Subject: [PATCH 0239/1036] #1377 - Bump dependency - jsnakeyaml 1.19 to 1.21 --- pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0cbd3d6b1..f2e3c6e4d 100644 --- a/pom.xml +++ b/pom.xml @@ -17,6 +17,7 @@ 2.9.5 + 1.21 @@ -93,7 +94,7 @@ org.yaml snakeyaml - 1.19 + ${snakeyaml.version} @@ -99,6 +107,8 @@ + + @@ -125,6 +135,18 @@ + + + + + + + + + + + + @@ -157,6 +179,8 @@ + + @@ -216,6 +240,10 @@ + + + + @@ -236,8 +264,8 @@ - - + + @@ -269,11 +297,14 @@ - - + + + + + @@ -310,6 +341,7 @@ + diff --git a/src/main/resources/ebean-extraddl-1.0.xsd b/src/main/resources/ebean-extraddl-1.0.xsd index b9b39bb02..93a7090d4 100644 --- a/src/main/resources/ebean-extraddl-1.0.xsd +++ b/src/main/resources/ebean-extraddl-1.0.xsd @@ -18,6 +18,8 @@ + + diff --git a/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml index 72f3ef7ab..5a2e4d63d 100644 --- a/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml +++ b/src/test/resources/dbmigration/migrationtest/model/1.1.model.xml @@ -15,15 +15,21 @@ - -- rename all collisions + + -- rename all collisions + - insert into migtest_e_user (id) select distinct user_id from migtest_e_basic + + insert into migtest_e_user (id) select distinct user_id from migtest_e_basic + - update ${table} set ${column} = old_boolean + + update ${table} set ${column} = old_boolean + @@ -31,14 +37,16 @@ - - - - + + + + - alter table ${table} alter column ${column} TYPE bigint USING (${column}::integer) + + alter table ${table} alter column ${column} TYPE bigint USING (${column}::integer) + diff --git a/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml b/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml index 02d4777ba..d32d725be 100644 --- a/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml +++ b/src/test/resources/dbmigration/migrationtest/model/1.3.model.xml @@ -18,8 +18,8 @@ - - + + From 1d678576f77c847092fdd230d041c7042373a3fb Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 8 Aug 2018 23:33:57 +1200 Subject: [PATCH 0414/1036] [maven-release-plugin] prepare release ebean-11.20.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d07b0a928..91f8576b4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.20.1-SNAPSHOT + 11.20.1 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.20.1 From 19756421adfa42219f44da7882c38cac17642054 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 8 Aug 2018 23:34:11 +1200 Subject: [PATCH 0415/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 91f8576b4..f2f64fa2f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.20.1 + 11.20.2-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.20.1 + HEAD From db35f0f5ed8f1a815bc0b188988d45da11dc1d93 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 9 Aug 2018 21:34:23 +1200 Subject: [PATCH 0416/1036] #1466 - With ebean.dbSchema property (aka default db schema) we should not connection.setSchema() when running migrations --- pom.xml | 2 +- .../io/ebean/config/DbMigrationConfig.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index f2f64fa2f..764c2b2e5 100644 --- a/pom.xml +++ b/pom.xml @@ -135,7 +135,7 @@ io.ebean ebean-migration - 11.8.1 + 11.8.2 diff --git a/src/main/java/io/ebean/config/DbMigrationConfig.java b/src/main/java/io/ebean/config/DbMigrationConfig.java index f40f6f58d..d09f3430a 100644 --- a/src/main/java/io/ebean/config/DbMigrationConfig.java +++ b/src/main/java/io/ebean/config/DbMigrationConfig.java @@ -107,6 +107,11 @@ public class DbMigrationConfig { */ protected String dbSchema; + /** + * Set to true if we consider this the 'default schema' (Postgres schema that matches DB username) + */ + protected boolean defaultDbSchema; + /** * DB user used to run the DB migration. */ @@ -400,9 +405,15 @@ public class DbMigrationConfig { * Set the Db schema if it hasn't already been defined. */ public void setDefaultDbSchema(String dbSchema) { - if (this.dbSchema == null) { - this.dbSchema = dbSchema; - } + this.defaultDbSchema = true; + this.dbSchema = dbSchema; + } + + /** + * Return true if this is considered the default DB schema (Postgres schema matching DB username). + */ + public boolean isDefaultDbSchema() { + return defaultDbSchema; } /** @@ -591,6 +602,9 @@ public class DbMigrationConfig { runnerConfig.setDbUsername(getDbUsername()); runnerConfig.setDbPassword(getDbPassword()); runnerConfig.setDbSchema(getDbSchema()); + if (defaultDbSchema) { + runnerConfig.setSetCurrentSchema(false); + } runnerConfig.setClassLoader(classLoader); if (patchInsertOn != null) { runnerConfig.setPatchInsertOn(patchInsertOn); From afb76793027d2eb3540547d9e7d66b3df91bc454 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 10 Aug 2018 14:52:42 +1200 Subject: [PATCH 0417/1036] #1468 - ENH: Add built-in DDL generation for Postgres table partitioning (by day, week, month and year) (#1469) --- .../config/dbplatform/DatabasePlatform.java | 15 ++ .../dbplatform/postgres/PostgresPlatform.java | 32 +++ .../io/ebean/dbmigration/DbMigration.java | 5 + .../dbmigration/DdlGenerator.java | 43 ++++ .../dbmigration/DefaultDbMigration.java | 32 ++- .../dbmigration/model/CurrentModel.java | 38 ++- .../dbmigration/model/MTable.java | 18 ++ .../dbmigration/model/ModelContainer.java | 20 ++ .../extraddl/model/ExtraDdlXmlReader.java | 20 ++ .../builtin-extra-ddl-partitioning.xml | 242 ++++++++++++++++++ 10 files changed, 444 insertions(+), 21 deletions(-) create mode 100644 src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index ecc211289..ff887d038 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -2,6 +2,7 @@ package io.ebean.config.dbplatform; import io.ebean.BackgroundExecutor; import io.ebean.Query; +import io.ebean.annotation.PartitionMode; import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; import io.ebean.config.CustomDbTypeMapping; @@ -706,6 +707,20 @@ public class DatabasePlatform { } } + /** + * Return true if partitions exist for the given table. + */ + public boolean tablePartitionsExist(Connection connection, String table) throws SQLException { + return true; + } + + /** + * Return the SQL to create an initial partition for the given table. + */ + public String tablePartitionInit(String tableName, PartitionMode mode, String property, String singlePrimaryKey) { + return null; + } + /** * Escapes the like string for this DB-Platform */ diff --git a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java index 75a395568..fde6f7af3 100644 --- a/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/postgres/PostgresPlatform.java @@ -2,6 +2,7 @@ package io.ebean.config.dbplatform.postgres; import io.ebean.BackgroundExecutor; import io.ebean.Query; +import io.ebean.annotation.PartitionMode; import io.ebean.annotation.Platform; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; @@ -11,6 +12,10 @@ import io.ebean.config.dbplatform.PlatformIdGenerator; import io.ebean.config.dbplatform.SqlErrorCodes; import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Types; /** @@ -116,4 +121,31 @@ public class PostgresPlatform extends DatabasePlatform { return sql + " for update"; } } + + @Override + public boolean tablePartitionsExist(Connection connection, String table) throws SQLException { + + try (PreparedStatement statement = connection.prepareStatement("select count(*) from pg_inherits i WHERE i.inhparent = ?::regclass")) { + statement.setString(1, table); + try (ResultSet resultSet = statement.executeQuery()) { + return resultSet.next() && resultSet.getInt(1) > 0; + } + } + } + + /** + * Return SQL using built in partition helper functions to create some initial partitions. + * + * Only use this if extra-dll doesn't have some initial partitions defined (which it should). + */ + public String tablePartitionInit(String tableName, PartitionMode mode, String property, String pkey) { + if (property == null) { + property = ""; + } + if (pkey == null) { + pkey = ""; + } + return "select partition('" + mode.name().toLowerCase() + "','" + tableName + "','" + pkey + "','" + property + "',1);"; + } + } diff --git a/src/main/java/io/ebean/dbmigration/DbMigration.java b/src/main/java/io/ebean/dbmigration/DbMigration.java index 582838e79..1a1e0e9f6 100644 --- a/src/main/java/io/ebean/dbmigration/DbMigration.java +++ b/src/main/java/io/ebean/dbmigration/DbMigration.java @@ -98,6 +98,11 @@ public interface DbMigration { */ void setIncludeGeneratedFileComment(boolean includeGeneratedFileComment); + /** + * Set this to false to exclude the builtin support for table partitioning (with @DbPartition). + */ + void setIncludeBuiltInPartitioning(boolean includeBuiltInPartitioning); + /** * Set the header that is included in the generated DDL script. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java index e8edf79dc..b8271273b 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java @@ -1,11 +1,14 @@ package io.ebeaninternal.dbmigration; import io.ebean.config.ServerConfig; +import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.migration.ddl.DdlRunner; import io.ebean.util.JdbcClose; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.model.CurrentModel; +import io.ebeaninternal.dbmigration.model.MTable; import io.ebeaninternal.extraddl.model.ExtraDdlXmlReader; +import io.ebeaninternal.server.deploy.PartitionMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -180,10 +183,50 @@ public class DdlGenerator { String ignoreExtraDdl = System.getProperty("ebean.ignoreExtraDdl"); if (!"true".equalsIgnoreCase(ignoreExtraDdl) && jaxbPresent) { + if (currentModel.isTablePartitioning()) { + String extraPartitioning = ExtraDdlXmlReader.buildPartitioning(server.getDatabasePlatform().getName()); + if (extraPartitioning != null && !extraPartitioning.isEmpty()) { + runScript(connection, false, extraPartitioning, "builtin-partitioning-dll"); + } + } + String extraApply = ExtraDdlXmlReader.buildExtra(server.getDatabasePlatform().getName(), false); if (extraApply != null) { runScript(connection, false, extraApply, "extra-dll"); } + + if (currentModel.isTablePartitioning()) { + checkInitialTablePartitions(connection); + } + } + } + + /** + * Check if table partitions exist and if not create some. The expectation is that + * extra-dll.xml should have some partition initialisation but this helps people get going. + */ + private void checkInitialTablePartitions(Connection connection) { + + DatabasePlatform databasePlatform = server.getDatabasePlatform(); + try { + StringBuilder sb = new StringBuilder(); + for (MTable table : currentModel.getPartitionedTables()) { + String tableName = table.getName(); + if (!databasePlatform.tablePartitionsExist(connection, tableName)) { + log.info("No table partitions for table {}", tableName); + PartitionMeta meta = table.getPartitionMeta(); + String initPart = databasePlatform.tablePartitionInit(tableName, meta.getMode(), meta.getProperty(), table.singlePrimaryKey()); + sb.append(initPart).append("\n"); + } + } + + String initialPartitionSql = sb.toString(); + if (!initialPartitionSql.isEmpty()) { + runScript(connection, false, initialPartitionSql, "initial table partitions"); + } + + } catch (SQLException e) { + log.error("Error checking initial table partitions", e); } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index 68872221a..b73812955 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -100,6 +100,8 @@ public class DefaultDbMigration implements DbMigration { protected String name; protected String generatePendingDrop; + protected boolean includeBuiltInPartitioning = true; + /** * Create for offline migration generation. */ @@ -181,6 +183,11 @@ public class DefaultDbMigration implements DbMigration { this.includeGeneratedFileComment = includeGeneratedFileComment; } + @Override + public void setIncludeBuiltInPartitioning(boolean includeBuiltInPartitioning) { + this.includeBuiltInPartitioning = includeBuiltInPartitioning; + } + @Override public void setHeader(String header) { this.header = header; @@ -279,7 +286,7 @@ public class DefaultDbMigration implements DbMigration { try { Request request = createRequest(); if (platforms.isEmpty()) { - generateExtraDdl(request.migrationDir, databasePlatform); + generateExtraDdl(request.migrationDir, databasePlatform, request.isTablePartitioning()); } String pendingVersion = generatePendingDrop(); @@ -314,24 +321,27 @@ public class DefaultDbMigration implements DbMigration { * migration runner. *

    */ - private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform) throws IOException { + private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform, boolean tablePartitioning) throws IOException { if (dbPlatform != null) { - generateExtraDdl(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin()); - generateExtraDdl(migrationDir, dbPlatform, ExtraDdlXmlReader.read()); + if (tablePartitioning && includeBuiltInPartitioning) { + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltinTablePartitioning()); + } + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.readBuiltin()); + generateExtraDdlFor(migrationDir, dbPlatform, ExtraDdlXmlReader.read()); } } - private void generateExtraDdl(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl) throws IOException { + private void generateExtraDdlFor(File migrationDir, DatabasePlatform dbPlatform, ExtraDdl extraDdl) throws IOException { if (extraDdl != null) { List ddlScript = extraDdl.getDdlScript(); for (DdlScript script : ddlScript) { if (!script.isDrop() && ExtraDdlXmlReader.matchPlatform(dbPlatform.getName(), script.getPlatforms())) { - writeExtraDdl(migrationDir, script); - } + writeExtraDdl(migrationDir, script); } } } + } /** * Write (or override) the "repeatable" migration script. @@ -349,8 +359,6 @@ public class DefaultDbMigration implements DbMigration { } } - - private String repeatableMigrationName(boolean init, String scriptName) { StringBuilder sb = new StringBuilder(); if (init) { @@ -421,6 +429,10 @@ public class DefaultDbMigration implements DbMigration { this.current = currentModel.read(); } + boolean isTablePartitioning() { + return current.isTablePartitioning(); + } + /** * Return the migration for the pending drops for a given version. */ @@ -528,7 +540,7 @@ public class DefaultDbMigration implements DbMigration { File subPath = platformWriter.subPath(writePath, pair.prefix); platformWriter.processMigration(dbMigration, platformBuffer, subPath, fullVersion); - generateExtraDdl(subPath, pair.platform); + generateExtraDdl(subPath, pair.platform, currentModel.isTablePartitioning()); } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/CurrentModel.java b/src/main/java/io/ebeaninternal/dbmigration/model/CurrentModel.java index 8418cc8d0..1b83beb4c 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/CurrentModel.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/CurrentModel.java @@ -60,6 +60,20 @@ public class CurrentModel { this.platformTypes = platformTypes; } + /** + * Return true if the model contains tables that are partitioned. + */ + public boolean isTablePartitioning() { + return model.isTablePartitioning(); + } + + /** + * Return the tables that have partitioning. + */ + public List getPartitionedTables() { + return model.getPartitionedTables(); + } + private static DbConstraintNaming.MaxLength maxLength(SpiEbeanServer server, DbConstraintNaming naming) { if (naming.getMaxLength() != null) { @@ -116,17 +130,7 @@ public class CurrentModel { ddl.append(header).append('\n'); } - ExtraDdl extraDdl = ExtraDdlXmlReader.readBuiltin(); - if (extraDdl != null) { - List ddlScript = extraDdl.getDdlScript(); - for (DdlScript script : ddlScript) { - if (script.isInit() && ExtraDdlXmlReader.matchPlatform(server.getDatabasePlatform().getName(), script.getPlatforms())) { - ddl.append("-- init script " + script.getName()).append('\n'); - ddl.append(script.getValue()); - } - } - } - + addExtraDdl(ddl, ExtraDdlXmlReader.readBuiltin(), "-- init script "); ddl.append(write.apply().getBuffer()); ddl.append(write.applyForeignKeys().getBuffer()); @@ -136,6 +140,18 @@ public class CurrentModel { return ddl.toString(); } + private void addExtraDdl(StringBuilder ddl, ExtraDdl extraDdl, String prefix) { + if (extraDdl != null) { + List ddlScript = extraDdl.getDdlScript(); + for (DdlScript script : ddlScript) { + if (script.isInit() && ExtraDdlXmlReader.matchPlatform(server.getDatabasePlatform().getName(), script.getPlatforms())) { + ddl.append(prefix + script.getName()).append('\n'); + ddl.append(script.getValue()); + } + } + } + } + /** * Return the 'Drop' DDL. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java index 024071aea..3e3c5fa1a 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/MTable.java @@ -434,6 +434,13 @@ public class MTable { return partitionMeta != null; } + /** + * Return the partition meta for this table. + */ + public PartitionMeta getPartitionMeta() { + return partitionMeta; + } + public void setPkName(String pkName) { this.pkName = pkName; } @@ -546,6 +553,17 @@ public class MTable { return pk; } + /** + * Return the primary key column if it is a simple primary key. + */ + public String singlePrimaryKey() { + List columns = primaryKeyColumns(); + if (columns.size() == 1) { + return columns.get(0).getName(); + } + return null; + } + private void checkTableName(String tableName) { if (!name.equals(tableName)) { throw new IllegalArgumentException("addColumn tableName [" + tableName + "] does not match [" + name + "]"); diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java index 15009f5b1..f2daca21b 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java @@ -19,6 +19,7 @@ import io.ebeaninternal.dbmigration.migration.DropTable; import io.ebeaninternal.dbmigration.migration.Migration; import io.ebeaninternal.dbmigration.migration.Sql; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -43,9 +44,25 @@ public class ModelContainer { private final PendingDrops pendingDrops = new PendingDrops(); + private final List partitionedTables = new ArrayList<>(); + public ModelContainer() { } + /** + * Return true if the model contains tables that are partitioned. + */ + public boolean isTablePartitioning() { + return !partitionedTables.isEmpty(); + } + + /** + * Return the list of partitioned tables. + */ + public List getPartitionedTables() { + return partitionedTables; + } + /** * Adjust the FK references on all the draft tables. */ @@ -300,6 +317,9 @@ public class ModelContainer { * Add a table (typically from reading EbeanServer meta data). */ public MTable addTable(MTable table) { + if (table.isPartitioned()) { + partitionedTables.add(table); + } return tables.put(table.getName(), table); } diff --git a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java index 541b725a3..34b7381a5 100644 --- a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java +++ b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java @@ -26,9 +26,22 @@ public class ExtraDdlXmlReader { public static String buildExtra(String platformName, boolean drops) { ExtraDdl read = ExtraDdlXmlReader.read("/extra-ddl.xml"); + return buildExtra(platformName, drops, read); + } + + /** + * Return any extra DDL for supporting partitioning given the database platform. + */ + public static String buildPartitioning(String platformName) { + return buildExtra(platformName, false, readBuiltinTablePartitioning()); + } + + private static String buildExtra(String platformName, boolean drops, ExtraDdl read) { + if (read == null) { return null; } + StringBuilder sb = new StringBuilder(300); for (DdlScript script : read.getDdlScript()) { if (script.isDrop() == drops && matchPlatform(platformName, script.getPlatforms())) { @@ -90,6 +103,13 @@ public class ExtraDdlXmlReader { return read("/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml"); } + /** + * Read the builtin extra ddl to support table partitioning. + */ + public static ExtraDdl readBuiltinTablePartitioning() { + return read("/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml"); + } + /** * Read the extra ddl. */ diff --git a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml new file mode 100644 index 000000000..237e563cb --- /dev/null +++ b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml @@ -0,0 +1,242 @@ + + + + +-- partitioning helper functions (UTC based) + +------------------------------------------------------------------------------------ +-- Type: partition_meta +-- +-- Type used to hold common partitioning parameters such as period start and end etc +------------------------------------------------------------------------------------ +do $$ +begin + if not exists (select 1 from pg_type where typname = 'partition_meta') THEN + create type partition_meta as + ( + period_start timestamptz, + period_end timestamptz, + period_name text, + base_name text, + part_name text, + unique_column text, + index_column text + ); + end if; +end$$; + +------------------------------------------------------------------------------------ +-- Function: _partition_create +-- +-- Internal helper method to create a partition given meta data and +-- optional extra function to call (typically to create additional indexes) +------------------------------------------------------------------------------------ +create or replace function _partition_create(meta partition_meta, extra text) + returns text +language plpgsql +set timezone to 'UTC' +as $$ +begin + + execute format('create table if not exists %I partition of %I for values from (''%s'') TO (''%s'')', meta.part_name, meta.base_name, meta.period_start, meta.period_end); + + if (length(meta.unique_column) > 0) then + execute format('create unique index if not exists uq_%I ON %I (%I)', meta.part_name, meta.part_name, meta.unique_column); + end if; + + if (length(meta.index_column) > 0) then + execute format('create index if not exists ix_%I_%s ON %I (%I)', meta.part_name, meta.index_column, meta.part_name, meta.index_column); + end if; + + if (length(extra) > 0) then + execute 'select ' || extra || '($1)' using meta; + end if; + + return meta.part_name; +end; +$$; + + +------------------------------------------------------------------------------------ +-- Function: _partition_meta +-- +-- Internal helper method to create and return meta data used to create a partition. +-- Helps work out start and end periods for day, week, month and year partitions. +------------------------------------------------------------------------------------ +create or replace function _partition_meta( + mode text, + asOf date, + baseName text, + uniqueColumn text, + indexColumn text) + returns partition_meta +language plpgsql +set timezone to 'UTC' +as $$ +declare + partName text; + meta partition_meta; + asOfUtc timestamptz; +begin + asOfUtc = timezone('utc', asOf); + if (mode = 'day') then + asOfUtc = date_trunc('day', asOfUtc); + partName = to_char(asOfUtc, 'YYYY_MM_DD'); + select asOfUtc, asOfUtc + interval '1 days' into meta.period_start, meta.period_end; + + elseif (mode = 'week') then + asOfUtc = date_trunc('week', asOfUtc); + partName = format('%s_w%s', extract(ISOYEAR FROM asOfUtc), extract(WEEK FROM asOfUtc)); + select asOfUtc, asOfUtc + interval '7 days' into meta.period_start, meta.period_end; + + elseif (mode = 'year') then + asOfUtc = date_trunc('year', asOfUtc); + partName = to_char(date_trunc('year', asOfUtc), 'YYYY'); + select asOfUtc, asOfUtc + interval '1 year' into meta.period_start, meta.period_end; + + else + asOfUtc = date_trunc('month', asOfUtc); + partName = to_char(asOfUtc, 'YYYY_MM'); + select asOfUtc, asOfUtc + interval '1 month' into meta.period_start, meta.period_end; + end if; + + select partName, baseName, format('%s_%s', baseName, partName), uniqueColumn, indexColumn + into meta.period_name, meta.base_name, meta.part_name, meta.unique_column, meta.index_column; + + return meta; +end; +$$; + +create or replace function _partition_meta_initdate( + meta partition_meta, + initDate date) + returns partition_meta +language plpgsql +set timezone to 'UTC' +as $$ +begin + meta.period_start = initDate; + return meta; +end; +$$; + + +-- select _partition_over('week', current_date, 4); + +------------------------------------------------------------------------------------ +-- Function: _partition_over +-- +-- Internal helper method to return a set/table of dates to ensure partitions exists for. +-- Typically we want to ensure some future partitions exist and this helps return dates +-- for which we loop to create partitions. +------------------------------------------------------------------------------------ +create or replace function _partition_over( + mode text, + fromDate date default current_date, + _count integer default 0) + returns TABLE(of_date date) +language plpgsql +as $$ +declare + endDate date; +begin + if (mode = 'day') then + endDate = fromDate + (interval '1 day' * _count); + fromDate = fromDate - interval '1 day'; -- allow for timezone + return query select s::date from generate_series(fromDate, endDate, '1 day') s; + + elseif (mode = 'week') then + fromDate = date_trunc('week', fromDate); + endDate = fromDate + (interval '1 week' * _count); + return query select s::date from generate_series(fromDate, endDate, '1 week') s; + + elseif (mode = 'year') then + fromDate = date_trunc('year', fromDate); + endDate = fromDate + (interval '1 year' * _count); + return query select s::date from generate_series(fromDate, endDate, '1 year') s; + + else + fromDate = date_trunc('month', fromDate); + endDate = fromDate + (interval '1 month' * _count); + return query select s::date from generate_series(fromDate, endDate, '1 month') s; + end if; +end; +$$; + + +------------------------------------------------------------------------------------ +-- Function: partition +-- +-- Helper to ensure we create partitions into the future as needed for day, week, month +-- and year based partitioning. Typically we call this periodically (e.g. every day). +-- +-- Examples: +-- +-- select partition('week', 'trip', 'id', 'when_started', 4); +-- select partition('month', 'event', 'id', 'event_timestamp', 1); +-- +------------------------------------------------------------------------------------ +create or replace function partition( + mode text, -- one of 'day','week','month','year' + baseName text, -- base table name + uniqueColumn text, -- optional unique column + indexColumn text, -- optional column to index + partitionCount integer default 0, -- number of additional partitions + fromDate date default current_date, -- date to create first partition for + extra text default '') -- custom function to call per partition + returns text +language plpgsql +set timezone to 'UTC' +as $$ +begin + perform _partition_create(_partition_meta(mode, poDate, baseName, uniqueColumn, indexColumn), extra) + from _partition_over(mode, fromDate, partitionCount) poDate; + return 'done'; +end; +$$; + + +------------------------------------------------------------------------------------ +-- Function: partition_init +-- +-- Similar to partition but allows the first partition to be bigger with an explicit +-- initDate typically to allow back dated rows to go into the initial partition. +-- +-- Examples: +-- +-- select partition_init(date '2001-01-01', 'week', 'event', 'id', 'event_timestamp', 4); +-- +------------------------------------------------------------------------------------ +create or replace function partition_init( + initDate date, -- first partition period start date + mode text, -- one of 'day','week','month','year' + baseName text, -- base table name + uniqueColumn text, -- optional unique column + indexColumn text, -- optional column to index + partitionCount integer default 0, -- number of additional partitions + fromDate date default current_date, -- date to create first partition for + extra text default '') -- custom function to call per partition + returns text +language plpgsql +set timezone to 'UTC' +as $$ +declare + meta partition_meta; +begin + -- override the period start for the first partition + meta = _partition_meta(mode, fromDate, baseName, uniqueColumn, indexColumn); + meta = _partition_meta_initdate(meta, initDate); + perform _partition_create(meta, extra); + + if (partitionCount > 0) then + -- create additional migrations normally + perform _partition_create(_partition_meta(mode, poDate, baseName, uniqueColumn, indexColumn), extra) + from _partition_over(mode, fromDate, partitionCount) poDate; + end if; + + return 'done'; +end; +$$; + + + From 046a9b30b01e02b0d449b06a58664eb14d24b4e6 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 10 Aug 2018 15:54:29 +1200 Subject: [PATCH 0418/1036] [maven-release-plugin] prepare release ebean-11.20.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 764c2b2e5..dac671dec 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.20.2-SNAPSHOT + 11.20.2 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.20.2 From 0faf9f54eac51ea784df60daf99abd111468a051 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 10 Aug 2018 15:54:42 +1200 Subject: [PATCH 0419/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index dac671dec..7ea3e4133 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.20.2 + 11.20.3-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.20.2 + HEAD From 9bbe99657ace3c2550689911051b6570d2cd9af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C5=8Dwball?= Date: Mon, 13 Aug 2018 11:26:14 +0200 Subject: [PATCH 0420/1036] Let enum arrays be saved as integers or strings (#1467) * Let enums be saved as integers or strings as needed * Add tests for int and varchar @DbArray enums --- .../server/type/ArrayElementConverter.java | 4 +- .../server/type/ScalarTypeArrayList.java | 14 ++++++- .../server/type/ScalarTypeArraySet.java | 15 ++++++- .../org/tests/model/array/EArrayBean.java | 21 ++++++++++ .../java/org/tests/model/array/IntEnum.java | 13 +++++++ .../tests/model/array/TestDbArray_basic.java | 39 +++++++++++++++---- .../org/tests/model/array/VarcharEnum.java | 13 +++++++ 7 files changed, 106 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/tests/model/array/IntEnum.java create mode 100644 src/test/java/org/tests/model/array/VarcharEnum.java diff --git a/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java b/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java index 2c6c09b76..0d704b81e 100644 --- a/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java +++ b/src/main/java/io/ebeaninternal/server/type/ArrayElementConverter.java @@ -112,14 +112,14 @@ interface ArrayElementConverter { @Override public Object toElement(Object rawValue) { - return scalarType.parse(rawValue.toString()); + return scalarType.toBeanType(rawValue); } @Override public Object[] toDbArray(Object[] objects) { Object[] dbArray = new Object[objects.length]; for (int i = 0; i < objects.length; i++) { - dbArray[i] = scalarType.format(objects[i]); + dbArray[i] = scalarType.toJdbcType(objects[i]); } return dbArray; } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java index 0621fe833..f9e07fd60 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArrayList.java @@ -60,7 +60,19 @@ public class ScalarTypeArrayList extends ScalarTypeJsonCollection implemen @Override public ScalarTypeArrayList typeForEnum(ScalarType scalarType) { - return new ScalarTypeArrayList("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType)); + final String arrayType; + switch (scalarType.getJdbcType()) { + case Types.INTEGER: + arrayType = "integer"; + break; + case Types.VARCHAR: + arrayType = "varchar"; + break; + default: + throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set."); + } + + return new ScalarTypeArrayList(arrayType, scalarType.getDocType(), new ArrayElementConverter.EnumConverter(scalarType)); } } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java index 29fc9d0f8..79f5a9411 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java @@ -54,13 +54,24 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl if (valueType.equals(String.class)) { return STRING; } - throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping on set"); + throw new IllegalArgumentException("Type [" + valueType + "] not supported for @DbArray mapping on list"); } @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public ScalarTypeArraySet typeForEnum(ScalarType scalarType) { - return new ScalarTypeArraySet("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType)); + final String arrayType; + switch (scalarType.getJdbcType()) { + case Types.INTEGER: + arrayType = "integer"; + break; + case Types.VARCHAR: + arrayType = "varchar"; + break; + default: + throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set."); + } + return new ScalarTypeArraySet(arrayType, scalarType.getDocType(), new ArrayElementConverter.EnumConverter(scalarType)); } } diff --git a/src/test/java/org/tests/model/array/EArrayBean.java b/src/test/java/org/tests/model/array/EArrayBean.java index 853fe9976..a9c4e7d64 100644 --- a/src/test/java/org/tests/model/array/EArrayBean.java +++ b/src/test/java/org/tests/model/array/EArrayBean.java @@ -38,6 +38,12 @@ public class EArrayBean { @DbArray List statuses; + @DbArray + List vcEnums = new ArrayList<>(); + + @DbArray + List intEnums = new ArrayList<>(); + @DbArray Set status2; @@ -100,6 +106,21 @@ public class EArrayBean { this.statuses = statuses; } + public List getVcEnums() { + return vcEnums; + } + + public void setVcEnums(final List vcEnums) { + this.vcEnums = vcEnums; + } + + public List getIntEnums() { + return intEnums; + } + + public void setIntEnums(final List intEnums) { + this.intEnums = intEnums; + } public Set getStatus2() { return status2; diff --git a/src/test/java/org/tests/model/array/IntEnum.java b/src/test/java/org/tests/model/array/IntEnum.java new file mode 100644 index 000000000..130d9d030 --- /dev/null +++ b/src/test/java/org/tests/model/array/IntEnum.java @@ -0,0 +1,13 @@ +package org.tests.model.array; + +import io.ebean.annotation.DbEnumType; +import io.ebean.annotation.DbEnumValue; + +public enum IntEnum { + ZERO, ONE, TWO; + + @DbEnumValue(storage = DbEnumType.INTEGER) + public int dbValue() { + return 100 + ordinal(); + } +} diff --git a/src/test/java/org/tests/model/array/TestDbArray_basic.java b/src/test/java/org/tests/model/array/TestDbArray_basic.java index e816edc86..6a3e938c5 100644 --- a/src/test/java/org/tests/model/array/TestDbArray_basic.java +++ b/src/test/java/org/tests/model/array/TestDbArray_basic.java @@ -1,19 +1,22 @@ package org.tests.model.array; -import io.ebean.BaseTestCase; -import io.ebean.Ebean; -import io.ebean.Query; -import org.ebeantest.LoggedSqlCollector; -import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.UUID; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertEquals; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Query; +import io.ebean.SqlRow; public class TestDbArray_basic extends BaseTestCase { @@ -22,7 +25,7 @@ public class TestDbArray_basic extends BaseTestCase { private EArrayBean found; @Test - public void insert() { + public void insert() throws SQLException { bean.setName("some stuff"); @@ -44,6 +47,10 @@ public class TestDbArray_basic extends BaseTestCase { bean.setStatuses(new ArrayList<>()); bean.getStatuses().add(EArrayBean.Status.ONE); bean.getStatuses().add(EArrayBean.Status.THREE); + bean.getVcEnums().add(VarcharEnum.ONE); + bean.getVcEnums().add(VarcharEnum.TWO); + bean.getIntEnums().add(IntEnum.ZERO); + bean.getIntEnums().add(IntEnum.TWO); bean.setStatus2(new LinkedHashSet<>()); bean.getStatus2().add(EArrayBean.Status.TWO); @@ -64,16 +71,23 @@ public class TestDbArray_basic extends BaseTestCase { .arrayIsNotEmpty("phoneNumbers") .arrayContains("statuses", EArrayBean.Status.ONE) .arrayContains("status2", EArrayBean.Status.TWO) + .arrayContains("vcEnums", VarcharEnum.TWO) + .arrayContains("intEnums", IntEnum.ZERO) .query(); List list = query.findList(); List statuses = list.get(0).getStatuses(); Set status2 = list.get(0).getStatus2(); + List intEnums = list.get(0).getIntEnums(); + List varcharEnums = list.get(0).getVcEnums(); assertThat(statuses).contains(EArrayBean.Status.ONE, EArrayBean.Status.THREE); assertThat(status2).contains(EArrayBean.Status.ONE, EArrayBean.Status.TWO); + assertThat(intEnums).containsExactly(IntEnum.ZERO, IntEnum.TWO); + assertThat(varcharEnums).containsExactly(VarcharEnum.ONE, VarcharEnum.TWO); + assertThat(query.getGeneratedSql()).contains(" t0.other_ids @> array[?,?]::bigint[] "); assertThat(query.getGeneratedSql()).contains(" t0.uids @> array[?] "); assertThat(query.getGeneratedSql()).contains(" t0.phone_numbers @> array[?] "); @@ -87,6 +101,15 @@ public class TestDbArray_basic extends BaseTestCase { .query(); query.findList(); + + final SqlRow row = Ebean.createSqlQuery("select * from earray_bean").findOne(); + + final String[] vcs = (String[]) ((java.sql.Array) row.get("vc_enums")).getArray(); + assertThat(vcs).containsExactly("xXxONE", "xXxTWO"); + + final Integer[] ints = (Integer[]) ((java.sql.Array) row.get("int_enums")).getArray(); + assertThat(ints).containsExactly(100, 102); + assertThat(query.getGeneratedSql()).contains(" coalesce(cardinality(t0.other_ids),0) = 0"); assertThat(query.getGeneratedSql()).contains(" not (t0.uids @> array[?])"); } diff --git a/src/test/java/org/tests/model/array/VarcharEnum.java b/src/test/java/org/tests/model/array/VarcharEnum.java new file mode 100644 index 000000000..2bbc64daf --- /dev/null +++ b/src/test/java/org/tests/model/array/VarcharEnum.java @@ -0,0 +1,13 @@ +package org.tests.model.array; + +import io.ebean.annotation.DbEnumType; +import io.ebean.annotation.DbEnumValue; + +public enum VarcharEnum { + ZERO, ONE, TWO; + + @DbEnumValue(storage = DbEnumType.VARCHAR) + public String dbValue() { + return "xXx" + name(); + } +} From 94e6fe90e53d2799a3a07ef811ebc6cd0363521f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 13 Aug 2018 21:54:19 +1200 Subject: [PATCH 0421/1036] No effective change - white space format --- .../ebeaninternal/server/type/ScalarTypeArraySet.java | 10 +++++----- .../server/type/ScalarTypeArraySetH2.java | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java index 79f5a9411..78c3ca3db 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySet.java @@ -58,7 +58,7 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public ScalarTypeArraySet typeForEnum(ScalarType scalarType) { final String arrayType; switch (scalarType.getJdbcType()) { @@ -68,8 +68,8 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl case Types.VARCHAR: arrayType = "varchar"; break; - default: - throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set."); + default: + throw new IllegalArgumentException("JdbcType [" + scalarType.getJdbcType() + "] not supported for @DbArray mapping on set."); } return new ScalarTypeArraySet(arrayType, scalarType.getDocType(), new ArrayElementConverter.EnumConverter(scalarType)); } @@ -79,9 +79,9 @@ public class ScalarTypeArraySet extends ScalarTypeJsonCollection> impl private final ArrayElementConverter converter; - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public ScalarTypeArraySet(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) { - super((Class)Set.class, Types.ARRAY, docPropertyType); + super((Class) Set.class, Types.ARRAY, docPropertyType); this.arrayType = arrayType; this.converter = converter; } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java index 1d54314fa..86bc471b5 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeArraySetH2.java @@ -7,6 +7,7 @@ import java.sql.SQLException; import java.sql.Types; import java.util.Set; import java.util.UUID; + /** * H2 database support for DB ARRAY. */ @@ -48,13 +49,13 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public ScalarTypeArraySetH2 typeForEnum(ScalarType scalarType) { return new ScalarTypeArraySetH2("varchar", DocPropertyType.TEXT, new ArrayElementConverter.EnumConverter(scalarType)); } } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) private ScalarTypeArraySetH2(String arrayType, DocPropertyType docPropertyType, ArrayElementConverter converter) { super(arrayType, docPropertyType, converter); } From 6d1e3a08e1f78ff273f491f1d90c46d77cc28e33 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 13 Aug 2018 21:59:33 +1200 Subject: [PATCH 0422/1036] #1470 - Change OnQueryOnly to default to OnQueryOnly.COMMIT --- src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java | 2 +- .../io/ebeaninternal/server/transaction/TransactionManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index ff887d038..65bdfff4c 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -52,7 +52,7 @@ public class DatabasePlatform { /** * The behaviour used when ending a read only transaction at read committed isolation level. */ - protected OnQueryOnly onQueryOnly = OnQueryOnly.ROLLBACK; + protected OnQueryOnly onQueryOnly = OnQueryOnly.COMMIT; /** * The open quote used by quoted identifiers. diff --git a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java index 147839461..51824492e 100644 --- a/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java +++ b/src/main/java/io/ebeaninternal/server/transaction/TransactionManager.java @@ -301,7 +301,7 @@ public class TransactionManager implements SpiTransactionManager { } // default to rollback if not defined on the platform - return dbPlatformOnQueryOnly == null ? OnQueryOnly.ROLLBACK : dbPlatformOnQueryOnly; + return dbPlatformOnQueryOnly == null ? OnQueryOnly.COMMIT : dbPlatformOnQueryOnly; } public String getServerName() { From cd1ae2001514f7192d33ba5030c9b4d1e6bc2d73 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 13 Aug 2018 22:00:15 +1200 Subject: [PATCH 0423/1036] Bump to 11.21.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7ea3e4133..06807d451 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.20.3-SNAPSHOT + 11.21.1-SNAPSHOT jar ebean From 3f12739e71c24376630746da5d5a303695d574bb Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 13 Aug 2018 22:06:26 +1200 Subject: [PATCH 0424/1036] [maven-release-plugin] prepare release ebean-11.21.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 06807d451..0a68704e1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.21.1-SNAPSHOT + 11.21.1 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.21.1 From ce10dd79f949923e4403b89bbf197f80c0c7b7c0 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 13 Aug 2018 22:06:41 +1200 Subject: [PATCH 0425/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0a68704e1..4ee1fb037 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.21.1 + 11.21.2-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.21.1 + HEAD From 95dab97b1bc52f33e357a5560f3d3837de438db7 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 14 Aug 2018 14:16:08 +1200 Subject: [PATCH 0426/1036] No effective change - adjust test adding @Draft property to @Draftable Document --- .../java/org/tests/model/draftable/Document.java | 12 ++++++++++++ .../transaction/TestTransactionTryResources.java | 1 + 2 files changed, 13 insertions(+) diff --git a/src/test/java/org/tests/model/draftable/Document.java b/src/test/java/org/tests/model/draftable/Document.java index 5340ee4fe..2652b2237 100644 --- a/src/test/java/org/tests/model/draftable/Document.java +++ b/src/test/java/org/tests/model/draftable/Document.java @@ -1,6 +1,7 @@ package org.tests.model.draftable; import io.ebean.Finder; +import io.ebean.annotation.Draft; import io.ebean.annotation.DraftOnly; import io.ebean.annotation.Draftable; @@ -25,6 +26,9 @@ public class Document extends BaseDomain { String body; + @Draft + boolean draft; + @DraftOnly Timestamp whenPublish; @@ -54,6 +58,14 @@ public class Document extends BaseDomain { this.body = body; } + public boolean isDraft() { + return draft; + } + + public void setDraft(boolean draft) { + this.draft = draft; + } + public Organisation getOrganisation() { return organisation; } diff --git a/src/test/java/org/tests/transaction/TestTransactionTryResources.java b/src/test/java/org/tests/transaction/TestTransactionTryResources.java index a9978a237..f53640dfd 100644 --- a/src/test/java/org/tests/transaction/TestTransactionTryResources.java +++ b/src/test/java/org/tests/transaction/TestTransactionTryResources.java @@ -34,6 +34,7 @@ public class TestTransactionTryResources extends BaseTestCase { Document document = Document.find.asDraft(doc.getId()); assertThat(document).isNotNull(); + assertThat(document.isDraft()).isTrue(); // cleanup Ebean.delete(document); From 80975acfbf83cdbb6dd1cbed212ad92a7568ab53 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 14 Aug 2018 14:23:28 +1200 Subject: [PATCH 0427/1036] #1471 - Change stateless update on bean with no @Version property that updates 0 rows to throw EntityNotFoundException --- .../server/core/PersistRequestBean.java | 12 +++++----- .../server/persist/dml/DmlHandler.java | 1 - .../org/tests/update/TestStatelessUpdate.java | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index dcee6530f..d71d7e9cd 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -31,6 +31,7 @@ import io.ebeanservice.docstore.api.DocStoreUpdate; import io.ebeanservice.docstore.api.DocStoreUpdateContext; import io.ebeanservice.docstore.api.DocStoreUpdates; +import javax.persistence.EntityNotFoundException; import javax.persistence.OptimisticLockException; import javax.persistence.PersistenceException; import java.io.IOException; @@ -854,12 +855,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ @Override public final void checkRowCount(int rowCount) { - if (ConcurrencyMode.VERSION == concurrencyMode && rowCount != 1) { - // fix for oracle. - // see: https://stackoverflow.com/questions/19022175/executebatch-method-return-array-of-value-2-in-java - if (rowCount != Statement.SUCCESS_NO_INFO) { - String m = Message.msg("persist.conc2", String.valueOf(rowCount)); - throw new OptimisticLockException(m, null, bean); + if (rowCount != 1 && rowCount != Statement.SUCCESS_NO_INFO) { + if (ConcurrencyMode.VERSION == concurrencyMode) { + throw new OptimisticLockException(Message.msg("persist.conc2", String.valueOf(rowCount)), null, bean); + } else if (rowCount == 0 && type == Type.UPDATE) { + throw new EntityNotFoundException("No rows updated"); } } switch (type) { diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java b/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java index a90e3198b..ea1a05087 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/DmlHandler.java @@ -7,7 +7,6 @@ import io.ebeaninternal.server.lib.util.Str; import io.ebeaninternal.server.persist.BatchedPstmt; import io.ebeaninternal.server.persist.BatchedPstmtHolder; import io.ebeaninternal.server.persist.dmlbind.BindableRequest; -import io.ebeaninternal.server.transaction.TransactionManager; import io.ebeaninternal.server.type.DataBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/test/java/org/tests/update/TestStatelessUpdate.java b/src/test/java/org/tests/update/TestStatelessUpdate.java index 184248b88..7a3376adf 100644 --- a/src/test/java/org/tests/update/TestStatelessUpdate.java +++ b/src/test/java/org/tests/update/TestStatelessUpdate.java @@ -11,6 +11,7 @@ import org.tests.model.basic.EBasic.Status; import org.junit.Assert; import org.junit.Test; +import javax.persistence.EntityNotFoundException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -70,6 +71,28 @@ public class TestStatelessUpdate extends TransactionalTestCase { } + @Test(expected = EntityNotFoundException.class) + public void update_NoRowsUpdated_expect_EntityNotFoundException() { + + EBasic basic = new EBasic(); + basic.setId(999999999); + basic.setName("something"); + basic.setStatus(Status.ACTIVE); + + Ebean.update(basic); + } + + @Test + public void delete_NoRowsDeleted_expect_false() { + + EBasic basic = new EBasic(); + basic.setId(999999999); + basic.setName("something"); + basic.setStatus(Status.ACTIVE); + + assertThat(Ebean.delete(basic)).isFalse(); + } + /** * I am expecting that Ebean detects there aren't any changes and don't execute any query. * Currently a {@link javax.persistence.PersistenceException} with message 'Invalid value "null" for parameter "SQL"' is thrown. From 340b100a1ab1e432ea315a02a1803f8f85614291 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 14 Aug 2018 22:09:01 +1200 Subject: [PATCH 0428/1036] No effective change - Add test for OneToOne orphanRemoval=true and String Ids (non generated ids) --- .../org/tests/model/onetoone/OtoAone.java | 19 ++++++++ .../org/tests/model/onetoone/OtoAtwo.java | 47 +++++++++++++++++++ .../onetoone/TestOneToOneOrphanStringId.java | 39 +++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 src/test/java/org/tests/model/onetoone/OtoAone.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoAtwo.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java diff --git a/src/test/java/org/tests/model/onetoone/OtoAone.java b/src/test/java/org/tests/model/onetoone/OtoAone.java new file mode 100644 index 000000000..9716b4a37 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoAone.java @@ -0,0 +1,19 @@ +package org.tests.model.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class OtoAone { + + @Id + private String id; + + private String description; + + public OtoAone(String id, String description){ + this.id = id; + this.description = description; + } + +} diff --git a/src/test/java/org/tests/model/onetoone/OtoAtwo.java b/src/test/java/org/tests/model/onetoone/OtoAtwo.java new file mode 100644 index 000000000..d60bfb5c1 --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoAtwo.java @@ -0,0 +1,47 @@ +package org.tests.model.onetoone; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +@Entity +public class OtoAtwo { + + @Id + private String id; + + private String description; + + @OneToOne(orphanRemoval=true, cascade = CascadeType.ALL) + private OtoAone aone; + + public OtoAtwo(String id, String description){ + this.id = id; + this.description = description; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public OtoAone getAone() { + return aone; + } + + public void setAone(OtoAone aone) { + this.aone = aone; + } +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java new file mode 100644 index 000000000..de738af4e --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java @@ -0,0 +1,39 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOneOrphanStringId extends BaseTestCase { + + @Test + public void test() { + + OtoAone a = new OtoAone("a", "a test"); + OtoAtwo b = new OtoAtwo("b", "b test"); + b.setAone(a); + + LoggedSqlCollector.start(); + + Ebean.save(b); + + List inserts = LoggedSqlCollector.current(); + assertThat(inserts).hasSize(2); + assertThat(inserts.get(0)).contains("insert into oto_aone"); + assertThat(inserts.get(1)).contains("insert into oto_atwo"); + + Ebean.delete(b); + + List deletes = LoggedSqlCollector.stop(); + assertThat(deletes).hasSize(2); + assertThat(deletes.get(0)).contains("delete from oto_atwo"); + assertThat(deletes.get(1)).contains("delete from oto_aone"); + } +} + + From 29c5a17202b9835134414a3920cf87d47e77e137 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 15 Aug 2018 23:12:06 +1200 Subject: [PATCH 0429/1036] #1472 - Cascade insert with managed id ... results in update rather than insert statement --- .../server/core/PersistRequestBean.java | 12 +++- .../server/persist/DefaultPersister.java | 7 +-- .../ebeaninternal/server/persist/Flags.java | 63 +++++++++++++------ .../server/persist/FlagsTest.java | 51 +++++++++++++-- .../onetoone/TestOneToOneOrphanStringId.java | 33 +++++++++- 5 files changed, 132 insertions(+), 34 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index d71d7e9cd..9a8d0f23b 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1307,14 +1307,22 @@ public final class PersistRequestBean extends PersistRequest implements BeanP * Set the request flags indicating this is an insert. */ public void flagInsert() { - flags = Flags.setInsert(flags); + if (intercept.isNew()) { + flags = Flags.setInsertNormal(flags); + } else { + flags = Flags.setInsert(flags); + } } /** * Unset the request insert flag indicating this is an update. */ public void flagUpdate() { - flags = Flags.unsetInsert(flags); + if (intercept.isLoaded()) { + flags = Flags.setUpdateNormal(flags); + } else { + flags = Flags.setUpdate(flags); + } } /** diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index feb7337b3..0e402dcdc 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -456,8 +456,7 @@ public final class DefaultPersister implements Persister { void saveRecurse(EntityBean bean, Transaction t, Object parentBean, int flags) { // determine insert or update taking into account stateless updates - PersistRequestBean request = createRequestRecurse(bean, t, parentBean, flags); - saveRecurse(request); + saveRecurse(createRequestRecurse(bean, t, parentBean, flags)); } private void saveRecurse(PersistRequestBean request) { @@ -1229,8 +1228,8 @@ public final class DefaultPersister implements Persister { BeanDescriptor desc = mgr.getBeanDescriptor(); EntityBean entityBean = (EntityBean) bean; PersistRequest.Type type; - if (Flags.isPublishOrMerge(flags)) { - // insert if it is a new bean (as publish created it) + if (Flags.isPublishMergeOrNormal(flags)) { + // just use bean state to determine insert or update type = entityBean._ebean_getIntercept().isUpdate() ? Type.UPDATE : Type.INSERT; } else { // determine Insert or Update based on bean state and insert flag diff --git a/src/main/java/io/ebeaninternal/server/persist/Flags.java b/src/main/java/io/ebeaninternal/server/persist/Flags.java index ffde410c5..263dbb6e8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/Flags.java +++ b/src/main/java/io/ebeaninternal/server/persist/Flags.java @@ -5,7 +5,7 @@ package io.ebeaninternal.server.persist; *

    * Allows passing of flag state when recursively persisting. */ -public class Flags { +public final class Flags { /** * Indicates the bean is being inserted. @@ -27,6 +27,11 @@ public class Flags { */ public static final int MERGE = 0x00000008; + /** + * Indicates Normal insert or update (not forced). + */ + public static final int NORMAL = 0x00000010; + /** * No flags set. */ @@ -34,7 +39,9 @@ public class Flags { public static final int PUBLISH_RECURSE = PUBLISH + RECURSE; - private static final int PUBLISH_MERGE = PUBLISH + MERGE; + private static final int PUBLISH_MERGE_NORMAL = PUBLISH + MERGE + NORMAL; + + private static final int INSERT_NORMAL = INSERT + NORMAL; /** * Return true if the bean is being inserted. @@ -65,10 +72,10 @@ public class Flags { } /** - * Return true if part of a Merge or Publish. + * Return true if part of a Merge or Publish or Normal (bean state matches persist). */ - public static boolean isPublishOrMerge(long state) { - return (state & PUBLISH_MERGE) != 0; + public static boolean isPublishMergeOrNormal(int state) { + return (state & PUBLISH_MERGE_NORMAL) != 0; } /** @@ -82,54 +89,70 @@ public class Flags { * Set Insert flag. */ public static int setInsert(int state) { - return set(state, INSERT, true); + return set(state, INSERT); + } + + /** + * Insert flag and normal in that bean is in NEW state (for insert). + */ + public static int setInsertNormal(int state) { + return set(state, INSERT_NORMAL); } /** * Parent was not inserted. */ - public static int unsetInsert(int state) { - return set(state, INSERT, false); + public static int setUpdate(int state) { + return unset(state, INSERT); + } + + /** + * Not Insert and normal in that bean is in LOADED state (for update). + */ + public static int setUpdateNormal(int state) { + state &= ~INSERT; + state |= NORMAL; + return state; } /** * Set Recurse flag. */ public static int setRecurse(int state) { - return set(state, RECURSE, true); + return set(state, RECURSE); } public static int unsetRecuse(int state) { - return set(state, RECURSE, false); + return unset(state, RECURSE); } /** * Set Publish flag. */ public static int setPublish(int state) { - return set(state, PUBLISH, true); + return set(state, PUBLISH); } public static int unsetPublish(int state) { - return set(state, PUBLISH, false); + return unset(state, PUBLISH); } /** * Set Merge flag. */ public static int setMerge(int state) { - return set(state, MERGE, true); + return set(state, MERGE); } public static int unsetMerge(int state) { - return set(state, MERGE, false); + return unset(state, MERGE); } - private static int set(int state, int flag, boolean setFlag) { - if (setFlag) { - return (state |= flag); - } else { - return state &= ~flag; - } + private static int set(int state, int flag) { + return (state |= flag); + } + + private static int unset(int state, int flag) { + return state &= ~flag; } } diff --git a/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java b/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java index 4e4d947c4..0753a3841 100644 --- a/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java +++ b/src/test/java/io/ebeaninternal/server/persist/FlagsTest.java @@ -26,19 +26,60 @@ public class FlagsTest { assertThat(Flags.isSet(state, Flags.PUBLISH)).isFalse(); assertThat(Flags.isSet(state, Flags.MERGE)).isTrue(); assertThat(Flags.isSet(state, Flags.INSERT)).isTrue(); + } + @Test + public void insert() { + + int state = 0; + + state = Flags.setInsert(state); + assertThat(Flags.isSet(state, Flags.INSERT)).isTrue(); + assertThat(Flags.isSet(state, Flags.NORMAL)).isFalse(); + } + + @Test + public void insertNormal() { + + int state = 0; + + state = Flags.setInsertNormal(state); + assertThat(Flags.isSet(state, Flags.INSERT)).isTrue(); + assertThat(Flags.isSet(state, Flags.NORMAL)).isTrue(); + } + + @Test + public void update() { + + int state = 0; + + state = Flags.setUpdate(state); + assertThat(Flags.isSet(state, Flags.INSERT)).isFalse(); + assertThat(Flags.isSet(state, Flags.NORMAL)).isFalse(); + } + + @Test + public void updateNormal() { + + int state = 0; + + state = Flags.setUpdateNormal(state); + assertThat(Flags.isSet(state, Flags.INSERT)).isFalse(); + assertThat(Flags.isSet(state, Flags.NORMAL)).isTrue(); } @Test public void isPublishOrMerge() { - assertThat(Flags.isPublishOrMerge(0)).isFalse(); - assertThat(Flags.isPublishOrMerge(Flags.INSERT)).isFalse(); + assertThat(Flags.isPublishMergeOrNormal(0)).isFalse(); + assertThat(Flags.isPublishMergeOrNormal(Flags.INSERT)).isFalse(); + assertThat(Flags.isPublishMergeOrNormal(Flags.RECURSE)).isFalse(); - assertThat(Flags.isPublishOrMerge(Flags.PUBLISH)).isTrue(); - assertThat(Flags.isPublishOrMerge(Flags.MERGE)).isTrue(); + assertThat(Flags.isPublishMergeOrNormal(Flags.PUBLISH)).isTrue(); + assertThat(Flags.isPublishMergeOrNormal(Flags.MERGE)).isTrue(); + assertThat(Flags.isPublishMergeOrNormal(Flags.NORMAL)).isTrue(); int mergePublish = Flags.setMerge(Flags.setPublish(0)); - assertThat(Flags.isPublishOrMerge(mergePublish)).isTrue(); + assertThat(Flags.isPublishMergeOrNormal(mergePublish)).isTrue(); } } diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java index de738af4e..1a16f50d6 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java @@ -12,10 +12,37 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestOneToOneOrphanStringId extends BaseTestCase { @Test - public void test() { + public void test_updateInsert() { + + OtoAtwo b = new OtoAtwo("b1", "b test"); + Ebean.save(b); + + OtoAone a = new OtoAone("a1", "a test"); + b.setAone(a); + + LoggedSqlCollector.start(); + + Ebean.save(b); + + List update = LoggedSqlCollector.current(); + assertThat(update).hasSize(2); + assertThat(update.get(0)).contains("insert into oto_aone"); + assertThat(update.get(1)).contains("update oto_atwo set aone_id=? where id=?"); + + Ebean.delete(b); + + List deletes = LoggedSqlCollector.stop(); + assertThat(deletes).hasSize(2); + assertThat(deletes.get(0)).contains("delete from oto_atwo"); + assertThat(deletes.get(1)).contains("delete from oto_aone"); + } + + @Test + public void test_cascade() { + + OtoAone a = new OtoAone("a2", "a test"); + OtoAtwo b = new OtoAtwo("b2", "b test"); - OtoAone a = new OtoAone("a", "a test"); - OtoAtwo b = new OtoAtwo("b", "b test"); b.setAone(a); LoggedSqlCollector.start(); From f63a3cb9260645abb7f831a0655f9cbb9b7e8e6e Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 16 Aug 2018 00:02:10 +1200 Subject: [PATCH 0430/1036] Bump ebean-migration to 11.9.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4ee1fb037..27a2e272a 100644 --- a/pom.xml +++ b/pom.xml @@ -135,7 +135,7 @@ io.ebean ebean-migration - 11.8.2 + 11.9.1 From e1b7161b22e22490935cabb72bece2c96519057b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 16 Aug 2018 00:03:15 +1200 Subject: [PATCH 0431/1036] Bump version to 11.22.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 27a2e272a..8787fb6e3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.21.2-SNAPSHOT + 11.22.1-SNAPSHOT jar ebean From d28e3ee456ead8d66a5234cfa19ae8c25031493e Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 16 Aug 2018 00:05:16 +1200 Subject: [PATCH 0432/1036] [maven-release-plugin] prepare release ebean-11.22.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8787fb6e3..0528b83c9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.1-SNAPSHOT + 11.22.1 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.1 From 5f83584315f1534b319da42f70e5a31ab8a1b5e9 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 16 Aug 2018 00:05:31 +1200 Subject: [PATCH 0433/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0528b83c9..13393abcb 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.1 + 11.22.2-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.1 + HEAD From f3d26e32ecb60791ae1354c325c4f1253e2b00c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sn=C5=8Dwball?= Date: Tue, 21 Aug 2018 10:26:08 +0200 Subject: [PATCH 0434/1036] Possible fix error with multiple uses of enum (#1473) When an enum is exists in the type cache and isn't String, @DbArray fails. This includes a test that should fail everywhere (order of reading fields isn't guaranteed afaik and the column needs to be read before the @DbArray for the test to fail). --- .../ebeaninternal/server/type/DefaultTypeManager.java | 4 ++-- src/test/java/org/tests/model/array/EArrayBean.java | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index eebf80aca..d6fb20e33 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -351,7 +351,7 @@ public final class DefaultTypeManager implements TypeManager { if (type.equals(List.class)) { if (arrayTypeListFactory != null) { if (isEnumType(valueType)) { - return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING)); + return arrayTypeListFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), null)); } return arrayTypeListFactory.typeFor(valueType); } @@ -360,7 +360,7 @@ public final class DefaultTypeManager implements TypeManager { } else if (type.equals(Set.class)) { if (arrayTypeSetFactory != null) { if (isEnumType(valueType)) { - return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), EnumType.STRING)); + return arrayTypeSetFactory.typeForEnum(createEnumScalarType(asEnumClass(valueType), null)); } return arrayTypeSetFactory.typeFor(valueType); } diff --git a/src/test/java/org/tests/model/array/EArrayBean.java b/src/test/java/org/tests/model/array/EArrayBean.java index a9c4e7d64..c8fd0f29d 100644 --- a/src/test/java/org/tests/model/array/EArrayBean.java +++ b/src/test/java/org/tests/model/array/EArrayBean.java @@ -18,6 +18,8 @@ public class EArrayBean { ONE, TWO, THREE } + IntEnum foo; + @Id Long id; @@ -50,6 +52,14 @@ public class EArrayBean { @Version Long version; + public IntEnum getFoo() { + return foo; + } + + public void setFoo(final IntEnum foo) { + this.foo = foo; + } + public Long getId() { return id; } From 663b1bb4aa01a640b855f6e62a844aaebd5cbff3 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 21 Aug 2018 20:45:31 +1200 Subject: [PATCH 0435/1036] #1474 - IllegalStateException: Table [some_table] does not exists in model? ... when applying drop table migration and table is no longer in the model --- .../dbmigration/model/ModelContainer.java | 26 +++++------------ .../dbmigration/model/ModelContainerTest.java | 28 +++++++++++++++++++ .../model/5.0__dropTable.model.xml | 6 ++++ 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 src/test/resources/io/ebeaninternal/dbmigration/model/5.0__dropTable.model.xml diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java index f2daca21b..d92adfb61 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/ModelContainer.java @@ -184,13 +184,12 @@ public class ModelContainer { /** * Unset the withHistory flag on the associated base table. */ - private void applyChange(DropHistoryTable change) { + protected void applyChange(DropHistoryTable change) { MTable table = tables.get(change.getBaseTable()); - if (table == null) { - throw new IllegalStateException("Table [" + change.getBaseTable() + "] does not exist in model?"); + if (table != null) { + table.setWithHistory(false); } - table.setWithHistory(false); } private void applyChange(AddUniqueConstraint change) { @@ -241,19 +240,14 @@ public class ModelContainer { if (tables.containsKey(tableName)) { throw new IllegalStateException("Table [" + tableName + "] already exists in model?"); } - MTable table = new MTable(createTable); - tables.put(tableName, table); + tables.put(tableName, new MTable(createTable)); } /** * Apply a DropTable change to the model. */ protected void applyChange(DropTable dropTable) { - String tableName = dropTable.getName(); - if (!tables.containsKey(tableName)) { - throw new IllegalStateException("Table [" + tableName + "] does not exists in model?"); - } - tables.remove(tableName); + tables.remove(dropTable.getName()); } /** @@ -264,22 +258,16 @@ public class ModelContainer { if (indexes.containsKey(indexName)) { throw new IllegalStateException("Index [" + indexName + "] already exists in model?"); } - MIndex index = new MIndex(createIndex); - indexes.put(createIndex.getIndexName(), index); + indexes.put(createIndex.getIndexName(), new MIndex(createIndex)); } /** * Apply a DropTable change to the model. */ protected void applyChange(DropIndex dropIndex) { - String name = dropIndex.getIndexName(); - if (!indexes.containsKey(name)) { - throw new IllegalStateException("Index [" + name + "] does not exist in model?"); - } - indexes.remove(name); + indexes.remove(dropIndex.getIndexName()); } - /** * Apply a AddColumn change to the model. */ diff --git a/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java b/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java index ae05f368b..591e7aa99 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/model/ModelContainerTest.java @@ -1,6 +1,9 @@ package io.ebeaninternal.dbmigration.model; +import io.ebeaninternal.dbmigration.migration.DropHistoryTable; +import io.ebeaninternal.dbmigration.migration.DropIndex; +import io.ebeaninternal.dbmigration.migration.DropTable; import io.ebeaninternal.dbmigration.migration.Migration; import io.ebeaninternal.dbmigration.migrationreader.MigrationXmlReader; import org.junit.Test; @@ -79,6 +82,31 @@ public class ModelContainerTest { assertThat(container.getPendingDrops()).isEmpty(); } + @Test + public void apply_dropTable_when_notInModel_then_ok() { + + ModelContainer container = new ModelContainer(); + container.apply(mig("5.0__dropTable.model.xml"), ver("5.0")); + assertThat(container.getTables()).isEmpty(); + } + + @Test + public void apply_drop_when_notInModel_then_ok() { + + ModelContainer container = new ModelContainer(); + DropTable dropTable = new DropTable(); + dropTable.setName("DoesNotExist"); + container.applyChange(dropTable); + + DropIndex dropIndex = new DropIndex(); + dropIndex.setIndexName("DoesNotExist"); + container.applyChange(dropIndex); + + DropHistoryTable dropHistoryTable = new DropHistoryTable(); + dropHistoryTable.setBaseTable("DoesNotExist"); + container.applyChange(dropHistoryTable); + } + private ModelContainer container_2_1() { ModelContainer container = new ModelContainer(); container.apply(mig("2.0.model.xml"), ver("2.0")); diff --git a/src/test/resources/io/ebeaninternal/dbmigration/model/5.0__dropTable.model.xml b/src/test/resources/io/ebeaninternal/dbmigration/model/5.0__dropTable.model.xml new file mode 100644 index 000000000..5085a7aba --- /dev/null +++ b/src/test/resources/io/ebeaninternal/dbmigration/model/5.0__dropTable.model.xml @@ -0,0 +1,6 @@ + + + + + + From d11bb2c4e509a7895e4e82dc70fa168120eaf2d8 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 21 Aug 2018 21:08:17 +1200 Subject: [PATCH 0436/1036] No effective change - add a new test for OneToMany orphanRemoval=true --- .../tests/model/orphanremoval/OrpDetail.java | 58 ++++++++++++++++++ .../tests/model/orphanremoval/OrpMaster.java | 60 +++++++++++++++++++ .../orphanremoval/TestOrphanRemoveO2M.java | 36 +++++++++++ 3 files changed, 154 insertions(+) create mode 100644 src/test/java/org/tests/model/orphanremoval/OrpDetail.java create mode 100644 src/test/java/org/tests/model/orphanremoval/OrpMaster.java create mode 100644 src/test/java/org/tests/model/orphanremoval/TestOrphanRemoveO2M.java diff --git a/src/test/java/org/tests/model/orphanremoval/OrpDetail.java b/src/test/java/org/tests/model/orphanremoval/OrpDetail.java new file mode 100644 index 000000000..4ba7c12fa --- /dev/null +++ b/src/test/java/org/tests/model/orphanremoval/OrpDetail.java @@ -0,0 +1,58 @@ +package org.tests.model.orphanremoval; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Version; + +@Entity +public class OrpDetail { + + @Id + String id; + + String detail; + + @ManyToOne + OrpMaster master; + + @Version + long version; + + public OrpDetail(String id, String detail) { + this.id = id; + this.detail = detail; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public OrpMaster getMaster() { + return master; + } + + public void setMaster(OrpMaster master) { + this.master = master; + } + + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/orphanremoval/OrpMaster.java b/src/test/java/org/tests/model/orphanremoval/OrpMaster.java new file mode 100644 index 000000000..8801d87f7 --- /dev/null +++ b/src/test/java/org/tests/model/orphanremoval/OrpMaster.java @@ -0,0 +1,60 @@ +package org.tests.model.orphanremoval; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Version; +import java.util.List; + +@Entity +public class OrpMaster { + + @Id + String id; + + String name; + + @OneToMany(orphanRemoval = true, cascade = CascadeType.ALL) + List details; + + @Version + long version; + + public OrpMaster(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getDetails() { + return details; + } + + public void setDetails(List details) { + this.details = details; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/orphanremoval/TestOrphanRemoveO2M.java b/src/test/java/org/tests/model/orphanremoval/TestOrphanRemoveO2M.java new file mode 100644 index 000000000..b0c52a12b --- /dev/null +++ b/src/test/java/org/tests/model/orphanremoval/TestOrphanRemoveO2M.java @@ -0,0 +1,36 @@ +package org.tests.model.orphanremoval; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOrphanRemoveO2M extends BaseTestCase { + + @Test + public void clear_expect_deletes() { + + OrpMaster master = new OrpMaster("m","master"); + master.getDetails().add(new OrpDetail("d1", "d1")); + master.getDetails().add(new OrpDetail("d2", "d2")); + + Ebean.save(master); + + master.getDetails().clear(); + + LoggedSqlCollector.start(); + Ebean.save(master); + + List sql = LoggedSqlCollector.stop(); + + assertThat(Ebean.find(OrpDetail.class, "d1")).isNull(); + assertThat(Ebean.find(OrpDetail.class, "d2")).isNull(); + + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from orp_detail where id=?"); + } +} From 4d4886d8080207f7c0b005349dd6dad4a637b8d4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 21 Aug 2018 21:15:07 +1200 Subject: [PATCH 0437/1036] [maven-release-plugin] prepare release ebean-11.22.2 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 13393abcb..c1f928873 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.2-SNAPSHOT + 11.22.2 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.2 From e1e8092144614f85a3f13b3aab30acab96556cf4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Tue, 21 Aug 2018 21:15:23 +1200 Subject: [PATCH 0438/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c1f928873..3c8fe96d4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.2 + 11.22.3-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.2 + HEAD From 2df2224286dc1043f5681da80887756a19c99c45 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 27 Aug 2018 20:00:44 +1200 Subject: [PATCH 0439/1036] No effective change - add a new test for OneToOne with fetchType LAZY --- .../org/tests/model/onetoone/OtoBMaster.java | 3 +- .../TestOneToOneImportedPkNative.java | 41 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/tests/model/onetoone/OtoBMaster.java b/src/test/java/org/tests/model/onetoone/OtoBMaster.java index 2ab81d97e..43e968ef0 100644 --- a/src/test/java/org/tests/model/onetoone/OtoBMaster.java +++ b/src/test/java/org/tests/model/onetoone/OtoBMaster.java @@ -2,6 +2,7 @@ package org.tests.model.onetoone; import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.OneToOne; @@ -13,7 +14,7 @@ public class OtoBMaster { String name; - @OneToOne(cascade = CascadeType.ALL, mappedBy = "master") + @OneToOne(cascade = CascadeType.ALL, mappedBy = "master", fetch = FetchType.LAZY) OtoBChild child; public Long getId() { diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java b/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java index b01c4ddb3..1ee9e17e9 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java @@ -3,12 +3,53 @@ package org.tests.model.onetoone; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; +import io.ebean.Query; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; public class TestOneToOneImportedPkNative extends BaseTestCase { + @Test + public void findWithLazyOneToOne() { + + OtoBChild child = new OtoBChild(); + child.setChild("c1"); + + OtoBMaster master = new OtoBMaster(); + master.setName("m2"); + master.setChild(child); + + Ebean.save(master); + + Query query = Ebean.find(OtoBMaster.class) + //.select("name") + .where().idEq(master.getId()) + .query(); + + OtoBMaster one = query.findOne(); + + String sql = sqlOf(query); + assertThat(sql).contains("select t0.id, t0.name from oto_bmaster t0 where t0.id "); + assertThat(sql).doesNotContain("left join oto_bchild"); + + assertThat(one).isNotNull(); + + LoggedSqlCollector.start(); + + OtoBChild child1 = one.getChild(); + assertThat(child1).isNotNull(); + assertThat(child1.getChild()).isEqualTo("c1"); + + List lazyLoadSql = LoggedSqlCollector.stop(); + assertThat(lazyLoadSql).hasSize(2); + assertThat(lazyLoadSql.get(0)).contains("select t0.id, t0.name, t1.master_id from oto_bmaster t0 left join oto_bchild t1"); + assertThat(lazyLoadSql.get(1)).contains("select t0.master_id, t0.child, t0.master_id from oto_bchild t0 where t0.master_id"); + } + @Test public void native_with_o2oAndImportedPrimaryKey() { From 55a9ba7170a3111e5a879267f3d03b7d2ef6e990 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 27 Aug 2018 21:35:00 +1200 Subject: [PATCH 0440/1036] #1475 - @OneToOne child with @SoftDelete that is deleted is still loaded by parent --- .../deploy/AssocOneHelpRefExported.java | 14 +++- .../server/deploy/DbSqlContext.java | 13 ++-- .../server/deploy/TableJoin.java | 10 +++ .../server/query/DefaultDbSqlContext.java | 15 ++-- .../server/query/SqlTreeAlias.java | 10 ++- .../server/query/SqlTreeBuilder.java | 2 +- .../org/tests/model/onetoone/OtoSdChild.java | 73 +++++++++++++++++++ .../org/tests/model/onetoone/OtoSdMaster.java | 55 ++++++++++++++ .../onetoone/TestOneToOneSoftDeleteChild.java | 47 ++++++++++++ 9 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 src/test/java/org/tests/model/onetoone/OtoSdChild.java create mode 100644 src/test/java/org/tests/model/onetoone/OtoSdMaster.java create mode 100644 src/test/java/org/tests/model/onetoone/TestOneToOneSoftDeleteChild.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/AssocOneHelpRefExported.java b/src/main/java/io/ebeaninternal/server/deploy/AssocOneHelpRefExported.java index 81de5a036..874231645 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/AssocOneHelpRefExported.java +++ b/src/main/java/io/ebeaninternal/server/deploy/AssocOneHelpRefExported.java @@ -7,8 +7,14 @@ import io.ebeaninternal.server.query.SqlJoinType; */ class AssocOneHelpRefExported extends AssocOneHelp { - public AssocOneHelpRefExported(BeanPropertyAssocOne property) { + private final boolean softDelete; + + private final String softDeletePredicate; + + AssocOneHelpRefExported(BeanPropertyAssocOne property) { super(property); + this.softDelete = property.targetDescriptor.isSoftDelete(); + this.softDeletePredicate = (softDelete) ? property.targetDescriptor.getSoftDeletePredicate("") : null; } /** @@ -28,6 +34,10 @@ class AssocOneHelpRefExported extends AssocOneHelp { void appendFrom(DbSqlContext ctx, SqlJoinType joinType) { String relativePrefix = ctx.getRelativePrefix(property.getName()); - property.tableJoin.addJoin(joinType, relativePrefix, ctx); + if (softDelete && !ctx.isIncludeSoftDelete()) { + property.tableJoin.addJoin(joinType, relativePrefix, ctx, softDeletePredicate); + } else { + property.tableJoin.addJoin(joinType, relativePrefix, ctx); + } } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java index 0eca9a112..3fd4e3666 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DbSqlContext.java @@ -12,8 +12,6 @@ public interface DbSqlContext { */ void addJoin(String type, String table, TableJoinColumn[] cols, String a1, String a2, String inheritance); - void pushSecondaryTableAlias(String alias); - /** * Push the current table alias onto the stack. */ @@ -91,11 +89,6 @@ public interface DbSqlContext { */ String getContent(); - /** - * Return the current join node. - */ - String peekJoin(); - /** * Push a join node onto the stack. */ @@ -125,6 +118,11 @@ public interface DbSqlContext { */ void appendHistorySysPeriod(); + /** + * Return true if the query includes soft deleted rows. + */ + boolean isIncludeSoftDelete(); + /** * Return true if the query is a 'asDraft' query. */ @@ -139,4 +137,5 @@ public interface DbSqlContext { * Append 'for update' lock hints on FROM clause (sql server only). */ void appendFromForUpdate(); + } diff --git a/src/main/java/io/ebeaninternal/server/deploy/TableJoin.java b/src/main/java/io/ebeaninternal/server/deploy/TableJoin.java index 6a23e300d..eedb2b547 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/TableJoin.java +++ b/src/main/java/io/ebeaninternal/server/deploy/TableJoin.java @@ -126,6 +126,16 @@ public final class TableJoin { return type; } + public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx, String predicate) { + String[] names = SplitName.split(prefix); + String a1 = ctx.getTableAlias(names[0]); + String a2 = ctx.getTableAlias(prefix); + + SqlJoinType returnJoinType = addJoin(joinType, a1, a2, ctx); + ctx.append("and ").append(a2).append(predicate); + return returnJoinType; + } + public SqlJoinType addJoin(SqlJoinType joinType, String prefix, DbSqlContext ctx) { String[] names = SplitName.split(prefix); diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index f40b9c2cf..cb5ae732e 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -70,6 +70,11 @@ class DefaultDbSqlContext implements DbSqlContext { this.fromForUpdate = fromForUpdate; } + @Override + public boolean isIncludeSoftDelete() { + return alias.isIncludeSoftDelete(); + } + @Override public void appendFromForUpdate() { if (fromForUpdate != null) { @@ -99,11 +104,6 @@ class DefaultDbSqlContext implements DbSqlContext { return encryptedProps.toArray(new BeanProperty[encryptedProps.size()]); } - @Override - public String peekJoin() { - return joinStack.peek(); - } - @Override public void popJoin() { joinStack.pop(); @@ -206,11 +206,6 @@ class DefaultDbSqlContext implements DbSqlContext { return alias.getTableAliasManyWhere(prefix); } - @Override - public void pushSecondaryTableAlias(String alias) { - tableAliasStack.push(alias); - } - @Override public String getRelativePrefix(String propName) { diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java index ea583c833..39895df70 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeAlias.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.query; import io.ebean.util.SplitName; +import io.ebeaninternal.api.SpiQuery; import java.util.HashMap; import java.util.HashSet; @@ -17,6 +18,8 @@ class SqlTreeAlias { private static final Pattern TABLE_ALIAS_REPLACE = Pattern.compile("${}", Pattern.LITERAL); + private final SpiQuery.TemporalMode temporalMode; + private int counter; private int manyWhereCounter; @@ -33,8 +36,9 @@ class SqlTreeAlias { private final String rootTableAlias; - SqlTreeAlias(String rootTableAlias) { + SqlTreeAlias(String rootTableAlias, SpiQuery.TemporalMode temporalMode) { this.rootTableAlias = rootTableAlias; + this.temporalMode = temporalMode; } /** @@ -211,4 +215,8 @@ class SqlTreeAlias { boolean isIncludeJoins() { return !aliasMap.isEmpty() || !manyWhereAliasMap.isEmpty(); } + + boolean isIncludeSoftDelete() { + return temporalMode == SpiQuery.TemporalMode.SOFT_DELETED; + } } diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index e7682b8f8..0dcf9f773 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -110,7 +110,7 @@ public final class SqlTreeBuilder { this.queryDetail = query.getDetail(); this.predicates = predicates; - this.alias = new SqlTreeAlias(request.getBaseTableAlias()); + this.alias = new SqlTreeAlias(request.getBaseTableAlias(), temporalMode); this.distinctOnPlatform = builder.isPlatformDistinctOn(); String fromForUpdate = builder.fromForUpdate(query); diff --git a/src/test/java/org/tests/model/onetoone/OtoSdChild.java b/src/test/java/org/tests/model/onetoone/OtoSdChild.java new file mode 100644 index 000000000..2d60a7dfa --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoSdChild.java @@ -0,0 +1,73 @@ +package org.tests.model.onetoone; + +import io.ebean.Finder; +import io.ebean.annotation.SoftDelete; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class OtoSdChild { + + public static Finder find = new Finder<>(OtoSdChild.class); + + @Id + long id; + + String child; + + @SoftDelete + boolean deleted; + + @OneToOne + OtoSdMaster master; + + @Version + long version; + + public OtoSdChild(String child) { + this.child = child; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getChild() { + return child; + } + + public void setChild(String child) { + this.child = child; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public OtoSdMaster getMaster() { + return master; + } + + public void setMaster(OtoSdMaster master) { + this.master = master; + } + + public long getVersion() { + return version; + } + + public void setVersion(long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/onetoone/OtoSdMaster.java b/src/test/java/org/tests/model/onetoone/OtoSdMaster.java new file mode 100644 index 000000000..95e5f947c --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/OtoSdMaster.java @@ -0,0 +1,55 @@ +package org.tests.model.onetoone; + +import io.ebean.Finder; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +@Entity +public class OtoSdMaster { + + public static Finder find = new Finder<>(OtoSdMaster.class); + + @Id + long id; + + String name; + + @OneToOne(cascade = CascadeType.ALL, mappedBy = "master")//, fetch = FetchType.LAZY) + OtoSdChild child; + + @Version + long version; + + public OtoSdMaster(String name) { + this.name = name; + } + + 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 OtoSdChild getChild() { + return child; + } + + public void setChild(OtoSdChild child) { + this.child = child; + } + +} diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneSoftDeleteChild.java b/src/test/java/org/tests/model/onetoone/TestOneToOneSoftDeleteChild.java new file mode 100644 index 000000000..326f822dc --- /dev/null +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneSoftDeleteChild.java @@ -0,0 +1,47 @@ +package org.tests.model.onetoone; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestOneToOneSoftDeleteChild extends BaseTestCase { + + @Test + public void deleteChild() { + + + OtoSdChild child = new OtoSdChild("c1"); + OtoSdMaster master = new OtoSdMaster("m1"); + master.setChild(child); + + Ebean.save(master); + + + verifyBeforeDelete(master, child); + + Ebean.delete(child); + + verifyAfterDelete(master, child); + } + + private void verifyBeforeDelete(OtoSdMaster parent, OtoSdChild child) { + assertThat(OtoSdMaster.find.byId(parent.getId()).getChild().getId()) + .isEqualTo(child.getId()); + + assertThat( + OtoSdChild.find.byId(child.getId()).getMaster().getId()) + .isEqualTo(parent.getId()); + } + + private void verifyAfterDelete(OtoSdMaster parent, OtoSdChild child) { + // After delete, finding child by id should return null + assertThat(OtoSdChild.find.byId(child.getId())) + .isNull(); + + // After delete, getting linked child from parent should return null + assertThat(OtoSdMaster.find.byId(parent.getId()).getChild()) + .isNull(); + } +} From db25cb7bfbfa2a0061de3d9ad0f12d696b86f656 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 27 Aug 2018 21:44:38 +1200 Subject: [PATCH 0441/1036] [maven-release-plugin] prepare release ebean-11.22.3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 3c8fe96d4..5d2e45853 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.3-SNAPSHOT + 11.22.3 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.3 From bd3cb3c54775f5453244bd6528bc2292316a3c95 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 27 Aug 2018 21:44:54 +1200 Subject: [PATCH 0442/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5d2e45853..ad7f8491e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.3 + 11.22.4-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.3 + HEAD From 7809858634c3406cfc69ffc699af27a2af7b1323 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 31 Aug 2018 21:54:48 +1200 Subject: [PATCH 0443/1036] #1478 - MySql DDL, invalid comment included resulting in PersistenceException: Failed to run script --- .../dbmigration/builtin-extra-ddl.xml | 34 +++++++++---------- .../cache/TestQueryCacheTableDependency.java | 2 +- .../org/tests/model/composite/CkeUserKey.java | 8 ++--- .../migrationtest/mysql/I__create_procs.sql | 14 ++++---- .../sqlserver17/I__create_procs.sql | 20 +++++------ 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml index 1309cd7c7..825171455 100644 --- a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml +++ b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml @@ -13,16 +13,16 @@ if not exists (select name from sys.types where name = 'ebean_uniqueidentifier_ if not exists (select name from sys.types where name = 'ebean_nvarchar_tvp') create type ebean_nvarchar_tvp as table (c1 nvarchar(max)); delimiter $$ ------------------------------------------------------------ +-- -- PROCEDURE: usp_ebean_drop_indices TABLE, COLUMN -- deletes all indices referring to TABLE.COLUMN ------------------------------------------------------------ +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_indices @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) declare @indexName nvarchar(255) BEGIN - DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i + DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id where i.object_id = OBJECT_ID(@tableName) AND c.name = @columnName; @@ -41,10 +41,10 @@ END $$ delimiter $$ --------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_default_constraint TABLE, COLUMN -- deletes the default constraint, which has a random name --------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_default_constraint @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @tmp nvarchar(1000) @@ -58,16 +58,16 @@ END $$ delimiter $$ --------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_constraints TABLE, COLUMN -- deletes constraints and foreign keys refering to TABLE.COLUMN --------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_constraints @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) declare @constraintName nvarchar(255) BEGIN - DECLARE name_cursor CURSOR FOR + DECLARE name_cursor CURSOR FOR SELECT cc.name from sys.check_constraints cc join sys.columns c on c.object_id = cc.parent_object_id and c.column_id = cc.parent_column_id where parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName @@ -92,10 +92,10 @@ END $$ delimiter $$ -------------------------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN -- deletes the column annd ensures that all indices and constraints are dropped first -------------------------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_column @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) @@ -114,21 +114,21 @@ $$ 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 + 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 @@ -138,7 +138,7 @@ BEGIN PREPARE stmt FROM @sql; EXECUTE stmt; END LOOP; - + CLOSE curs; END $$ @@ -146,10 +146,10 @@ $$ 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); diff --git a/src/test/java/org/tests/cache/TestQueryCacheTableDependency.java b/src/test/java/org/tests/cache/TestQueryCacheTableDependency.java index 494d5c377..ee12f6794 100644 --- a/src/test/java/org/tests/cache/TestQueryCacheTableDependency.java +++ b/src/test/java/org/tests/cache/TestQueryCacheTableDependency.java @@ -72,7 +72,7 @@ public class TestQueryCacheTableDependency extends BaseTestCase { .findCount(); assertThat(custs).isEqualTo(1); - Ebean.createSqlUpdate("update O_ADDRESS set line_2=? where line_2=?") + Ebean.createSqlUpdate("update o_address set line_2=? where line_2=?") .setNextParameter("St Lucky3") .setNextParameter("St Lucky2") .execute(); diff --git a/src/test/java/org/tests/model/composite/CkeUserKey.java b/src/test/java/org/tests/model/composite/CkeUserKey.java index cb7655e19..637a10cf7 100644 --- a/src/test/java/org/tests/model/composite/CkeUserKey.java +++ b/src/test/java/org/tests/model/composite/CkeUserKey.java @@ -8,14 +8,14 @@ import java.util.Objects; @Embeddable public class CkeUserKey { - @Basic(optional = false) - @Column(name = "cod_cpny") - private int codCompany; - @Basic(optional = false) @Column(name = "username") private String username; + @Basic(optional = false) + @Column(name = "cod_cpny") + private int codCompany; + public CkeUserKey(int codCompany, String username) { this.codCompany = codCompany; this.username = username; diff --git a/src/test/resources/dbmigration/migrationtest/mysql/I__create_procs.sql b/src/test/resources/dbmigration/migrationtest/mysql/I__create_procs.sql index 581d9965a..55acf0bf3 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/I__create_procs.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/I__create_procs.sql @@ -2,21 +2,21 @@ 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 + 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 @@ -26,7 +26,7 @@ BEGIN PREPARE stmt FROM @sql; EXECUTE stmt; END LOOP; - + CLOSE curs; END $$ @@ -34,10 +34,10 @@ $$ 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); diff --git a/src/test/resources/dbmigration/migrationtest/sqlserver17/I__create_procs.sql b/src/test/resources/dbmigration/migrationtest/sqlserver17/I__create_procs.sql index 7ff3b383f..5c35dffc6 100644 --- a/src/test/resources/dbmigration/migrationtest/sqlserver17/I__create_procs.sql +++ b/src/test/resources/dbmigration/migrationtest/sqlserver17/I__create_procs.sql @@ -10,16 +10,16 @@ if not exists (select name from sys.types where name = 'ebean_uniqueidentifier_ if not exists (select name from sys.types where name = 'ebean_nvarchar_tvp') create type ebean_nvarchar_tvp as table (c1 nvarchar(max)); delimiter $$ ------------------------------------------------------------ +-- -- PROCEDURE: usp_ebean_drop_indices TABLE, COLUMN -- deletes all indices referring to TABLE.COLUMN ------------------------------------------------------------ +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_indices @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) declare @indexName nvarchar(255) BEGIN - DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i + DECLARE index_cursor CURSOR FOR SELECT i.name from sys.indexes i join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id join sys.columns c on c.object_id = ic.object_id and c.column_id = ic.column_id where i.object_id = OBJECT_ID(@tableName) AND c.name = @columnName; @@ -38,10 +38,10 @@ END $$ delimiter $$ --------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_default_constraint TABLE, COLUMN -- deletes the default constraint, which has a random name --------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_default_constraint @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @tmp nvarchar(1000) @@ -55,16 +55,16 @@ END $$ delimiter $$ --------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_constraints TABLE, COLUMN -- deletes constraints and foreign keys refering to TABLE.COLUMN --------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_constraints @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) declare @constraintName nvarchar(255) BEGIN - DECLARE name_cursor CURSOR FOR + DECLARE name_cursor CURSOR FOR SELECT cc.name from sys.check_constraints cc join sys.columns c on c.object_id = cc.parent_object_id and c.column_id = cc.parent_column_id where parent_object_id = OBJECT_ID(@tableName) AND c.name = @columnName @@ -89,10 +89,10 @@ END $$ delimiter $$ -------------------------------------------------------------------------------------- +-- -- PROCEDURE: usp_ebean_drop_column TABLE, COLUMN -- deletes the column annd ensures that all indices and constraints are dropped first -------------------------------------------------------------------------------------- +-- CREATE OR ALTER PROCEDURE usp_ebean_drop_column @tableName nvarchar(255), @columnName nvarchar(255) AS SET NOCOUNT ON declare @sql nvarchar(1000) From 7c1c144af559d92417ef1751c0630f4392d6fd57 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 31 Aug 2018 21:56:19 +1200 Subject: [PATCH 0444/1036] [maven-release-plugin] prepare release ebean-11.22.4 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ad7f8491e..1a0438040 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.4-SNAPSHOT + 11.22.4 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.4 From c81d329100adf54d469dc72805946329642f516f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 31 Aug 2018 21:56:34 +1200 Subject: [PATCH 0445/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1a0438040..a1bf35b2f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.4 + 11.22.5-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.4 + HEAD From 29d88d7de8bdee184887928102008bf0befb6f4b Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 20 Sep 2018 10:23:46 +0200 Subject: [PATCH 0446/1036] FIX: NPE in StalarTypeLocalTime and StalarTypeMonthDay (#1479) --- .../server/type/ScalarTypeLocalTime.java | 1 + .../type/ScalarTypeLocalTimeWithNanos.java | 1 + .../server/type/ScalarTypeMonthDay.java | 1 + .../tests/model/types/SomeNewTypesBean.java | 34 ++++++++++++++++ .../java/org/tests/types/TestNewTypes.java | 39 +++++++++++++++++++ 5 files changed, 76 insertions(+) diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTime.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTime.java index f4449b718..49a217951 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTime.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTime.java @@ -51,6 +51,7 @@ public class ScalarTypeLocalTime extends ScalarTypeBase { @Override public LocalTime toBeanType(Object value) { if (value instanceof LocalTime) return (LocalTime) value; + if (value == null) return null; return BasicTypeConverter.toTime(value).toLocalTime(); } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java index 9a39e3222..780820f02 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeLocalTimeWithNanos.java @@ -39,6 +39,7 @@ public class ScalarTypeLocalTimeWithNanos extends ScalarTypeLocalTime { @Override public LocalTime toBeanType(Object value) { if (value instanceof LocalTime) return (LocalTime) value; + if (value == null) return null; return LocalTime.ofNanoOfDay(BasicTypeConverter.toLong(value)); } diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java index 0afa5e865..3a3acdb3e 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeMonthDay.java @@ -72,6 +72,7 @@ public class ScalarTypeMonthDay extends ScalarTypeBase { @Override public MonthDay toBeanType(Object value) { if (value instanceof MonthDay) return (MonthDay) value; + if (value == null) return null; return convertFromDate((Date) value); } diff --git a/src/test/java/org/tests/model/types/SomeNewTypesBean.java b/src/test/java/org/tests/model/types/SomeNewTypesBean.java index 64f0a2220..35a133d8f 100644 --- a/src/test/java/org/tests/model/types/SomeNewTypesBean.java +++ b/src/test/java/org/tests/model/types/SomeNewTypesBean.java @@ -6,10 +6,13 @@ import javax.persistence.Id; import javax.persistence.Version; import java.nio.file.Path; import java.time.DayOfWeek; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.Month; +import java.time.MonthDay; import java.time.OffsetDateTime; import java.time.Period; import java.time.Year; @@ -39,6 +42,9 @@ public class SomeNewTypesBean { @Column(name = "yr_mth") YearMonth yearMonth; + @Column(name = "month_day") + MonthDay monthDay; + LocalDate localDate; LocalDateTime localDateTime; @@ -47,6 +53,8 @@ public class SomeNewTypesBean { ZonedDateTime zonedDateTime; + LocalTime localTime; + Instant instant; ZoneId zoneId; @@ -57,6 +65,8 @@ public class SomeNewTypesBean { Period period; + Duration duration; + public Long getId() { return id; } @@ -105,6 +115,14 @@ public class SomeNewTypesBean { this.yearMonth = yearMonth; } + public MonthDay getMonthDay() { + return monthDay; + } + + public void setMonthDay(MonthDay monthDay) { + this.monthDay = monthDay; + } + public LocalDate getLocalDate() { return localDate; } @@ -137,6 +155,14 @@ public class SomeNewTypesBean { this.zonedDateTime = zonedDateTime; } + public LocalTime getLocalTime() { + return localTime; + } + + public void setLocalTime(LocalTime localTime) { + this.localTime = localTime; + } + public Instant getInstant() { return instant; } @@ -176,4 +202,12 @@ public class SomeNewTypesBean { public void setPeriod(Period period) { this.period = period; } + + public Duration getDuration() { + return duration; + } + + public void setDuration(Duration duration) { + this.duration = duration; + } } diff --git a/src/test/java/org/tests/types/TestNewTypes.java b/src/test/java/org/tests/types/TestNewTypes.java index 4f2f15981..45578f6b1 100644 --- a/src/test/java/org/tests/types/TestNewTypes.java +++ b/src/test/java/org/tests/types/TestNewTypes.java @@ -11,10 +11,13 @@ import org.tests.model.types.SomeNewTypesBean; import java.io.File; import java.nio.file.Paths; import java.time.DayOfWeek; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.Month; +import java.time.MonthDay; import java.time.OffsetDateTime; import java.time.Period; import java.time.Year; @@ -37,6 +40,7 @@ public class TestNewTypes extends BaseTestCase { bean.setLocalDateTime(LocalDateTime.now()); bean.setOffsetDateTime(OffsetDateTime.now()); bean.setZonedDateTime(ZonedDateTime.now()); + bean.setLocalTime(LocalTime.now()); bean.setInstant(Instant.now()); bean.setYear(Year.now()); bean.setMonth(Month.APRIL); @@ -44,8 +48,10 @@ public class TestNewTypes extends BaseTestCase { bean.setZoneId(ZoneId.systemDefault()); bean.setZoneOffset(ZonedDateTime.now().getOffset()); bean.setYearMonth(YearMonth.of(2014, 9)); + bean.setMonthDay(MonthDay.of(9,22)); bean.setPath(Paths.get(TEMP_PATH)); bean.setPeriod(Period.of(4,3,2)); + bean.setDuration(Duration.ofMinutes(5)); Ebean.save(bean); @@ -70,6 +76,9 @@ public class TestNewTypes extends BaseTestCase { list = Ebean.find(SomeNewTypesBean.class).where().lt("zonedDateTime", ZonedDateTime.now()).findList(); assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().le("localTime", LocalTime.now()).findList(); + assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().eq("zoneId", ZoneId.systemDefault().getId()).findList(); assertTrue(!list.isEmpty()); @@ -79,6 +88,9 @@ public class TestNewTypes extends BaseTestCase { list = Ebean.find(SomeNewTypesBean.class).where().le("yearMonth", YearMonth.of(2014, 9)).findList(); assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().le("monthDay", MonthDay.of(9,22)).findList(); + assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().le("year", Year.now()).findList(); assertTrue(!list.isEmpty()); @@ -91,6 +103,9 @@ public class TestNewTypes extends BaseTestCase { list = Ebean.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList(); assertTrue(!list.isEmpty()); + list = Ebean.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList(); + assertTrue(!list.isEmpty()); + SomeNewTypesBean fetched = Ebean.find(SomeNewTypesBean.class, bean.getId()); assertEquals(bean.getZoneId(), fetched.getZoneId()); @@ -98,12 +113,15 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getMonth(), fetched.getMonth()); assertEquals(bean.getYear(), fetched.getYear()); assertEquals(bean.getYearMonth(), fetched.getYearMonth()); + assertEquals(bean.getMonthDay(), fetched.getMonthDay()); assertEquals(bean.getLocalDate(), fetched.getLocalDate()); assertThat(fetched.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime()); assertThat(fetched.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime()); + assertThat(fetched.getLocalTime().toSecondOfDay()).isEqualTo(bean.getLocalTime().toSecondOfDay()); assertEquals(bean.getInstant().toEpochMilli() / 1000, fetched.getInstant().toEpochMilli() / 1000); assertEquals(bean.getPath(), fetched.getPath()); assertEquals(bean.getPeriod(), fetched.getPeriod()); + assertEquals(bean.getDuration(), fetched.getDuration()); String asJson = Ebean.json().toJson(fetched); @@ -115,13 +133,16 @@ public class TestNewTypes extends BaseTestCase { assertEquals(bean.getMonth(), toBean.getMonth()); assertEquals(bean.getYear(), toBean.getYear()); assertEquals(bean.getYearMonth(), toBean.getYearMonth()); + assertEquals(bean.getMonthDay(), toBean.getMonthDay()); assertEquals(bean.getLocalDate(), toBean.getLocalDate()); assertThat(toBean.getLocalDateTime()).isEqualToIgnoringNanos(bean.getLocalDateTime()); assertThat(toBean.getOffsetDateTime()).isEqualToIgnoringNanos(bean.getOffsetDateTime()); + assertEquals(bean.getLocalTime().toSecondOfDay(), toBean.getLocalTime().toSecondOfDay()); assertEquals(bean.getInstant().toEpochMilli() / 1000, toBean.getInstant().toEpochMilli() / 1000); // FIXME: This test fails on Windows with: expected:<\tmp> but was: assertEquals(bean.getPath(), toBean.getPath()); assertEquals(bean.getPeriod(), toBean.getPeriod()); + assertEquals(bean.getDuration(), toBean.getDuration()); } @@ -139,12 +160,15 @@ public class TestNewTypes extends BaseTestCase { assertNull(fetched.getMonth()); assertNull(fetched.getYear()); assertNull(fetched.getYearMonth()); + assertNull(fetched.getMonthDay()); assertNull(fetched.getLocalDate()); assertNull(fetched.getLocalDateTime()); assertNull(fetched.getOffsetDateTime()); + assertNull(fetched.getLocalTime()); assertNull(fetched.getInstant()); assertNull(fetched.getPath()); assertNull(fetched.getPeriod()); + assertNull(fetched.getDuration()); } @Test @@ -154,6 +178,7 @@ public class TestNewTypes extends BaseTestCase { refBean.setLocalDateTime(LocalDateTime.now()); refBean.setOffsetDateTime(OffsetDateTime.now()); refBean.setZonedDateTime(ZonedDateTime.now()); + refBean.setLocalTime(LocalTime.now()); refBean.setInstant(Instant.now()); refBean.setYear(Year.now()); refBean.setMonth(Month.APRIL); @@ -161,8 +186,10 @@ public class TestNewTypes extends BaseTestCase { refBean.setZoneId(ZoneId.systemDefault()); refBean.setZoneOffset(ZonedDateTime.now().getOffset()); refBean.setYearMonth(YearMonth.of(2014, 9)); + refBean.setMonthDay(MonthDay.of( 9, 22)); refBean.setPath(Paths.get(TEMP_PATH)); refBean.setPeriod(Period.of(4,3,2)); + refBean.setDuration(Duration.ofMinutes(5)); testSetGetPath(refBean); } @@ -179,6 +206,7 @@ public class TestNewTypes extends BaseTestCase { ExpressionPath localDateTime = beanType.getExpressionPath("localDateTime"); ExpressionPath offsetDateTime = beanType.getExpressionPath("offsetDateTime"); ExpressionPath zonedDateTime = beanType.getExpressionPath("zonedDateTime"); + ExpressionPath localTime = beanType.getExpressionPath("localTime"); ExpressionPath instant = beanType.getExpressionPath("instant"); ExpressionPath year = beanType.getExpressionPath("year"); ExpressionPath month = beanType.getExpressionPath("month"); @@ -186,8 +214,10 @@ public class TestNewTypes extends BaseTestCase { ExpressionPath zoneId = beanType.getExpressionPath("zoneId"); ExpressionPath zoneOffset = beanType.getExpressionPath("zoneOffset"); ExpressionPath yearMonth = beanType.getExpressionPath("yearMonth"); + ExpressionPath monthDay = beanType.getExpressionPath("monthDay"); ExpressionPath path = beanType.getExpressionPath("path"); ExpressionPath period = beanType.getExpressionPath("period"); + ExpressionPath duration = beanType.getExpressionPath("duration"); localDate.pathSet(testBean, refBean.getLocalDate()); assertThat(localDate.pathGet(testBean)).isEqualTo(refBean.getLocalDate()); @@ -201,6 +231,9 @@ public class TestNewTypes extends BaseTestCase { zonedDateTime.pathSet(testBean, refBean.getZonedDateTime()); assertThat(zonedDateTime.pathGet(testBean)).isEqualTo(refBean.getZonedDateTime()); + localTime.pathSet(testBean, refBean.getLocalTime()); + assertThat(localTime.pathGet(testBean)).isEqualTo(refBean.getLocalTime()); + instant.pathSet(testBean, refBean.getInstant()); assertThat(instant.pathGet(testBean)).isEqualTo(refBean.getInstant()); @@ -222,12 +255,18 @@ public class TestNewTypes extends BaseTestCase { yearMonth.pathSet(testBean, refBean.getYearMonth()); assertThat(yearMonth.pathGet(testBean)).isEqualTo(refBean.getYearMonth()); + monthDay.pathSet(testBean, refBean.getMonthDay()); + assertThat(monthDay.pathGet(testBean)).isEqualTo(refBean.getMonthDay()); + path.pathSet(testBean, refBean.getPath()); assertThat(path.pathGet(testBean)).isEqualTo(refBean.getPath()); period.pathSet(testBean, refBean.getPeriod()); assertThat(period.pathGet(testBean)).isEqualTo(refBean.getPeriod()); + duration.pathSet(testBean, refBean.getDuration()); + assertThat(duration.pathGet(testBean)).isEqualTo(refBean.getDuration()); + Ebean.save(refBean); Ebean.save(testBean); } From 72845acbad6bb24752b6b81d99e29c8146aed69e Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 20 Sep 2018 10:24:33 +0200 Subject: [PATCH 0447/1036] FIX: JunctionExpression.notExists (#1481) --- .../io/ebeaninternal/server/expression/JunctionExpression.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java index b0329a1f0..04bdc0777 100644 --- a/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/JunctionExpression.java @@ -667,7 +667,7 @@ class JunctionExpression implements SpiJunction, SpiExpression, Expression @Override public ExpressionList notExists(Query subQuery) { - return exprList.exists(subQuery); + return exprList.notExists(subQuery); } @Override From 0e7dc4209c544f5be75f7ae7b66c88a46cb13fdd Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 21:09:01 +1200 Subject: [PATCH 0448/1036] #1482 - Improve error message for incorrect mapping - @JoinColumn without @ManyToOne etc --- .../server/deploy/parse/AnnotationAssocOnes.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index 0c3606bd3..bb0bac37d 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -132,6 +132,9 @@ public class AnnotationAssocOnes extends AnnotationParser { // check for manually defined joins BeanTable beanTable = prop.getBeanTable(); for (JoinColumn joinColumn : getAll(prop, JoinColumn.class)) { + if (beanTable == null) { + throw new IllegalStateException("Looks like a missing @ManyToOne or @OneToOne on property " + prop.getFullBeanName()+" - no related 'BeanTable'"); + } prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable); if (!joinColumn.updatable()) { prop.setDbUpdateable(false); @@ -146,6 +149,9 @@ public class AnnotationAssocOnes extends AnnotationParser { JoinTable joinTable = get(prop, JoinTable.class); if (joinTable != null) { for (JoinColumn joinColumn : joinTable.joinColumns()) { + if (beanTable == null) { + throw new IllegalStateException("Looks like a missing @ManyToOne or @OneToOne on property " + prop.getFullBeanName()+" - no related 'BeanTable'"); + } prop.getTableJoin().addJoinColumn(false, joinColumn, beanTable); if (!joinColumn.updatable()) { prop.setDbUpdateable(false); From 3a50c264b10e6be6992c6a2baa5846a7f0af478a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 21:10:41 +1200 Subject: [PATCH 0449/1036] No effective change - add test with softDelete on bean with history --- .../java/org/tests/model/history/HeLink.java | 13 ++++++++++++- .../model/history/TestHistoryExclude.java | 18 +++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/tests/model/history/HeLink.java b/src/test/java/org/tests/model/history/HeLink.java index 449bca72d..8bc4e2011 100644 --- a/src/test/java/org/tests/model/history/HeLink.java +++ b/src/test/java/org/tests/model/history/HeLink.java @@ -2,12 +2,12 @@ package org.tests.model.history; import io.ebean.annotation.History; import io.ebean.annotation.HistoryExclude; +import io.ebean.annotation.SoftDelete; import org.tests.model.draftable.BaseDomain; import javax.persistence.Entity; import javax.persistence.ManyToMany; import javax.persistence.Table; - import java.util.List; @History @@ -21,6 +21,9 @@ public class HeLink extends BaseDomain { String comments; + @SoftDelete + boolean deleted; + @HistoryExclude @ManyToMany List docs; @@ -33,6 +36,14 @@ public class HeLink extends BaseDomain { public HeLink() { } + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + public String getName() { return name; } diff --git a/src/test/java/org/tests/model/history/TestHistoryExclude.java b/src/test/java/org/tests/model/history/TestHistoryExclude.java index a8b4c746f..4193b6323 100644 --- a/src/test/java/org/tests/model/history/TestHistoryExclude.java +++ b/src/test/java/org/tests/model/history/TestHistoryExclude.java @@ -7,8 +7,9 @@ import io.ebean.annotation.Platform; import org.junit.Test; import java.sql.Timestamp; +import java.util.List; -import static org.assertj.core.api.StrictAssertions.assertThat; +import static org.assertj.core.api.Assertions.assertThat; public class TestHistoryExclude extends BaseTestCase { @@ -28,6 +29,21 @@ public class TestHistoryExclude extends BaseTestCase { } } + @Test + public void testSoftDelete() { + + HeLink l = new HeLink("two", "boo"); + Ebean.save(l); + + Ebean.delete(l); + + List list = Ebean.find(HeLink.class) + .setIncludeSoftDeletes() + .findList(); + + assertThat(list).isNotEmpty(); + } + @Test public void testLazyLoad() { From bb164a0763e5c5c868cf2e04e3f0be5c698b17df Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 21:32:48 +1200 Subject: [PATCH 0450/1036] OneToOne inserts with idType=SEQUENCE will fail #1480 --- src/test/java/org/tests/model/onetoone/OtoBChild.java | 4 ++-- .../tests/model/onetoone/TestOneToOneImportedPkNative.java | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/org/tests/model/onetoone/OtoBChild.java b/src/test/java/org/tests/model/onetoone/OtoBChild.java index 56c1b58a5..a91fce44b 100644 --- a/src/test/java/org/tests/model/onetoone/OtoBChild.java +++ b/src/test/java/org/tests/model/onetoone/OtoBChild.java @@ -3,8 +3,8 @@ package org.tests.model.onetoone; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; -import javax.persistence.JoinColumn; import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; @Entity public class OtoBChild { @@ -16,7 +16,7 @@ public class OtoBChild { String child; @OneToOne - @JoinColumn(name = "master_id", referencedColumnName = "id") + @PrimaryKeyJoinColumn OtoBMaster master; public Long getId() { diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java b/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java index 1ee9e17e9..3cb7e3319 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneImportedPkNative.java @@ -46,8 +46,8 @@ public class TestOneToOneImportedPkNative extends BaseTestCase { List lazyLoadSql = LoggedSqlCollector.stop(); assertThat(lazyLoadSql).hasSize(2); - assertThat(lazyLoadSql.get(0)).contains("select t0.id, t0.name, t1.master_id from oto_bmaster t0 left join oto_bchild t1"); - assertThat(lazyLoadSql.get(1)).contains("select t0.master_id, t0.child, t0.master_id from oto_bchild t0 where t0.master_id"); + assertThat(lazyLoadSql.get(0)).contains("select t0.id, t0.name, t0.id from oto_bmaster t0 where t0.id = ?"); + assertThat(lazyLoadSql.get(1)).contains("select t0.master_id, t0.child, t0.master_id from oto_bchild t0 where t0.master_id = ?"); } @Test @@ -64,12 +64,10 @@ public class TestOneToOneImportedPkNative extends BaseTestCase { assertThat(m.getId()).isEqualTo(one.getId()); assertThat(m.getName()).isEqualTo(one.getName()); - assertThat(m.getChild()).isNull(); OtoBMaster m2 = server.find(OtoBMaster.class, one.getId()); assertThat(m2.getId()).isEqualTo(one.getId()); assertThat(m2.getName()).isEqualTo(one.getName()); - assertThat(m2.getChild()).isNull(); } } From 42d3e9eb91ef7bb2e2e61a39cc9787a36e18563c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 21:35:08 +1200 Subject: [PATCH 0451/1036] [maven-release-plugin] prepare release ebean-11.22.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index a1bf35b2f..2ccc15c44 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.5-SNAPSHOT + 11.22.5 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.5 From be24e11b919ba2813db37897d0d1a37374f422ad Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 21:35:24 +1200 Subject: [PATCH 0452/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2ccc15c44..5b056dc3f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.5 + 11.22.6-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.5 + HEAD From 42f9e74d91a63a95e07be71ba0dc4e7b7620c59b Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 20 Sep 2018 23:12:26 +1200 Subject: [PATCH 0453/1036] #1483 - Invalid SQL with allQuotedIdentifiers true - where t0.[t0.[COND]] in (?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) --- .../server/deploy/DeployParser.java | 8 ++++-- .../deploy/DeployPropertyParserTest.java | 13 ++++++++++ .../org/tests/model/basic/BWithQIdent.java | 12 ++++++++- .../TestQuotedIdentifierQuery.java | 26 +++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index 75f0a3b1a..a5e71183e 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -22,6 +22,10 @@ public abstract class DeployParser { */ protected static final char UNDERSCORE = '_'; + protected static final char OPEN_SQUARE_BRACKET = '['; + protected static final char CLOSE_SQUARE_BRACKET = ']'; + protected static final char DOUBLE_QUOTE = '\"'; + /** * Used to determine when a column name terminates. */ @@ -183,10 +187,10 @@ public abstract class DeployParser { wordBuffer.append(ch); return false; } - return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD; + return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD || ch == DOUBLE_QUOTE || ch == CLOSE_SQUARE_BRACKET; } private boolean isWordStart(char ch) { - return Character.isLetter(ch) || ch == UNDERSCORE; + return Character.isLetter(ch) || ch == UNDERSCORE || ch == DOUBLE_QUOTE || ch == OPEN_SQUARE_BRACKET; } } diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index 10056984e..1c387aa49 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; import org.junit.Test; import org.tests.model.basic.Address; +import org.tests.model.basic.BWithQIdent; import org.tests.model.basic.Customer; import static org.assertj.core.api.Assertions.assertThat; @@ -14,6 +15,8 @@ public class DeployPropertyParserTest extends BaseTestCase { private final BeanDescriptor

    addressBeanDescriptor = getBeanDescriptor(Address.class); + private final BeanDescriptor bWithQIdentDescriptor = getBeanDescriptor(BWithQIdent.class); + @Test public void from_prefix_expect_unchanged() { assertThat(parser().parse("(select x from status join status)")).isEqualTo("(select x from status join status)"); @@ -49,6 +52,12 @@ public class DeployPropertyParserTest extends BaseTestCase { assertThat(addressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')"); } + @Test + public void withQuote_when_match() { + assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}\"Name\" like ?"); + assertThat(withQuoteParser().parse("t0.\"CODE\" like ?")).isEqualTo("t0.\"CODE\" like ?"); + } + @Test public void unknown_path() { assertThat(parser().parse(" foo ")).isEqualTo(" foo "); @@ -62,4 +71,8 @@ public class DeployPropertyParserTest extends BaseTestCase { return addressBeanDescriptor.parser(); } + private DeployPropertyParser withQuoteParser() { + return bWithQIdentDescriptor.parser(); + } + } diff --git a/src/test/java/org/tests/model/basic/BWithQIdent.java b/src/test/java/org/tests/model/basic/BWithQIdent.java index 329d40f41..fcb91cdb3 100644 --- a/src/test/java/org/tests/model/basic/BWithQIdent.java +++ b/src/test/java/org/tests/model/basic/BWithQIdent.java @@ -5,7 +5,6 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Version; import javax.validation.constraints.Size; - import java.sql.Timestamp; @Entity @@ -18,6 +17,9 @@ public class BWithQIdent { @Size(max = 191) // key must not exceed 767 Bytes, so max key len for mysql with utf8mb4 = 191*4 = 764 bytes String name; + @Column(name = "`CODE`") + String CODE; + @Version Timestamp lastUpdated; @@ -37,6 +39,14 @@ public class BWithQIdent { this.name = name; } + public String getCODE() { + return CODE; + } + + public void setCODE(String CODE) { + this.CODE = CODE; + } + public Timestamp getLastUpdated() { return lastUpdated; } diff --git a/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java b/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java new file mode 100644 index 000000000..90f6b3be8 --- /dev/null +++ b/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java @@ -0,0 +1,26 @@ +package org.tests.quotedidentifier; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; +import org.tests.model.basic.BWithQIdent; + +public class TestQuotedIdentifierQuery extends BaseTestCase { + + @Test + public void test() { + + BWithQIdent bean = new BWithQIdent(); + bean.setName("foo"); + bean.setCODE("bar"); + + Ebean.save(bean); + + Ebean.find(BWithQIdent.class) + .where() + .eq("name", "foo") + .raw("t0.\"Name\" = ?", "foo") + .raw("t0.\"CODE\" = ?", "bar") + .findList(); + } +} From eb7277aa13e292b7285944d1c31a8858479e9b2f Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 21 Sep 2018 05:35:01 +0200 Subject: [PATCH 0454/1036] Wrong behaviour in BeanMap.put/putAll (#1484) --- src/main/java/io/ebean/common/BeanMap.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/ebean/common/BeanMap.java b/src/main/java/io/ebean/common/BeanMap.java index 34bb51f9e..82a3c9853 100644 --- a/src/main/java/io/ebean/common/BeanMap.java +++ b/src/main/java/io/ebean/common/BeanMap.java @@ -273,14 +273,16 @@ public final class BeanMap extends AbstractBeanCollection implements Ma checkReadOnly(); init(); if (modifyListening) { - Object oldBean = map.put(key, value); + E oldBean = map.put(key, value); if (value != oldBean) { // register the add of the new and the removal of the old modifyAddition(value); modifyRemoval(oldBean); } + return oldBean; + } else { + return map.put(key, value); } - return map.put(key, value); } @Override @@ -295,8 +297,9 @@ public final class BeanMap extends AbstractBeanCollection implements Ma modifyRemoval(oldBean); } } + } else { + map.putAll(puts); } - map.putAll(puts); } @Override From 56e65d7463bf15af7e4abe5cff1fe57db956d132 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 21 Sep 2018 05:35:53 +0200 Subject: [PATCH 0455/1036] Fix issue in UUID-v1 generator on AWS Beanstalk (#1485) --- src/main/java/io/ebean/config/ServerConfig.java | 9 +++++++++ .../server/idgen/UuidV1IdGenerator.java | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 30e6e92f1..853c05858 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -1965,6 +1965,15 @@ public class ServerConfig { * Return the UUID state file. */ public String getUuidStateFile() { + if (uuidStateFile == null || uuidStateFile.isEmpty()) { + // by default, add servername... + uuidStateFile = name + "-uuid.state"; + // and store it in the user's home directory + String homeDir = System.getProperty("user.home"); + if (homeDir != null && homeDir.isEmpty()) { + uuidStateFile = homeDir + "/.ebean/" + uuidStateFile; + } + } return uuidStateFile; } diff --git a/src/main/java/io/ebeaninternal/server/idgen/UuidV1IdGenerator.java b/src/main/java/io/ebeaninternal/server/idgen/UuidV1IdGenerator.java index 0202ab816..19e94f4cd 100644 --- a/src/main/java/io/ebeaninternal/server/idgen/UuidV1IdGenerator.java +++ b/src/main/java/io/ebeaninternal/server/idgen/UuidV1IdGenerator.java @@ -82,8 +82,17 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator { final Enumeration e = NetworkInterface.getNetworkInterfaces(); while (e.hasMoreElements()) { NetworkInterface network = e.nextElement(); - if (!network.isLoopback()) { - return network.getHardwareAddress(); + try { + logger.trace("Probing interface {}", network); + if (!network.isLoopback()) { + byte[] addr = network.getHardwareAddress(); + if (addr != null) { + logger.debug("Using interface {}", network); + return addr; + } + } + } catch (SocketException ex) { + logger.debug("Skipping {}", network, ex); } } return null; @@ -181,6 +190,10 @@ public class UuidV1IdGenerator extends UuidV1RndIdGenerator { prop.setProperty("nodeId", getNodeIdentifier()); prop.setProperty("clockSeq", String.valueOf(clockSeq.get())); prop.setProperty("timeStamp", String.valueOf(timeStamp.get())); + File dir = stateFile.getParentFile(); + if (dir != null) { + dir.mkdirs(); + } try (OutputStream os = new FileOutputStream(stateFile)) { prop.store(os, "ebean uuid state file"); logger.debug("Persisted state to '{}'", stateFile); From 66703a3a295747b54406a9ab2dd8504daf6e20db Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Fri, 21 Sep 2018 05:38:21 +0200 Subject: [PATCH 0456/1036] FIX: recursive BatchedPstmtHolder.flush, when BeanPersistController or ChangeLogFilter hit the database (#1486) --- .../server/persist/BatchedPstmtHolder.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/persist/BatchedPstmtHolder.java b/src/main/java/io/ebeaninternal/server/persist/BatchedPstmtHolder.java index 100b2ff21..3ac38f6c0 100644 --- a/src/main/java/io/ebeaninternal/server/persist/BatchedPstmtHolder.java +++ b/src/main/java/io/ebeaninternal/server/persist/BatchedPstmtHolder.java @@ -110,7 +110,15 @@ public class BatchedPstmtHolder { // but still need to close PreparedStatements. boolean isError = false; - for (BatchedPstmt bs : stmtMap.values()) { + // if there are Listeners/Controllers that interact with the database, + // the flush may get called recursively in executeBatch/postExecute. + // which leads that we process stmtMap.values() twice in the loop. + // So we copy the values, that we want to flush and clear it immediately. + BatchedPstmt[] values = stmtMap.values().toArray(new BatchedPstmt[stmtMap.values().size()]); + clear(); + + // this loop + for (BatchedPstmt bs : values) { try { if (!isError) { bs.executeBatch(getGeneratedKeys); @@ -139,8 +147,6 @@ public class BatchedPstmtHolder { } } - // clear the batch cache - clear(); if (firstError != null) { String msg = "Error when batch flush on sql: " + errorSql; From cd1cdb027f902b28dadc0993ecb1f1c6d0ef3ec4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 24 Sep 2018 22:30:28 +1200 Subject: [PATCH 0457/1036] #1487 - @OneToOne Postgres with different Id types - error PSQLException: ERROR: operator does not exist: uuid = character varying Test --- .../uuidsibling/SoftDeleteCascadeTest.java | 66 +++++++++++++++++ .../tests/model/uuidsibling/USibChild.java | 70 +++++++++++++++++++ .../model/uuidsibling/USibChildSibling.java | 56 +++++++++++++++ .../tests/model/uuidsibling/USibParent.java | 52 ++++++++++++++ 4 files changed, 244 insertions(+) create mode 100644 src/test/java/org/tests/model/uuidsibling/SoftDeleteCascadeTest.java create mode 100644 src/test/java/org/tests/model/uuidsibling/USibChild.java create mode 100644 src/test/java/org/tests/model/uuidsibling/USibChildSibling.java create mode 100644 src/test/java/org/tests/model/uuidsibling/USibParent.java diff --git a/src/test/java/org/tests/model/uuidsibling/SoftDeleteCascadeTest.java b/src/test/java/org/tests/model/uuidsibling/SoftDeleteCascadeTest.java new file mode 100644 index 000000000..42cfa2a62 --- /dev/null +++ b/src/test/java/org/tests/model/uuidsibling/SoftDeleteCascadeTest.java @@ -0,0 +1,66 @@ +package org.tests.model.uuidsibling; + +import org.junit.Test; + +import java.util.UUID; + +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertThat; + +public class SoftDeleteCascadeTest { + + @Test + public void testDeleteParent() { + // Insert + link records + USibParent parent = new USibParent(); + parent.save(); + + USibChild child = new USibChild(parent); + child.save(); + + USibChildSibling childSibling = new USibChildSibling(child); + childSibling.save(); + + Long parentId = parent.getId(); + UUID childId = child.getId(); + Long childSiblingId = childSibling.getId(); + + assertBefore(parent, child, childSibling); + parent.delete(); + assertAfter(parentId, childId, childSiblingId); + } + + private void assertBefore(USibParent parent, USibChild child, USibChildSibling childSibling) { + + parent.refresh(); + + assertThat("Parent should have one child loaded", + parent.getChildren().size(), + is(1) + ); + + assertThat("Parent should have correct child loaded", + parent.getChildren().get(0).getId(), + is(child.getId()) + ); + + assertThat("Child that was loaded should have its sibling available", + parent.getChildren().get(0).getChildSibling(), + not(nullValue()) + ); + + assertThat( + "Child that was loaded should have loaded correct sibling", + parent.getChildren().get(0).getChildSibling().getId(), + is(childSibling.getId()) + ); + } + + private void assertAfter(Long parentId, UUID childId, Long childSiblingId) { + assertThat(USibParent.find.byId(parentId), is(nullValue())); + assertThat(USibChild.find.byId(childId), is(nullValue())); + assertThat(USibChildSibling.find.byId(childSiblingId), is(nullValue())); + } +} diff --git a/src/test/java/org/tests/model/uuidsibling/USibChild.java b/src/test/java/org/tests/model/uuidsibling/USibChild.java new file mode 100644 index 000000000..b2ff59e42 --- /dev/null +++ b/src/test/java/org/tests/model/uuidsibling/USibChild.java @@ -0,0 +1,70 @@ +package org.tests.model.uuidsibling; + +import io.ebean.Finder; +import io.ebean.Model; +import io.ebean.annotation.SoftDelete; +import java.util.UUID; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; + +@Entity +public class USibChild extends Model { + + private static final long serialVersionUID = 738194912181571389L; + + @Id + private UUID id; + + @SoftDelete + private boolean deleted; + + @OneToOne(mappedBy = "child", cascade = CascadeType.REMOVE) + private USibChildSibling childSibling; + + @ManyToOne + private USibParent parent; + + public static Finder find = new Finder<>(USibChild.class); + + public USibChild() {} + + public USibChild(USibParent parent) { + this.parent = parent; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public USibChildSibling getChildSibling() { + return childSibling; + } + + public USibChild setChildSibling(USibChildSibling childSibling) { + this.childSibling = childSibling; + return this; + } + + public USibParent getParent() { + return parent; + } + + public void setParent(USibParent parent) { + this.parent = parent; + } +} diff --git a/src/test/java/org/tests/model/uuidsibling/USibChildSibling.java b/src/test/java/org/tests/model/uuidsibling/USibChildSibling.java new file mode 100644 index 000000000..888c1cc88 --- /dev/null +++ b/src/test/java/org/tests/model/uuidsibling/USibChildSibling.java @@ -0,0 +1,56 @@ +package org.tests.model.uuidsibling; + +import io.ebean.Finder; +import io.ebean.Model; +import io.ebean.annotation.SoftDelete; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; + +@Entity +public class USibChildSibling extends Model { + + private static final long serialVersionUID = 738194912181571389L; + + @Id + private Long id; + + @SoftDelete + private boolean deleted; + + @OneToOne + private USibChild child; + + public static Finder find = new Finder<>(USibChildSibling.class); + + public USibChildSibling() {} + + public USibChildSibling(USibChild child) { + this.child = child; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public USibChild getChild() { + return child; + } + + public USibChildSibling setChild(USibChild child) { + this.child = child; + return this; + } +} diff --git a/src/test/java/org/tests/model/uuidsibling/USibParent.java b/src/test/java/org/tests/model/uuidsibling/USibParent.java new file mode 100644 index 000000000..a7e349d12 --- /dev/null +++ b/src/test/java/org/tests/model/uuidsibling/USibParent.java @@ -0,0 +1,52 @@ +package org.tests.model.uuidsibling; + +import io.ebean.Finder; +import io.ebean.Model; +import io.ebean.annotation.SoftDelete; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class USibParent extends Model { + + private static final long serialVersionUID = 4116545858939406149L; + + @Id + private Long id; + + @SoftDelete + private boolean deleted; + + @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "parent") + private List children; + + public static Finder find = new Finder<>(USibParent.class); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public List getChildren() { + return children; + } + + public USibParent setChildren(List children) { + this.children = children; + return this; + } +} From 0e75c50be5b7c73399aaf155159891c0a24ebc0f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 24 Sep 2018 22:30:45 +1200 Subject: [PATCH 0458/1036] #1487 - @OneToOne Postgres with different Id types - error PSQLException: ERROR: operator does not exist: uuid = character varying Fix --- .../ebeaninternal/server/deploy/BeanPropertyAssocOne.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index 8f8e3b66e..bd3455d90 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -261,7 +261,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr private List findIdsByParentIdList(List parentIds, Transaction t) { String rawWhere = deriveWhereParentIdSql(true); - String inClause = targetIdBinder.getIdInValueExpr(false, parentIds.size()); + String inClause = getIdBinder().getIdInValueExpr(false, parentIds.size()); String expr = rawWhere + inClause; SpiEbeanServer server = server(); @@ -537,8 +537,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr BeanProperty[] emIds = targetDesc.propertiesBaseScalar(); try { for (BeanProperty emId : emIds) { - ExportedProperty expProp = findMatch(true, emId); - list.add(expProp); + list.add(findMatch(true, emId)); } } catch (PersistenceException e) { // not found as individual scalar properties @@ -547,8 +546,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc implements STr } else { if (idProp != null) { - ExportedProperty expProp = findMatch(false, idProp); - list.add(expProp); + list.add(findMatch(false, idProp)); } } From ef46bc86cce1fe95a21ad0aba78ddeec83edfeef Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:40:56 +0200 Subject: [PATCH 0459/1036] Original Value and bean change was not computed correctly in changelog (#1488) * Bug in Changelog: It takes the first non null value as oldValue and does not detect if oldValue == newValue * CHANGE: EntityBeanIntercept uses bitflags instead of separate boolean arrays - new flag 'origValueSet' introduced - getDirtyValues checks, if values are really different. --- .../io/ebean/bean/EntityBeanIntercept.java | 141 +++++++++--------- .../org/tests/changelog/TestChangeLog.java | 69 +++++++++ 2 files changed, 140 insertions(+), 70 deletions(-) diff --git a/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/src/main/java/io/ebean/bean/EntityBeanIntercept.java index e35384ad4..fcd6bb7ad 100644 --- a/src/main/java/io/ebean/bean/EntityBeanIntercept.java +++ b/src/main/java/io/ebean/bean/EntityBeanIntercept.java @@ -71,21 +71,30 @@ public final class EntityBeanIntercept implements Serializable { /** * Used when a bean is partially filled. */ - private final boolean[] loadedProps; - - private boolean fullyLoadedBean; + private static final byte FLAG_LOADED_PROP = 1; /** * Set of changed properties. */ - private boolean[] changedProps; + private static final byte FLAG_CHANGED_PROP = 2; /** * Flags indicating if a property is a dirty embedded bean. Used to distingush * between an embedded bean being completely overwritten and one of its * embedded properties being made dirty. */ - private boolean[] embeddedDirty; + private static final byte FLAG_EMBEDDED_DIRTY = 4; + + /** + * Flags indicating if a property is a dirty embedded bean. Used to distingush + * between an embedded bean being completely overwritten and one of its + * embedded properties being made dirty. + */ + private static final byte FLAG_ORIG_VALUE_SET = 8; + + private final byte[] flags; + + private boolean fullyLoadedBean; private Object[] origValues; @@ -102,7 +111,7 @@ public final class EntityBeanIntercept implements Serializable { */ public EntityBeanIntercept(Object ownerBean) { this.owner = (EntityBean) ownerBean; - this.loadedProps = new boolean[owner._ebean_getPropertyNames().length]; + this.flags = new byte[owner._ebean_getPropertyNames().length]; } /** @@ -213,8 +222,8 @@ public final class EntityBeanIntercept implements Serializable { * Check each property to see if the bean is partially loaded. */ public boolean isPartial() { - for (boolean loadedProp : loadedProps) { - if (!loadedProp) { + for (byte flag : flags) { + if ((flag & FLAG_LOADED_PROP) == 0) { return true; } } @@ -259,10 +268,10 @@ public final class EntityBeanIntercept implements Serializable { * Return true if only the Id property has been loaded. */ public boolean hasIdOnly(int idIndex) { - for (int i = 0; i < loadedProps.length; i++) { + for (int i = 0; i < flags.length; i++) { if (i == idIndex) { - if (!loadedProps[i]) return false; - } else if (loadedProps[i]) { + if ((flags[i] & FLAG_LOADED_PROP) == 0) return false; + } else if ((flags[i] & FLAG_LOADED_PROP) != 0) { return false; } } @@ -284,9 +293,9 @@ public final class EntityBeanIntercept implements Serializable { if (idPos > -1) { // For cases where properties are set on constructor // set every non Id property to unloaded (for lazy loading) - for (int i = 0; i < loadedProps.length; i++) { + for (int i = 0; i < flags.length; i++) { if (i != idPos) { - loadedProps[i] = false; + flags[i] &= ~FLAG_LOADED_PROP; } } } @@ -352,7 +361,9 @@ public final class EntityBeanIntercept implements Serializable { this.owner._ebean_setEmbeddedLoaded(); this.lazyLoadProperty = -1; this.origValues = null; - this.changedProps = null; + for (int i = 0; i < flags.length; i++) { + flags[i] &= ~(FLAG_CHANGED_PROP + FLAG_ORIG_VALUE_SET); + } this.dirty = false; } @@ -475,7 +486,11 @@ public final class EntityBeanIntercept implements Serializable { if (position == -1) { throw new IllegalArgumentException("Property " + propertyName + " not found"); } - loadedProps[position] = loaded; + if (loaded) { + flags[position] |= FLAG_LOADED_PROP; + } else { + flags[position] &= ~FLAG_LOADED_PROP; + } } /** @@ -483,22 +498,22 @@ public final class EntityBeanIntercept implements Serializable { * constructor. */ public void setPropertyUnloaded(int propertyIndex) { - loadedProps[propertyIndex] = false; + flags[propertyIndex] &= ~FLAG_LOADED_PROP; } /** * Set the property to be loaded. */ public void setLoadedProperty(int propertyIndex) { - loadedProps[propertyIndex] = true; + flags[propertyIndex] |= FLAG_LOADED_PROP; } /** * Set all properties to be loaded (post insert). */ public void setLoadedPropertyAll() { - for (int i = 0; i < loadedProps.length; i++) { - loadedProps[i] = true; + for (int i = 0; i < flags.length; i++) { + flags[i] |= FLAG_LOADED_PROP; } } @@ -506,14 +521,14 @@ public final class EntityBeanIntercept implements Serializable { * Return true if the property is loaded. */ public boolean isLoadedProperty(int propertyIndex) { - return loadedProps[propertyIndex]; + return (flags[propertyIndex] & FLAG_LOADED_PROP) != 0; } /** * Return true if the property is considered changed. */ public boolean isChangedProperty(int propertyIndex) { - return (changedProps != null && changedProps[propertyIndex]); + return (flags[propertyIndex] & FLAG_CHANGED_PROP) != 0; } /** @@ -521,8 +536,7 @@ public final class EntityBeanIntercept implements Serializable { * embedded properties is dirty. */ public boolean isDirtyProperty(int propertyIndex) { - return (changedProps != null && changedProps[propertyIndex] - || embeddedDirty != null && embeddedDirty[propertyIndex]); + return (flags[propertyIndex] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0; } /** @@ -534,27 +548,22 @@ public final class EntityBeanIntercept implements Serializable { } public void setChangedProperty(int propertyIndex) { - if (changedProps == null) { - changedProps = new boolean[owner._ebean_getPropertyNames().length]; - } - changedProps[propertyIndex] = true; + flags[propertyIndex] |= FLAG_CHANGED_PROP; } /** * Set that an embedded bean has had one of its properties changed. */ private void setEmbeddedPropertyDirty(int propertyIndex) { - if (embeddedDirty == null) { - embeddedDirty = new boolean[owner._ebean_getPropertyNames().length]; - } - embeddedDirty[propertyIndex] = true; + flags[propertyIndex] |= FLAG_EMBEDDED_DIRTY; } private void setOriginalValue(int propertyIndex, Object value) { if (origValues == null) { origValues = new Object[owner._ebean_getPropertyNames().length]; } - if (origValues[propertyIndex] == null) { + if ((flags[propertyIndex] & FLAG_ORIG_VALUE_SET) == 0) { + flags[propertyIndex] |= FLAG_ORIG_VALUE_SET; origValues[propertyIndex] = value; } } @@ -574,13 +583,9 @@ public final class EntityBeanIntercept implements Serializable { */ public void setNewBeanForUpdate() { - if (changedProps == null) { - changedProps = new boolean[owner._ebean_getPropertyNames().length]; - } - - for (int i = 0; i < loadedProps.length; i++) { - if (loadedProps[i]) { - changedProps[i] = true; + for (int i = 0; i < flags.length; i++) { + if ((flags[i] & FLAG_LOADED_PROP) != 0) { + flags[i] |= FLAG_CHANGED_PROP; } } setDirty(true); @@ -594,8 +599,8 @@ public final class EntityBeanIntercept implements Serializable { return null; } Set props = new LinkedHashSet<>(); - for (int i = 0; i < loadedProps.length; i++) { - if (loadedProps[i]) { + for (int i = 0; i < flags.length; i++) { + if ((flags[i] & FLAG_LOADED_PROP) != 0) { props.add(getProperty(i)); } } @@ -609,12 +614,8 @@ public final class EntityBeanIntercept implements Serializable { int len = getPropertyLength(); boolean[] dirties = new boolean[len]; for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { - dirties[i] = true; - } else if (embeddedDirty != null && embeddedDirty[i]) { - // an embedded property has been changed - recurse - dirties[i] = true; - } + // this, or an embedded property has been changed - recurse + dirties[i] = (flags[i] & (FLAG_CHANGED_PROP + FLAG_EMBEDDED_DIRTY)) != 0; } return dirties; } @@ -634,11 +635,11 @@ public final class EntityBeanIntercept implements Serializable { public void addDirtyPropertyNames(Set props, String prefix) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { + if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // the property has been changed on this bean String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i)); props.add(propName); - } else if (embeddedDirty != null && embeddedDirty[i]) { + } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); embeddedBean._ebean_getIntercept().addDirtyPropertyNames(props, getProperty(i) + "."); @@ -654,12 +655,12 @@ public final class EntityBeanIntercept implements Serializable { String[] names = owner._ebean_getPropertyNames(); int len = getPropertyLength(); for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { + if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // the property has been changed on this bean if (propertyNames.contains(names[i])) { return true; } - } else if (embeddedDirty != null && embeddedDirty[i]) { + } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { if (propertyNames.contains(names[i])) { return true; } @@ -683,15 +684,16 @@ public final class EntityBeanIntercept implements Serializable { public void addDirtyPropertyValues(Map dirtyValues, String prefix) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { + if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // the property has been changed on this bean String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i)); Object newVal = owner._ebean_getField(i); Object oldVal = getOrigValue(i); + if (!areEqual(oldVal, newVal)) { + dirtyValues.put(propName, new ValuePair(newVal, oldVal)); + } - dirtyValues.put(propName, new ValuePair(newVal, oldVal)); - - } else if (embeddedDirty != null && embeddedDirty[i]) { + } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); embeddedBean._ebean_getIntercept().addDirtyPropertyValues(dirtyValues, getProperty(i) + "."); @@ -705,13 +707,15 @@ public final class EntityBeanIntercept implements Serializable { public void addDirtyPropertyValues(BeanDiffVisitor visitor) { int len = getPropertyLength(); for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { + if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // the property has been changed on this bean Object newVal = owner._ebean_getField(i); Object oldVal = getOrigValue(i); - visitor.visit(i, newVal, oldVal); + if (!areEqual(oldVal, newVal)) { + visitor.visit(i, newVal, oldVal); + } - } else if (embeddedDirty != null && embeddedDirty[i]) { + } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); visitor.visitPush(i); @@ -739,9 +743,9 @@ public final class EntityBeanIntercept implements Serializable { } int len = getPropertyLength(); for (int i = 0; i < len; i++) { - if (changedProps != null && changedProps[i]) { + if ((flags[i] & FLAG_CHANGED_PROP) != 0) { sb.append(i).append(','); - } else if (embeddedDirty != null && embeddedDirty[i]) { + } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { // an embedded property has been changed - recurse EntityBean embeddedBean = (EntityBean) owner._ebean_getField(i); sb.append(i).append('['); @@ -765,15 +769,12 @@ public final class EntityBeanIntercept implements Serializable { return sb; } - /** - * Return the set of property names for changed properties. - */ - public boolean[] getChanged() { - return changedProps; - } - public boolean[] getLoaded() { - return loadedProps; + boolean[] ret= new boolean[flags.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = (flags[i] & FLAG_LOADED_PROP) != 0; + } + return ret; } /** @@ -821,7 +822,7 @@ public final class EntityBeanIntercept implements Serializable { */ private void loadBeanInternal(int loadProperty, BeanLoader loader) { - if (loadedProps == null || loadedProps[loadProperty]) { + if ((flags[loadProperty] & FLAG_LOADED_PROP) != 0) { // race condition where multiple threads calling preGetter concurrently return; } @@ -887,7 +888,7 @@ public final class EntityBeanIntercept implements Serializable { * Called when a BeanCollection is initialised automatically. */ public void initialisedMany(int propertyIndex) { - loadedProps[propertyIndex] = true; + flags[propertyIndex] |= FLAG_LOADED_PROP; } private void preGetterCallback(int propertyIndex) { diff --git a/src/test/java/org/tests/changelog/TestChangeLog.java b/src/test/java/org/tests/changelog/TestChangeLog.java index d253c9173..9b906a8fd 100644 --- a/src/test/java/org/tests/changelog/TestChangeLog.java +++ b/src/test/java/org/tests/changelog/TestChangeLog.java @@ -5,11 +5,13 @@ import io.ebean.EbeanServerFactory; import io.ebean.annotation.ChangeLog; import io.ebean.config.ServerConfig; import io.ebean.event.BeanPersistRequest; +import io.ebean.event.changelog.BeanChange; import io.ebean.event.changelog.ChangeLogFilter; import io.ebean.event.changelog.ChangeLogListener; import io.ebean.event.changelog.ChangeLogPrepare; import io.ebean.event.changelog.ChangeLogRegister; import io.ebean.event.changelog.ChangeSet; +import io.ebean.event.changelog.ChangeType; import io.ebeaninternal.api.SpiEbeanServer; import org.tests.model.basic.EBasicChangeLog; import com.fasterxml.jackson.annotation.JsonInclude; @@ -18,8 +20,12 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; +import java.util.List; + public class TestChangeLog extends BaseTestCase { TDChangeLogPrepare changeLogPrepare = new TDChangeLogPrepare(); @@ -47,14 +53,77 @@ public class TestChangeLog extends BaseTestCase { bean.setName("logBean"); bean.setShortDescription("hello"); server.save(bean); + BeanChange change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.INSERT); + assertThat(change.getData()) + .contains("\"name\":\"logBean\"") + .contains("\"shortDescription\":\"hello\""); + bean.setName("ChangedName"); server.save(bean); + change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.UPDATE); + assertThat(change.getOldData()).contains("\"name\":\"logBean\""); + assertThat(change.getData()) .contains("\"name\":\"ChangedName\""); + + server.delete(bean); + change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.DELETE); + assertThat(change.getData()).isNull(); + } + + @Test + public void testWithNull() { + + EBasicChangeLog bean = new EBasicChangeLog(); + bean.setName(null); + bean.setShortDescription("hello"); + server.save(bean); + BeanChange change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.INSERT); + assertThat(change.getData()) + .doesNotContain("\"name\"") + .contains("\"shortDescription\":\"hello\""); + + + bean.setName("log"); + bean.setName("logBean"); + bean.setShortDescription("world"); + bean.setShortDescription("hello"); + server.save(bean); + + change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.UPDATE); + assertThat(change.getOldData()) + .contains("\"name\":null") // it was null + .doesNotContain("\"shortDescription\""); // it is unchanged + + assertThat(change.getData()) + .contains("\"name\":\"logBean\"") + .doesNotContain("\"shortDescription\""); // it is unchanged + + + server.delete(bean); + + change = changeLogListener.changes.getChanges().get(0); + + assertThat(change.getEvent()).isEqualTo(ChangeType.DELETE); + assertThat(change.getData()).isNull(); + + } + + private SpiEbeanServer getServer() { System.setProperty("ebean.ignoreExtraDdl", "true"); From 7e995efb6229a54b590a2ca3180b9702cd2c6090 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:48:19 +0200 Subject: [PATCH 0460/1036] Add methods th the plugin API to access type and inheritance information (#1491) --- src/main/java/io/ebean/plugin/BeanType.java | 30 +++++++++++++++++++ src/main/java/io/ebean/plugin/Property.java | 9 ++++++ .../server/deploy/BeanDescriptor.java | 29 ++++++++++++++++++ .../server/deploy/BeanProperty.java | 3 ++ 4 files changed, 71 insertions(+) diff --git a/src/main/java/io/ebean/plugin/BeanType.java b/src/main/java/io/ebean/plugin/BeanType.java index 2f00cd0af..bb487de35 100644 --- a/src/main/java/io/ebean/plugin/BeanType.java +++ b/src/main/java/io/ebean/plugin/BeanType.java @@ -9,6 +9,10 @@ import io.ebean.event.BeanQueryAdapter; import io.ebeanservice.docstore.api.mapping.DocumentMapping; import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; + +import javax.annotation.Nonnull; /** * Information and methods on BeanDescriptors made available to plugins. @@ -18,6 +22,7 @@ public interface BeanType { /** * Return the short name of the bean type. */ + @Nonnull String getName(); /** @@ -28,11 +33,13 @@ public interface BeanType { /** * Return the full name of the bean type. */ + @Nonnull String getFullName(); /** * Return the class type this BeanDescriptor describes. */ + @Nonnull Class getBeanType(); /** @@ -43,6 +50,7 @@ public interface BeanType { /** * Return all the properties for this bean type. */ + @Nonnull Collection allProperties(); /** @@ -197,6 +205,28 @@ public interface BeanType { */ boolean hasInheritance(); + /** + * Return true if this object is the root level object in its entity + * inheritance. + */ + boolean isInheritanceRoot(); + + /** + * Returns all direct children of this beantype + */ + List> getInheritanceChildren(); + + /** + * Returns the parent in inheritance hiearchy + */ + BeanType getInheritanceParent(); + + /** + * Visit all children recursively + * @param visitor + */ + void visitAllInheritanceChildren(Consumer> visitor); + /** * Return the discriminator column. */ diff --git a/src/main/java/io/ebean/plugin/Property.java b/src/main/java/io/ebean/plugin/Property.java index e3e9d2c3e..20d81d7e5 100644 --- a/src/main/java/io/ebean/plugin/Property.java +++ b/src/main/java/io/ebean/plugin/Property.java @@ -1,5 +1,7 @@ package io.ebean.plugin; +import javax.annotation.Nonnull; + /** * Property of a entity bean that can be read. */ @@ -8,8 +10,15 @@ public interface Property { /** * Return the name of the property. */ + @Nonnull String getName(); + /** + * Return the type of the property. + */ + @Nonnull + Class getPropertyType(); + /** * Return the value of the property on the given bean. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 4a0c711d5..f114970f9 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -100,6 +100,7 @@ import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; @@ -107,6 +108,8 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import java.util.stream.Collectors; /** * Describes Beans including their deployment information. @@ -1133,6 +1136,7 @@ public class BeanDescriptor implements BeanType, STreeType { * Return true if this object is the root level object in its entity * inheritance. */ + @Override public boolean isInheritanceRoot() { return inheritInfo == null || inheritInfo.isRoot(); } @@ -3475,4 +3479,29 @@ public class BeanDescriptor implements BeanType, STreeType { public List getUniqueProps() { return propertiesUnique; } + + @Override + public List> getInheritanceChildren() { + if (hasInheritance()) { + return getInheritInfo().getChildren() + .stream() + .map(InheritInfo::desc) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + @Override + public BeanType getInheritanceParent() { + return getInheritInfo() == null ? null : getInheritInfo().getParent().desc(); + } + + @Override + public void visitAllInheritanceChildren(Consumer> visitor) { + if (hasInheritance()) { + getInheritInfo().visitChildren(info -> visitor.accept(info.desc())); + } + } + } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 7473e01aa..8b0650f54 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -979,6 +979,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { /** * Return the full name of this property. */ + @Override public String getFullBeanName() { return descriptor.getFullName() + "." + name; } @@ -994,6 +995,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { /** * Return the scalarType. */ + @Override @SuppressWarnings(value = "unchecked") public ScalarType getScalarType() { return scalarType; @@ -1369,6 +1371,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { /** * Return the property type. */ + @Override public Class getPropertyType() { return propertyType; } From 5522d56e8da0b2604b6ccc0afce7a7a46f4979d4 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:48:49 +0200 Subject: [PATCH 0461/1036] ignored tests for sqlserver, because there is no nested transaction support, yet (#1493) --- .../tests/transaction/TestNestedSubTransaction.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java index 05eeed4d8..dc9e3d147 100644 --- a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java +++ b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java @@ -20,7 +20,7 @@ public class TestNestedSubTransaction extends BaseTestCase { /** * MySql only supports named savepoints - review. */ - @IgnorePlatform(Platform.MYSQL) + @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER}) @Test public void ebeanServer_commitTransaction_expect_sameAsTransactionCommit() { @@ -65,7 +65,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } - @IgnorePlatform(Platform.MYSQL) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) @Test public void nestedUseSavepoint_doubleNested_rollbackCommit() { @@ -102,7 +102,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } } - @IgnorePlatform(Platform.MYSQL) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) @Test public void nestedUseSavepoint_doubleNested_commitRollback() { @@ -139,7 +139,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } } - @IgnorePlatform(Platform.MYSQL) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) @Test public void nestedUseSavepoint_nested_RequiresNew() { @@ -175,7 +175,7 @@ public class TestNestedSubTransaction extends BaseTestCase { assertNull(after); } - @IgnorePlatform(Platform.MYSQL) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) @Test public void nestedUseSavepoint() { From fe71c7cc4e1f38e285f559a4915fdcd1c6bd4760 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:54:22 +0200 Subject: [PATCH 0462/1036] FIX: tableName detection for native statements on SQLServer (#1494) --- .../java/io/ebeaninternal/server/query/CQueryBuilder.java | 4 +++- .../java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index cd1dc413c..8fb718024 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -417,7 +417,9 @@ class CQueryBuilder { BeanDescriptor desc = request.getBeanDescriptor(); try { - PreparedStatement statement = connection.prepareStatement(sql); + // For SqlServer we need either "selectMethod=cursor" in the connection string or fetch explicitly a cursorable + // statement here by specifying ResultSet.CONCUR_UPDATABLE + PreparedStatement statement = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); predicates.bind(statement, connection); ResultSet resultSet = statement.executeQuery(); diff --git a/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java b/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java index 94f7219a4..1ab49cda3 100644 --- a/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java +++ b/src/test/java/org/tests/rawsql/nativesql/TestNativeSqlBasic.java @@ -139,7 +139,7 @@ public class TestNativeSqlBasic extends BaseTestCase { * Oracle does not support getTableName() via JDBC resultSet meta data */ @Test - @IgnorePlatform({Platform.SQLSERVER, Platform.ORACLE}) // does only work in 'cursor' mode! + @IgnorePlatform({Platform.ORACLE}) public void partialAssoc() { ResetBasicData.reset(); From a83a4fa1c4ea6041d5f33e80be62ba7c160ab1a4 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:55:39 +0200 Subject: [PATCH 0463/1036] FIX: check platform on multiple annotations like '@Formula(platform=...)' (#1495) --- .../io/ebeaninternal/server/deploy/parse/AnnotationBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationBase.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationBase.java index f86cac704..3d6e6b7d4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationBase.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationBase.java @@ -82,12 +82,12 @@ public abstract class AnnotationBase { T a = null; Field field = prop.getField(); if (field != null) { - a = AnnotationUtil.findAnnotation(field, annClass); + a = AnnotationUtil.findAnnotation(field, annClass, platform); } if (a == null) { Method method = prop.getReadMethod(); if (method != null) { - a = AnnotationUtil.findAnnotation(method, annClass); + a = AnnotationUtil.findAnnotation(method, annClass, platform); } } return a; From eb1ea5ddd2f5d358a56cbcf9d1384fbbfde2fada Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 10:57:33 +0200 Subject: [PATCH 0464/1036] NEW: collation support for orderBy (#1492) --- src/main/java/io/ebean/OrderBy.java | 63 +++++++++++++++++-- .../tests/unitinternal/TestOrderByParse.java | 47 ++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/ebean/OrderBy.java b/src/main/java/io/ebean/OrderBy.java index e9f68f6f5..438396109 100644 --- a/src/main/java/io/ebean/OrderBy.java +++ b/src/main/java/io/ebean/OrderBy.java @@ -5,6 +5,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import io.ebean.util.StringHelper; + /** * Represents an Order By for a Query. *

    @@ -74,6 +76,15 @@ public final class OrderBy implements Serializable { return query; } + /** + * Add a property with ascending order to this OrderBy. + */ + public Query asc(String propertyName, String collation) { + + list.add(new Property(propertyName, true, collation)); + return query; + } + /** * Add a property with descending order to this OrderBy. */ @@ -83,6 +94,16 @@ public final class OrderBy implements Serializable { return query; } + /** + * Add a property with descending order to this OrderBy. + */ + public Query desc(String propertyName, String collation) { + + list.add(new Property(propertyName, false, collation)); + return query; + } + + /** * Return true if the property is known to be contained in the order by clause. */ @@ -231,6 +252,8 @@ public final class OrderBy implements Serializable { private boolean ascending; + private String collation; + private String nulls; private String highLow; @@ -247,17 +270,32 @@ public final class OrderBy implements Serializable { this.highLow = highLow; } + public Property(String property, boolean ascending, String collation) { + this.property = property; + this.ascending = ascending; + this.collation = collation; + } + + public Property(String property, boolean ascending, String collation, String nulls, String highLow) { + this.property = property; + this.ascending = ascending; + this.collation = collation; + this.nulls = nulls; + this.highLow = highLow; + } + /** * Return a copy of this Property with the path trimmed. */ public Property copyWithTrim(String path) { - return new Property(property.substring(path.length() + 1), ascending, nulls, highLow); + return new Property(property.substring(path.length() + 1), ascending, collation, nulls, highLow); } @Override public int hashCode() { int hc = property.hashCode(); hc = hc * 92821 + (ascending ? 0 : 1); + hc = hc * 92821 + (collation == null ? 0 : collation.hashCode()); hc = hc * 92821 + (nulls == null ? 0 : nulls.hashCode()); hc = hc * 92821 + (highLow == null ? 0 : highLow.hashCode()); return hc; @@ -273,6 +311,7 @@ public final class OrderBy implements Serializable { } Property e = (Property) obj; if (ascending != e.ascending) return false; + if (collation != e.collation) return false; if (!property.equals(e.property)) return false; if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false; return highLow != null ? highLow.equals(e.highLow) : e.highLow == null; @@ -284,7 +323,7 @@ public final class OrderBy implements Serializable { } public String toStringFormat() { - if (nulls == null) { + if (nulls == null && collation == null) { if (ascending) { return property; } else { @@ -292,11 +331,25 @@ public final class OrderBy implements Serializable { } } else { StringBuilder sb = new StringBuilder(); - sb.append(property); + + // collate + if (collation != null) { + if (collation.contains("${}")) { + // this is a complex collation, e.g. DB2 - we must replace the property + sb.append(StringHelper.replaceString(collation, "${}", property)); + } else { + sb.append(property); + sb.append(" COLLATE ").append(collation); + } + } else { + sb.append(property); + } if (!ascending) { sb.append(" ").append("desc"); } - sb.append(" ").append(nulls).append(" ").append(highLow); + if (nulls != null) { + sb.append(" ").append(nulls).append(" ").append(highLow); + } return sb.toString(); } } @@ -319,7 +372,7 @@ public final class OrderBy implements Serializable { * Return a copy of this property. */ public Property copy() { - return new Property(property, ascending, nulls, highLow); + return new Property(property, ascending, collation, nulls, highLow); } /** diff --git a/src/test/java/org/tests/unitinternal/TestOrderByParse.java b/src/test/java/org/tests/unitinternal/TestOrderByParse.java index 5fc876353..0dc23eccb 100644 --- a/src/test/java/org/tests/unitinternal/TestOrderByParse.java +++ b/src/test/java/org/tests/unitinternal/TestOrderByParse.java @@ -153,4 +153,51 @@ public class TestOrderByParse extends BaseTestCase { assertEquals("id, name", copy.toStringFormat()); } + + @Test + public void testParsingWithCollation() { + + OrderBy o1 = new OrderBy<>(); + o1.asc("id", "latin_1"); + assertTrue(o1.getProperties().size() == 1); + assertTrue(o1.getProperties().get(0).getProperty().equals("id")); + assertTrue(o1.getProperties().get(0).isAscending()); + assertEquals("id COLLATE latin_1", o1.toStringFormat()); + + o1 = new OrderBy<>(); + o1.desc("id", "latin_1"); + assertTrue(o1.getProperties().size() == 1); + assertTrue(o1.getProperties().get(0).getProperty().equals("id")); + assertTrue(!o1.getProperties().get(0).isAscending()); + assertEquals("id COLLATE latin_1 desc", o1.toStringFormat()); + + o1 = new OrderBy<>(); + o1.desc("id", "latin_1"); + o1.asc("date"); + assertTrue(o1.getProperties().size() == 2); + assertTrue(o1.getProperties().get(0).getProperty().equals("id")); + assertTrue(o1.getProperties().get(1).getProperty().equals("date")); + assertTrue(!o1.getProperties().get(0).isAscending()); + assertTrue(o1.getProperties().get(1).isAscending()); + assertEquals("id COLLATE latin_1 desc, date", o1.toStringFormat()); + + o1 = new OrderBy<>(); + o1.desc("id", "latin_1"); + o1.asc("name", "latin_2"); + assertTrue(o1.getProperties().size() == 2); + assertTrue(o1.getProperties().get(0).getProperty().equals("id")); + assertTrue(o1.getProperties().get(1).getProperty().equals("name")); + assertTrue(!o1.getProperties().get(0).isAscending()); + assertTrue(o1.getProperties().get(1).isAscending()); + assertEquals("id COLLATE latin_1 desc, name COLLATE latin_2", o1.toStringFormat()); + + // functional (DB2) syntax + o1 = new OrderBy<>(); + o1.desc("id", "COLLATION_KEY(${}, 'latin_1')"); + assertTrue(o1.getProperties().size() == 1); + assertTrue(o1.getProperties().get(0).getProperty().equals("id")); + assertTrue(!o1.getProperties().get(0).isAscending()); + assertEquals("COLLATION_KEY(id, 'latin_1') desc", o1.toStringFormat()); + + } } From efa86043bfa64f8b7fcd0946ca22bb72a8a5ed77 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Sep 2018 21:15:41 +1200 Subject: [PATCH 0465/1036] #1492 - Update for NEW: collation support for orderBy --- src/main/java/io/ebean/OrderBy.java | 15 +++--- .../tests/unitinternal/TestOrderByParse.java | 54 +++++++++++++++++-- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/ebean/OrderBy.java b/src/main/java/io/ebean/OrderBy.java index 438396109..7ce78f340 100644 --- a/src/main/java/io/ebean/OrderBy.java +++ b/src/main/java/io/ebean/OrderBy.java @@ -1,11 +1,12 @@ package io.ebean; +import io.ebean.util.StringHelper; + import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import io.ebean.util.StringHelper; +import java.util.Objects; /** * Represents an Order By for a Query. @@ -311,10 +312,10 @@ public final class OrderBy implements Serializable { } Property e = (Property) obj; if (ascending != e.ascending) return false; - if (collation != e.collation) return false; if (!property.equals(e.property)) return false; - if (nulls != null ? !nulls.equals(e.nulls) : e.nulls != null) return false; - return highLow != null ? highLow.equals(e.highLow) : e.highLow == null; + if (!Objects.equals(collation, e.collation)) return false; + if (!Objects.equals(nulls, e.nulls)) return false; + return Objects.equals(highLow, e.highLow); } @Override @@ -331,15 +332,13 @@ public final class OrderBy implements Serializable { } } else { StringBuilder sb = new StringBuilder(); - - // collate if (collation != null) { if (collation.contains("${}")) { // this is a complex collation, e.g. DB2 - we must replace the property sb.append(StringHelper.replaceString(collation, "${}", property)); } else { sb.append(property); - sb.append(" COLLATE ").append(collation); + sb.append(" collate ").append(collation); } } else { sb.append(property); diff --git a/src/test/java/org/tests/unitinternal/TestOrderByParse.java b/src/test/java/org/tests/unitinternal/TestOrderByParse.java index 0dc23eccb..37ea83782 100644 --- a/src/test/java/org/tests/unitinternal/TestOrderByParse.java +++ b/src/test/java/org/tests/unitinternal/TestOrderByParse.java @@ -4,7 +4,10 @@ import io.ebean.BaseTestCase; import io.ebean.OrderBy; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; /** * Test the OrderBy object and especially its parsing. @@ -162,14 +165,14 @@ public class TestOrderByParse extends BaseTestCase { assertTrue(o1.getProperties().size() == 1); assertTrue(o1.getProperties().get(0).getProperty().equals("id")); assertTrue(o1.getProperties().get(0).isAscending()); - assertEquals("id COLLATE latin_1", o1.toStringFormat()); + assertEquals("id collate latin_1", o1.toStringFormat()); o1 = new OrderBy<>(); o1.desc("id", "latin_1"); assertTrue(o1.getProperties().size() == 1); assertTrue(o1.getProperties().get(0).getProperty().equals("id")); assertTrue(!o1.getProperties().get(0).isAscending()); - assertEquals("id COLLATE latin_1 desc", o1.toStringFormat()); + assertEquals("id collate latin_1 desc", o1.toStringFormat()); o1 = new OrderBy<>(); o1.desc("id", "latin_1"); @@ -179,7 +182,7 @@ public class TestOrderByParse extends BaseTestCase { assertTrue(o1.getProperties().get(1).getProperty().equals("date")); assertTrue(!o1.getProperties().get(0).isAscending()); assertTrue(o1.getProperties().get(1).isAscending()); - assertEquals("id COLLATE latin_1 desc, date", o1.toStringFormat()); + assertEquals("id collate latin_1 desc, date", o1.toStringFormat()); o1 = new OrderBy<>(); o1.desc("id", "latin_1"); @@ -189,7 +192,7 @@ public class TestOrderByParse extends BaseTestCase { assertTrue(o1.getProperties().get(1).getProperty().equals("name")); assertTrue(!o1.getProperties().get(0).isAscending()); assertTrue(o1.getProperties().get(1).isAscending()); - assertEquals("id COLLATE latin_1 desc, name COLLATE latin_2", o1.toStringFormat()); + assertEquals("id collate latin_1 desc, name collate latin_2", o1.toStringFormat()); // functional (DB2) syntax o1 = new OrderBy<>(); @@ -200,4 +203,45 @@ public class TestOrderByParse extends BaseTestCase { assertEquals("COLLATION_KEY(id, 'latin_1') desc", o1.toStringFormat()); } + + @Test + public void equals_with_nulls() { + + OrderBy o1 = new OrderBy<>("id desc nulls high"); + OrderBy o2 = new OrderBy<>("id desc nulls high"); + OrderBy o3 = new OrderBy<>(); + o3.add("id desc nulls high"); + + assertEquals(o1, o2); + assertEquals(o1, o3); + + + OrderBy o4 = new OrderBy<>("id desc"); + OrderBy o5 = new OrderBy<>("oid desc nulls high"); + OrderBy o6 = new OrderBy<>("id desc nulls low"); + + assertNotEquals(o1, o4); + assertNotEquals(o1, o5); + assertNotEquals(o1, o6); + } + + @Test + public void equals_with_collation() { + + OrderBy o1 = new OrderBy<>(); + o1.asc("name", "latin_1"); + + OrderBy o2 = new OrderBy<>(); + o2.asc("name", null); + + OrderBy o3 = new OrderBy<>(); + o2.asc("name", "bar"); + + assertNotEquals(o1, o2); + assertNotEquals(o1, o3); + + OrderBy o4 = new OrderBy<>(); + o4.asc("name", "latin_1"); + assertEquals(o1, o4); + } } From a020bb15a1e88604f221efdb05cbe6d0d7cd9cd3 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 11:19:28 +0200 Subject: [PATCH 0466/1036] removed the concat-operator "||" and replaced with "concat()" (#1489) * removed the concat-operator "||" and replaced with "concat()" * using || in postgres * FIX: Assert-statement --- .../config/dbplatform/DatabasePlatform.java | 9 -------- .../server/expression/InPairsExpression.java | 12 +++++----- .../expression/platform/BaseDbExpression.java | 22 +++++++++---------- .../platform/BasicDbExpression.java | 4 ---- .../platform/DbExpressionHandler.java | 10 ++++----- .../platform/DbExpressionHandlerFactory.java | 15 +++++++------ .../expression/platform/H2DbExpression.java | 4 ---- .../platform/MySqlDbExpression.java | 4 ---- .../platform/OracleDbExpression.java | 4 ---- .../platform/PostgresDbExpression.java | 16 ++++++++++---- .../platform/SqlServerDbExpression.java | 4 ---- .../cache/TestCacheViaComplexNaturalKey3.java | 16 +++++++------- 12 files changed, 49 insertions(+), 71 deletions(-) diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 65bdfff4c..152cd3588 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -64,8 +64,6 @@ public class DatabasePlatform { */ protected String closeQuote = "\""; - protected String concatOperator = "||"; - /** * When set to true all db column names and table names use quoted identifiers. */ @@ -455,13 +453,6 @@ public class DatabasePlatform { return openQuote; } - /** - * Return the DB concat operator. - */ - public String getConcatOperator() { - return concatOperator; - } - /** * Return the JDBC type used to store booleans. */ diff --git a/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java b/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java index 91f6742d6..9b2c5c5f1 100644 --- a/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java @@ -92,14 +92,12 @@ class InPairsExpression extends AbstractExpression { return; } - String concat = request.getDbPlatformHandler().getConcatOperator(); - String concatFormula = "(" + property0 + concat + "'" + separator + "'" + concat + property1; - if (suffix != null && !suffix.isEmpty()) { - concatFormula += concat + "'" + suffix + "'"; - } - concatFormula += ")"; - request.append(concatFormula); + StringBuilder sb = new StringBuilder(); + + request.getDbPlatformHandler().concat(property0, separator, property1, suffix); + + request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix)); request.appendInExpression(not, concatBindValues); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java index 584215d4c..8879c84f4 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -8,17 +8,6 @@ import io.ebeaninternal.server.expression.BitwiseOp; */ abstract class BaseDbExpression implements DbExpressionHandler { - private final String concatOperator; - - BaseDbExpression(String concatOperator) { - this.concatOperator = concatOperator; - } - - @Override - public String getConcatOperator() { - return concatOperator; - } - @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { @@ -57,4 +46,15 @@ abstract class BaseDbExpression implements DbExpressionHandler { } } + @Override + public String concat(String property0, String separator, String property1, String suffix) { + StringBuilder sb = new StringBuilder(); + sb.append("CONCAT(").append(property0).append(",'").append(separator).append("',").append(property1); + + if (suffix != null && !suffix.isEmpty()) { + sb.append(",'").append(suffix).append('\''); + } + sb.append(')'); + return sb.toString(); + } } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java index adacca04d..8b5ab8d70 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java @@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op; */ public class BasicDbExpression extends BaseDbExpression { - BasicDbExpression(String concatOperator) { - super(concatOperator); - } - @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { throw new RuntimeException("JSON expressions only supported on Postgres and Oracle"); diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java index 7cf6d696a..93c9dc18a 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java @@ -9,11 +9,6 @@ import io.ebeaninternal.server.expression.Op; */ public interface DbExpressionHandler { - /** - * Return the DB concat operator (Usually SQL standard "||"). - */ - String getConcatOperator(); - /** * Write the db platform specific json expression. */ @@ -33,4 +28,9 @@ public interface DbExpressionHandler { * Add the bitwise expression. */ void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match); + + /** + * Performs a "CONCAT" operation for that platform. + */ + String concat(String property0, String separator, String property1, String suffix); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java index b7b62eb71..e9696e5b6 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java @@ -12,20 +12,21 @@ public class DbExpressionHandlerFactory { public static DbExpressionHandler from(DatabasePlatform databasePlatform) { Platform platform = databasePlatform.getPlatform(); - String concatOperator = databasePlatform.getConcatOperator(); switch (platform) { case H2: - return new H2DbExpression(concatOperator); + return new H2DbExpression(); case POSTGRES: - return new PostgresDbExpression(concatOperator); + return new PostgresDbExpression(); case MYSQL: - return new MySqlDbExpression(concatOperator); + return new MySqlDbExpression(); case ORACLE: - return new OracleDbExpression(concatOperator); + return new OracleDbExpression(); + case SQLSERVER16: + case SQLSERVER17: case SQLSERVER: - return new SqlServerDbExpression(concatOperator); + return new SqlServerDbExpression(); default: - return new BasicDbExpression(concatOperator); + return new BasicDbExpression(); } } } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java index 4e0b544f2..fb65c7c03 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.BitwiseOp; */ class H2DbExpression extends BasicDbExpression { - H2DbExpression(String concatOperator) { - super(concatOperator); - } - @Override public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java index e0e04ad1f..dff49e0b2 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -5,8 +5,4 @@ package io.ebeaninternal.server.expression.platform; */ class MySqlDbExpression extends BasicDbExpression { - MySqlDbExpression(String concatOperator) { - super(concatOperator); - } - } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index 4347d2e80..168f01aaf 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -9,10 +9,6 @@ import io.ebeaninternal.server.expression.Op; */ public class OracleDbExpression extends BaseDbExpression { - OracleDbExpression(String concatOperator) { - super(concatOperator); - } - @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index 4af9aa2f7..adac971b5 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op; */ public class PostgresDbExpression extends BaseDbExpression { - PostgresDbExpression(String concatOperator) { - super(concatOperator); - } - @Override public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { @@ -65,4 +61,16 @@ public class PostgresDbExpression extends BaseDbExpression { request.append(" <> 0"); } } + + @Override + public String concat(String property0, String separator, String property1, String suffix) { + StringBuilder sb = new StringBuilder(); + sb.append("(").append(property0).append("||'").append(separator).append("'||").append(property1); + + if (suffix != null && !suffix.isEmpty()) { + sb.append("||'").append(suffix).append('\''); + } + sb.append(')'); + return sb.toString(); + } } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index dc52066e3..98d76ec43 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -8,10 +8,6 @@ import io.ebeaninternal.server.expression.Op; */ public class SqlServerDbExpression extends BaseDbExpression { - SqlServerDbExpression(String concatOperator) { - super(concatOperator); - } - @Override public void json(final SpiExpressionRequest request, final String propName, final String path, final Op operator, final Object value) { diff --git a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index 7f584c378..c9e698890 100644 --- a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -4,8 +4,6 @@ import io.ebean.BaseTestCase; import io.ebean.CacheMode; import io.ebean.Ebean; import io.ebean.Pairs; -import io.ebean.annotation.IgnorePlatform; -import io.ebean.annotation.Platform; import io.ebean.cache.ServerCache; import io.ebean.cache.ServerCacheManager; import io.ebean.cache.ServerCacheStatistics; @@ -251,7 +249,6 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertBeanCacheHitMiss(0, 0); } - @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER}) @Test public void findList_inPairs_standardConcat() { @@ -280,14 +277,15 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertBeanCacheHitMiss(1, 0); if (isH2()) { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); - } else { + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,'-',t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); + } else if (isPostgres()) { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)"); + } else { + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,'-',t0.code)"); } } - @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER}) @Test public void findList_inPairs_userConcat() { @@ -318,9 +316,11 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertBeanCacheHitMiss(1, 0); if (isH2()) { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); - } else { + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,':',t0.code,'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); + } else if (isPostgres()){ assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')"); + } else { + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,':',t0.code,'-foo')"); } } From 0036473971478abd92afb3b7435872a60b8ac465 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Sep 2018 21:23:14 +1200 Subject: [PATCH 0467/1036] #1489 - removed the concat-operator "||" and replaced with "concat()" --- .../server/expression/InPairsExpression.java | 5 ----- .../server/expression/platform/BaseDbExpression.java | 3 +-- .../model/basic/cache/TestCacheViaComplexNaturalKey3.java | 8 ++++---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java b/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java index 9b2c5c5f1..2147af1a2 100644 --- a/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/InPairsExpression.java @@ -92,11 +92,6 @@ class InPairsExpression extends AbstractExpression { return; } - - StringBuilder sb = new StringBuilder(); - - request.getDbPlatformHandler().concat(property0, separator, property1, suffix); - request.append(request.getDbPlatformHandler().concat(property0, separator, property1, suffix)); request.appendInExpression(not, concatBindValues); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java index 8879c84f4..40ae04a1d 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -49,8 +49,7 @@ abstract class BaseDbExpression implements DbExpressionHandler { @Override public String concat(String property0, String separator, String property1, String suffix) { StringBuilder sb = new StringBuilder(); - sb.append("CONCAT(").append(property0).append(",'").append(separator).append("',").append(property1); - + sb.append("concat(").append(property0).append(",'").append(separator).append("',").append(property1); if (suffix != null && !suffix.isEmpty()) { sb.append(",'").append(suffix).append('\''); } diff --git a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index c9e698890..9a42ea601 100644 --- a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -277,11 +277,11 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertBeanCacheHitMiss(1, 0); if (isH2()) { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,'-',t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); } else if (isPostgres()) { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)"); } else { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,'-',t0.code)"); + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code)"); } } @@ -316,11 +316,11 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertBeanCacheHitMiss(1, 0); if (isH2()) { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,':',t0.code,'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); } else if (isPostgres()){ assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')"); } else { - assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and CONCAT(t0.sku,':',t0.code,'-foo')"); + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo')"); } } From b817d5ee4d05cf3045d01fdcc14da3881aa78555 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 26 Sep 2018 11:26:29 +0200 Subject: [PATCH 0468/1036] FIX: withQuote_when:_match for different platforms (#1490) --- .../deploy/DeployPropertyParserTest.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index 1c387aa49..f7d40815d 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -1,6 +1,9 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; + import org.junit.Test; import org.tests.model.basic.Address; import org.tests.model.basic.BWithQIdent; @@ -53,11 +56,26 @@ public class DeployPropertyParserTest extends BaseTestCase { } @Test - public void withQuote_when_match() { + @ForPlatform(value = {Platform.H2, Platform.POSTGRES}) + public void withQuote_when_match_h2() { assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}\"Name\" like ?"); assertThat(withQuoteParser().parse("t0.\"CODE\" like ?")).isEqualTo("t0.\"CODE\" like ?"); } + @Test + @ForPlatform(value = Platform.SQLSERVER) + public void withQuote_when_match_sqlserver() { + assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}[Name] like ?"); + assertThat(withQuoteParser().parse("t0.[CODE] like ?")).isEqualTo("t0.[CODE] like ?"); + } + + @Test + @ForPlatform(value = Platform.MYSQL) + public void withQuote_when_match_mysql() { + assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}`Name` like ?"); + assertThat(withQuoteParser().parse("t0.`CODE` like ?")).isEqualTo("t0.`CODE` like ?"); + } + @Test public void unknown_path() { assertThat(parser().parse(" foo ")).isEqualTo(" foo "); From 9734ae57875ce688d8c9bab5d4c0558ac5507e4a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Sep 2018 21:33:27 +1200 Subject: [PATCH 0469/1036] #1490 - FIX: withQuote_when_match for different platforms --- .../io/ebeaninternal/server/deploy/DeployParser.java | 5 +++-- .../server/deploy/DeployPropertyParserTest.java | 11 +++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java index a5e71183e..ecbfeb0a8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java +++ b/src/main/java/io/ebeaninternal/server/deploy/DeployParser.java @@ -25,6 +25,7 @@ public abstract class DeployParser { protected static final char OPEN_SQUARE_BRACKET = '['; protected static final char CLOSE_SQUARE_BRACKET = ']'; protected static final char DOUBLE_QUOTE = '\"'; + protected static final char BACK_QUOTE = '`'; /** * Used to determine when a column name terminates. @@ -187,10 +188,10 @@ public abstract class DeployParser { wordBuffer.append(ch); return false; } - return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD || ch == DOUBLE_QUOTE || ch == CLOSE_SQUARE_BRACKET; + return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD || ch == DOUBLE_QUOTE || ch == CLOSE_SQUARE_BRACKET || ch == BACK_QUOTE; } private boolean isWordStart(char ch) { - return Character.isLetter(ch) || ch == UNDERSCORE || ch == DOUBLE_QUOTE || ch == OPEN_SQUARE_BRACKET; + return Character.isLetter(ch) || ch == UNDERSCORE || ch == DOUBLE_QUOTE || ch == OPEN_SQUARE_BRACKET || ch == BACK_QUOTE; } } diff --git a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java index f7d40815d..bb7d4e20a 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/DeployPropertyParserTest.java @@ -3,7 +3,6 @@ package io.ebeaninternal.server.deploy; import io.ebean.BaseTestCase; import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; - import org.junit.Test; import org.tests.model.basic.Address; import org.tests.model.basic.BWithQIdent; @@ -55,25 +54,29 @@ public class DeployPropertyParserTest extends BaseTestCase { assertThat(addressParser().parse("concat(line1, line2, '-EA')")).isEqualTo("concat(${}line_1, ${}line_2, '-EA')"); } + @Test + public void withExplicitQuote_all_platforms() { + assertThat(withQuoteParser().parse("t0.`CODE` like ?")).isEqualTo("t0.`CODE` like ?"); + assertThat(withQuoteParser().parse("t0.[CODE] like ?")).isEqualTo("t0.[CODE] like ?"); + assertThat(withQuoteParser().parse("t0.\"CODE\" like ?")).isEqualTo("t0.\"CODE\" like ?"); + } + @Test @ForPlatform(value = {Platform.H2, Platform.POSTGRES}) public void withQuote_when_match_h2() { assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}\"Name\" like ?"); - assertThat(withQuoteParser().parse("t0.\"CODE\" like ?")).isEqualTo("t0.\"CODE\" like ?"); } @Test @ForPlatform(value = Platform.SQLSERVER) public void withQuote_when_match_sqlserver() { assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}[Name] like ?"); - assertThat(withQuoteParser().parse("t0.[CODE] like ?")).isEqualTo("t0.[CODE] like ?"); } @Test @ForPlatform(value = Platform.MYSQL) public void withQuote_when_match_mysql() { assertThat(withQuoteParser().parse("name like ?")).isEqualTo("${}`Name` like ?"); - assertThat(withQuoteParser().parse("t0.`CODE` like ?")).isEqualTo("t0.`CODE` like ?"); } @Test From 6a616144302b4bb78ed87c724ba077fee314446c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Sep 2018 23:38:42 +1200 Subject: [PATCH 0470/1036] [maven-release-plugin] prepare release ebean-11.22.6 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5b056dc3f..116b59e48 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.6-SNAPSHOT + 11.22.6 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.6 From 3409f264ece552efcecf721e47c14fee8c92b174 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 26 Sep 2018 23:38:57 +1200 Subject: [PATCH 0471/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 116b59e48..c6f265724 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.6 + 11.22.7-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.6 + HEAD From 57056d7abd391e6399e72dba2cf70c2af898db59 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 28 Sep 2018 16:33:54 +1200 Subject: [PATCH 0472/1036] #1496 - Query label lost for findId() --- .../java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index da8a39f51..b2f294b02 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -768,6 +768,7 @@ public class DefaultOrmQuery implements SpiQuery { copy.timeout = timeout; copy.mapKey = mapKey; copy.id = id; + copy.label = label; copy.useBeanCache = useBeanCache; copy.useQueryCache = useQueryCache; copy.readOnly = readOnly; From 2c044301853b50cabeb0fb0bd750dec4614453c4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 17:14:53 +1300 Subject: [PATCH 0473/1036] No effective change - add testSoftDelete_includeSoftDeletes_findOne --- .../model/history/TestHistoryExclude.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/tests/model/history/TestHistoryExclude.java b/src/test/java/org/tests/model/history/TestHistoryExclude.java index 4193b6323..0132f9d7f 100644 --- a/src/test/java/org/tests/model/history/TestHistoryExclude.java +++ b/src/test/java/org/tests/model/history/TestHistoryExclude.java @@ -30,7 +30,7 @@ public class TestHistoryExclude extends BaseTestCase { } @Test - public void testSoftDelete() { + public void testSoftDelete_includeSoftDeletes_findList() { HeLink l = new HeLink("two", "boo"); Ebean.save(l); @@ -44,6 +44,23 @@ public class TestHistoryExclude extends BaseTestCase { assertThat(list).isNotEmpty(); } + @Test + public void testSoftDelete_includeSoftDeletes_findOne() { + + HeLink l = new HeLink("three", "boo2"); + Ebean.save(l); + + Ebean.delete(l); + + HeLink found = Ebean.find(HeLink.class) + .setId(l.getId()) + .setIncludeSoftDeletes() + .findOne(); + + assertThat(found).isNotNull(); + assertThat(found.getName()).isEqualTo("three"); + } + @Test public void testLazyLoad() { From c27749ae2d2d6a18c5c5b54c433f2e9b51904633 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 19:59:36 +1300 Subject: [PATCH 0474/1036] #1497 - SQL Error with @History + @SoftDelete + @OneToOne fetch=FetchType.EAGER --- .../java/io/ebeaninternal/api/SpiQuery.java | 23 +++++-- .../server/query/CQueryBuilder.java | 2 +- .../org/tests/model/history/HsdSetting.java | 62 +++++++++++++++++++ .../java/org/tests/model/history/HsdUser.java | 54 ++++++++++++++++ .../TestHistorySoftDeleteOneToOne.java | 27 ++++++++ 5 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/tests/model/history/HsdSetting.java create mode 100644 src/test/java/org/tests/model/history/HsdUser.java create mode 100644 src/test/java/org/tests/model/history/TestHistorySoftDeleteOneToOne.java diff --git a/src/main/java/io/ebeaninternal/api/SpiQuery.java b/src/main/java/io/ebeaninternal/api/SpiQuery.java index ae8b83805..24d625f47 100644 --- a/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -134,27 +134,40 @@ public interface SpiQuery extends Query, TxnProfileEventCodes { /** * Includes soft deletes rows in the result. */ - SOFT_DELETED, + SOFT_DELETED(false), /** * Query runs against draft tables. */ - DRAFT, + DRAFT(false), /** * Query runs against current data (normal). */ - CURRENT, + CURRENT(false), /** * Query runs potentially returning many versions of the same bean. */ - VERSIONS, + VERSIONS(true), /** * Query runs 'As Of' a given date time. */ - AS_OF; + AS_OF(true); + + private final boolean history; + + TemporalMode(boolean history) { + this.history = history; + } + + /** + * Return true if this is a history query. + */ + public boolean isHistory() { + return history; + } /** * Return the mode of the query of if null return CURRENT mode. diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 8fb718024..43f4275f0 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -217,7 +217,7 @@ class CQueryBuilder { * Return the history support if this query needs it (is a 'as of' type query). */ CQueryHistorySupport getHistorySupport(SpiQuery query) { - return query.getTemporalMode() != SpiQuery.TemporalMode.CURRENT ? historySupport : null; + return query.getTemporalMode().isHistory() ? historySupport : null; } /** diff --git a/src/test/java/org/tests/model/history/HsdSetting.java b/src/test/java/org/tests/model/history/HsdSetting.java new file mode 100644 index 000000000..26cfc30d9 --- /dev/null +++ b/src/test/java/org/tests/model/history/HsdSetting.java @@ -0,0 +1,62 @@ +package org.tests.model.history; + +import io.ebean.annotation.History; +import io.ebean.annotation.SoftDelete; +import org.tests.model.draftable.BaseDomain; + +import javax.persistence.Entity; +import javax.persistence.OneToOne; + +@History +@Entity +public class HsdSetting extends BaseDomain { + + String key; + String val; + + @SoftDelete + boolean deleted; + + @OneToOne + private HsdUser user; + + + public HsdSetting(String key) { + this.key = key; + } + + public HsdSetting() { + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getVal() { + return val; + } + + public void setVal(String val) { + this.val = val; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public HsdUser getUser() { + return user; + } + + public void setUser(HsdUser user) { + this.user = user; + } +} diff --git a/src/test/java/org/tests/model/history/HsdUser.java b/src/test/java/org/tests/model/history/HsdUser.java new file mode 100644 index 000000000..377bcf4ee --- /dev/null +++ b/src/test/java/org/tests/model/history/HsdUser.java @@ -0,0 +1,54 @@ +package org.tests.model.history; + +import io.ebean.annotation.History; +import io.ebean.annotation.SoftDelete; +import org.tests.model.draftable.BaseDomain; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.OneToOne; + +@History +@Entity +public class HsdUser extends BaseDomain { + + String name; + + @SoftDelete + boolean deleted; + + @OneToOne(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + HsdSetting setting; + + public HsdUser(String name) { + this.name = name; + } + + public HsdUser() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isDeleted() { + return deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + + public HsdSetting getSetting() { + return setting; + } + + public void setSetting(HsdSetting setting) { + this.setting = setting; + } +} diff --git a/src/test/java/org/tests/model/history/TestHistorySoftDeleteOneToOne.java b/src/test/java/org/tests/model/history/TestHistorySoftDeleteOneToOne.java new file mode 100644 index 000000000..36ba5d279 --- /dev/null +++ b/src/test/java/org/tests/model/history/TestHistorySoftDeleteOneToOne.java @@ -0,0 +1,27 @@ +package org.tests.model.history; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TestHistorySoftDeleteOneToOne extends BaseTestCase { + + @Test + public void findOne() { + + HsdUser u1 = new HsdUser("u1"); + + Ebean.save(u1); + Ebean.delete(u1); + + HsdUser one = Ebean.find(HsdUser.class) + .setId(u1.getId()) + .setIncludeSoftDeletes() + .findOne(); + + assertThat(one).isNotNull(); + + } +} From f8b9ca2034137959705165856edf437b4a1b4f1f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 20:26:00 +1300 Subject: [PATCH 0475/1036] #1498 - findIds() with @SoftDelete bean returns all Ids (when soft deleted ones should not return) --- .../server/query/CQueryBuilder.java | 17 +++++++--- .../tests/softdelete/TestSoftDeleteBasic.java | 32 +++++++++++++++++-- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 43f4275f0..e1f4b2249 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -138,11 +138,14 @@ class CQueryBuilder { // wrap as - delete from table where id in (select id ...) String sql = buildSql(null, request, predicates, sqlTree).getSql(); sql = request.getBeanDescriptor().getDeleteByIdInSql() + "in (" + sql + ")"; - String alias = (rootTableAlias == null) ? "t0" : rootTableAlias; - sql = aliasReplace(sql, alias); + sql = aliasReplace(sql, alias(rootTableAlias)); return sql; } + private String alias(String rootTableAlias) { + return (rootTableAlias == null) ? "t0" : rootTableAlias; + } + private String buildUpdateSql(OrmQueryRequest request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) { StringBuilder sb = new StringBuilder(200); @@ -160,8 +163,7 @@ class CQueryBuilder { // wrap as - update table set ... where id in (select id ...) String sql = buildSqlUpdate(null, request, predicates, sqlTree).getSql(); sql = updateClause + " " + request.getBeanDescriptor().getWhereIdInSql() + "in (" + sql + ")"; - String alias = (rootTableAlias == null) ? "t0" : rootTableAlias; - sql = aliasReplace(sql, alias); + sql = aliasReplace(sql, alias(rootTableAlias)); return sql; } @@ -209,7 +211,12 @@ class CQueryBuilder { */ CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest request) { - request.getQuery().setSelectId(); + SpiQuery query = request.getQuery(); + query.setSelectId(); + BeanDescriptor desc = request.getBeanDescriptor(); + if (desc.isSoftDelete()) { + query.addSoftDeletePredicate(desc.getSoftDeletePredicate(alias(query.getAlias()))); + } return buildFetchAttributeQuery(request); } diff --git a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java index d15698cda..511e68fd3 100644 --- a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java +++ b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java @@ -6,11 +6,10 @@ import io.ebean.Query; import io.ebean.SqlQuery; import io.ebean.SqlRow; import io.ebean.Transaction; - -import org.tests.model.softdelete.EBasicSDChild; -import org.tests.model.softdelete.EBasicSoftDelete; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; +import org.tests.model.softdelete.EBasicSDChild; +import org.tests.model.softdelete.EBasicSoftDelete; import java.util.List; @@ -18,6 +17,33 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestSoftDeleteBasic extends BaseTestCase { + @Test + public void testFindIdsWhenIncludeSoftDeletedChlld() { + + EBasicSoftDelete bean = new EBasicSoftDelete(); + bean.setName("softDelChildren"); + bean.addChild("child1", 10); + bean.addChild("child2", 20); + bean.addChild("child3", 30); + + Ebean.save(bean); + Ebean.delete(bean.getChildren().get(0)); + + LoggedSqlCollector.start(); + + List ids = Ebean.find(EBasicSDChild.class).where().eq("owner", bean).findIds(); + assertThat(ids).hasSize(2); + + List beans = Ebean.find(EBasicSDChild.class).where().eq("owner", bean).findList(); + assertThat(beans).hasSize(2); + + List sql = LoggedSqlCollector.stop(); + + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = false"); + assertThat(sql.get(1)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = false"); + } + @Test public void test() { From 31093babe370bf09fe7708a24e158ac83ef797c3 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 20:49:30 +1300 Subject: [PATCH 0476/1036] #1498 - findIds() with @SoftDelete bean returns all Ids (when soft deleted ones should not return) And fix delete permanent that cascades --- .../server/deploy/BeanPropertyAssocMany.java | 6 +++--- .../server/deploy/BeanPropertyAssocManySqlHelp.java | 12 ++++++++---- .../server/persist/DefaultPersister.java | 4 ++-- .../io/ebeaninternal/server/query/CQueryBuilder.java | 2 +- .../server/deploy/BeanPropertyAssocManyTest.java | 4 ++-- ...TestOnCascadeDeleteChildrenWithCompositeKeys.java | 4 ++-- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 0eaf2ae01..2058f0e56 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -318,11 +318,11 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST /** * Find the Id's of detail beans given a parent Id or list of parent Id's. */ - public List findIdsByParentId(Object parentId, List parentIdList, Transaction t, List excludeDetailIds) { + public List findIdsByParentId(Object parentId, List parentIdList, Transaction t, List excludeDetailIds, boolean hard) { if (parentId != null) { - return sqlHelp.findIdsByParentId(parentId, t, excludeDetailIds); + return sqlHelp.findIdsByParentId(parentId, t, excludeDetailIds, hard); } else { - return sqlHelp.findIdsByParentIdList(parentIdList, t, excludeDetailIds); + return sqlHelp.findIdsByParentIdList(parentIdList, t, excludeDetailIds, hard); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java index 3b3426aa3..7f58aa511 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManySqlHelp.java @@ -127,14 +127,16 @@ class BeanPropertyAssocManySqlHelp { many.bindParentIdsIn(expr, parentIds, query); } - List findIdsByParentId(Object parentId, Transaction t, List excludeDetailIds) { + List findIdsByParentId(Object parentId, Transaction t, List excludeDetailIds, boolean hard) { String rawWhere = deriveWhereParentIdSql(false, ""); SpiEbeanServer server = descriptor.getEbeanServer(); SpiQuery q = many.newQuery(server); many.bindParentIdEq(rawWhere, parentId, q); - + if (hard) { + q.setIncludeSoftDeletes(); + } if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); } @@ -142,7 +144,7 @@ class BeanPropertyAssocManySqlHelp { return server.findIds(q, t); } - List findIdsByParentIdList(List parentIds, Transaction t, List excludeDetailIds) { + List findIdsByParentIdList(List parentIds, Transaction t, List excludeDetailIds, boolean hard) { String rawWhere = deriveWhereParentIdSql(true, ""); String inClause = buildInClauseBinding(parentIds.size(), exportedPropertyBindProto); @@ -153,7 +155,9 @@ class BeanPropertyAssocManySqlHelp { SpiQuery q = many.newQuery(server); //Query q = server.find(propertyType); many.bindParentIdsIn(expr, parentIds, q); - + if (hard) { + q.setIncludeSoftDeletes(); + } if (excludeDetailIds != null && !excludeDetailIds.isEmpty()) { q.where().not(q.getExpressionFactory().idIn(excludeDetailIds)); } diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 0e402dcdc..884997f65 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -754,7 +754,7 @@ public final class DefaultPersister implements Persister { executeSqlUpdate(sqlDelete, t); } else { // we need to fetch the Id's to delete (recurse or notify L2 cache) - List childIds = many.findIdsByParentId(id, idList, t, null); + List childIds = many.findIdsByParentId(id, idList, t, null, deleteMode.isHard()); if (!childIds.isEmpty()) { delete(targetDesc, null, childIds, t, deleteMode); } @@ -1052,7 +1052,7 @@ public final class DefaultPersister implements Persister { } else { // Delete recurse using the Id values of the children Object parentId = desc.getId(parentBean); - List idsByParentId = many.findIdsByParentId(parentId, null, t, excludeDetailIds); + List idsByParentId = many.findIdsByParentId(parentId, null, t, excludeDetailIds, deleteMode.isHard()); if (!idsByParentId.isEmpty()) { deleteChildrenById(t, targetDesc, idsByParentId, deleteMode); } diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index e1f4b2249..a58c7b6ec 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -214,7 +214,7 @@ class CQueryBuilder { SpiQuery query = request.getQuery(); query.setSelectId(); BeanDescriptor desc = request.getBeanDescriptor(); - if (desc.isSoftDelete()) { + if (!query.isIncludeSoftDeletes() && desc.isSoftDelete()) { query.addSoftDeletePredicate(desc.getSoftDeletePredicate(alias(query.getAlias()))); } return buildFetchAttributeQuery(request); diff --git a/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java b/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java index 162832e76..ff35bf77e 100644 --- a/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java +++ b/src/test/java/io/ebeaninternal/server/deploy/BeanPropertyAssocManyTest.java @@ -72,9 +72,9 @@ public class BeanPropertyAssocManyTest extends BaseTestCase { customerIds.add(1L); customerIds.add(2L); - List contactIdsForOne = contacts().findIdsByParentId(1L, null, null, null); + List contactIdsForOne = contacts().findIdsByParentId(1L, null, null, null, true); - List contactIdsForMultiple = contacts().findIdsByParentId(null, customerIds, null, null); + List contactIdsForMultiple = contacts().findIdsByParentId(null, customerIds, null, null, true); assertThat(contactIdsForOne).isNotEmpty(); assertThat(contactIdsForMultiple).isNotEmpty(); diff --git a/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java b/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java index 08cde0802..095313e33 100644 --- a/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java +++ b/src/test/java/org/tests/compositekeys/TestOnCascadeDeleteChildrenWithCompositeKeys.java @@ -85,8 +85,8 @@ public class TestOnCascadeDeleteChildrenWithCompositeKeys extends BaseTestCase { ids.add(1L); ids.add(2L); - beanProperty.findIdsByParentId(null, ids, null, null); - beanProperty.findIdsByParentId(1L, null, null, null); + beanProperty.findIdsByParentId(null, ids, null, null, true); + beanProperty.findIdsByParentId(1L, null, null, null, true); } @Entity From 5b09443cdf0544c26f053bd86ffca94101ba7e07 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 22:10:06 +1300 Subject: [PATCH 0477/1036] [maven-release-plugin] prepare release ebean-11.22.7 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c6f265724..4741079d3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.7-SNAPSHOT + 11.22.7 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.7 From 9a6d33944916d5e1727a09d41db54f2e7ef3b93a Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 22:10:24 +1300 Subject: [PATCH 0478/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4741079d3..443584bd5 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.7 + 11.22.8-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.7 + HEAD From fc26765a7e9d138164d8a2bc5e5b7ee35bdcc343 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Thu, 4 Oct 2018 22:51:51 +1300 Subject: [PATCH 0479/1036] #1499 - findNative with findIds (or findSingleAttributeList with id property) throws ArrayIndexOutOfBoundsException --- .../server/query/SqlTreeNodeBean.java | 5 ++- .../server/querydefn/DefaultOrmQuery.java | 1 + .../org/tests/query/TestQueryFindNative.java | 31 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index 9bafd1317..c67d58600 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -148,7 +148,10 @@ class SqlTreeNodeBean implements SqlTreeNode { public ScalarType getSingleAttributeScalarType() { if (properties == null || properties.length == 0) { // if we have no property ask first children (in a distinct select with join) - // if we have also no children, NPE happens anyway. + if (children.length == 0) { + // expected to be a findIds query + return desc.getIdBinder().getBeanProperty().getScalarType(); + } return children[0].getSingleAttributeScalarType(); } if (properties[0] instanceof STreePropertyAssocOne) { diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index b2f294b02..fb3be3605 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -769,6 +769,7 @@ public class DefaultOrmQuery implements SpiQuery { copy.mapKey = mapKey; copy.id = id; copy.label = label; + copy.nativeSql = nativeSql; copy.useBeanCache = useBeanCache; copy.useQueryCache = useQueryCache; copy.readOnly = readOnly; diff --git a/src/test/java/org/tests/query/TestQueryFindNative.java b/src/test/java/org/tests/query/TestQueryFindNative.java index 734eb1c76..12dc45a6f 100644 --- a/src/test/java/org/tests/query/TestQueryFindNative.java +++ b/src/test/java/org/tests/query/TestQueryFindNative.java @@ -1,6 +1,7 @@ package org.tests.query; import io.ebean.BaseTestCase; +import io.ebean.Ebean; import org.junit.Test; import org.tests.model.basic.Contact; import org.tests.model.basic.Customer; @@ -13,6 +14,36 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestQueryFindNative extends BaseTestCase { + @Test + public void findIds() { + + ResetBasicData.reset(); + + String sql = "select c.id from contact c where c.first_name like ? "; + + List ids = Ebean.createSqlQuery(sql) + .setParameter(1, "J%") + .findSingleAttributeList(Integer.class); + + List idsScalar = + server() + .findNative(Contact.class, sql) + .setParameter(1, "J%") + .findSingleAttributeList(); + + List nativeIds = + server() + .findNative(Contact.class, sql) + .setParameter(1, "J%") + .findIds(); + + + assertThat(nativeIds).isNotEmpty(); + assertThat(nativeIds).containsAll(ids); + assertThat(idsScalar).containsAll(ids); + } + + @Test public void joinFromManyToOne() { From b5eec9399540593fec4d57020eb27a3fd57f6d75 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 5 Oct 2018 10:41:40 +1300 Subject: [PATCH 0480/1036] #1500 - Improve Postgres 10 partitioning support, easier to create multiple indexes on each partition --- .../dbmigration/builtin-extra-ddl-partitioning.xml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml index 237e563cb..678ab367b 100644 --- a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml +++ b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl-partitioning.xml @@ -36,6 +36,9 @@ create or replace function _partition_create(meta partition_meta, extra text) language plpgsql set timezone to 'UTC' as $$ +declare + idx_col text; + idx_name text; begin execute format('create table if not exists %I partition of %I for values from (''%s'') TO (''%s'')', meta.part_name, meta.base_name, meta.period_start, meta.period_end); @@ -45,7 +48,12 @@ begin end if; if (length(meta.index_column) > 0) then - execute format('create index if not exists ix_%I_%s ON %I (%I)', meta.part_name, meta.index_column, meta.part_name, meta.index_column); + -- delimited for multiple indexes + foreach idx_col in array regexp_split_to_array(meta.index_column,';') + loop + idx_name = replace(idx_col, ',', '_'); + execute format('create index if not exists ix_%I_%s ON %I (%s)', meta.part_name, idx_name, meta.part_name, idx_col); + end loop; end if; if (length(extra) > 0) then From da95ec0c05d65368f5d8d74619b45999af5879d4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 5 Oct 2018 11:26:42 +1300 Subject: [PATCH 0481/1036] #1501 - Change logging for io.ebeaninternal.dbmigration.DefaultDbMigration to "io.ebean.GenerateMigration" --- .../java/io/ebeaninternal/dbmigration/DefaultDbMigration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index b73812955..122899571 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -65,7 +65,7 @@ import java.util.List; */ public class DefaultDbMigration implements DbMigration { - protected static final Logger logger = LoggerFactory.getLogger(DefaultDbMigration.class); + protected static final Logger logger = LoggerFactory.getLogger("io.ebean.GenerateMigration"); private static final String initialVersion = "1.0"; From 54b56846280136c3b4f703596acf2087e60bd158 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 5 Oct 2018 12:22:25 +1300 Subject: [PATCH 0482/1036] #1502 - findNative build query to findPagedList, the query count is incorrect. --- .../server/querydefn/DefaultOrmQuery.java | 2 +- .../org/tests/query/TestQueryFindNative.java | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index fb3be3605..e64ab5c79 100644 --- a/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -1051,7 +1051,7 @@ public class DefaultOrmQuery implements SpiQuery { CQueryPlanKey createQueryPlanKey() { if (isNativeSql()) { - queryPlanKey = new NativeSqlQueryPlanKey(nativeSql + "-" + firstRow + "-" + maxRows); + queryPlanKey = new NativeSqlQueryPlanKey(type.ordinal() + nativeSql + "-" + firstRow + "-" + maxRows); } else { queryPlanKey = new OrmQueryPlanKey(planDescription(), maxRows, firstRow, rawSql); } diff --git a/src/test/java/org/tests/query/TestQueryFindNative.java b/src/test/java/org/tests/query/TestQueryFindNative.java index 12dc45a6f..4ad221231 100644 --- a/src/test/java/org/tests/query/TestQueryFindNative.java +++ b/src/test/java/org/tests/query/TestQueryFindNative.java @@ -2,6 +2,8 @@ package org.tests.query; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.PagedList; +import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.Contact; import org.tests.model.basic.Customer; @@ -14,6 +16,84 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestQueryFindNative extends BaseTestCase { + @Test + public void findCount() { + + ResetBasicData.reset(); + String sql = "select n.id from contact n where n.first_name like ?"; + + LoggedSqlCollector.start(); + + int rowCount = server() + .findNative(Contact.class, sql) + .setParameter(1, "J%") + .findCount(); + + List nativeIds = + server() + .findNative(Contact.class, sql) + .setParameter(1, "J%") + .findIds(); + + List loggedSql = LoggedSqlCollector.stop(); + + assertThat(nativeIds).hasSize(rowCount); + + assertThat(loggedSql).hasSize(2); + assertThat(loggedSql.get(0)).contains("select count(*) from ( select n.id from contact n where n.first_name like ?)"); + assertThat(loggedSql.get(1)).startsWith("select n.id from contact n where n.first_name like ?"); + } + + @Test + public void findPagedList() { + + ResetBasicData.reset(); + String sql = "select n.id, n.first_name from contact n where n.first_name like ?"; + + PagedList pagedList = server() + .findNative(Contact.class, sql) + .setParameter(1, "J%") + .setMaxRows(100) + .findPagedList(); + + LoggedSqlCollector.start(); + + int listSize = pagedList.getList().size(); + int totalCount = pagedList.getTotalCount(); + + List loggedSql = LoggedSqlCollector.stop(); + + assertThat(listSize).isEqualTo(totalCount); + + assertThat(loggedSql).hasSize(2); + assertThat(loggedSql.get(0)).startsWith("select n.id, n.first_name from contact n where n.first_name like ?"); + assertThat(loggedSql.get(1)).contains("select count(*) from ( select n.id, n.first_name from contact n where n.first_name like ?)"); + } + + + @Test + public void findPagedList_withColumnAlias() { + + ResetBasicData.reset(); + String sql = "select n.id, 'SillyName' first_name from contact n where n.id < ? "; + + PagedList pagedList = server() + .findNative(Contact.class, sql) + .setParameter(1, 100) + .setMaxRows(100) + .findPagedList(); + + int listSize = pagedList.getList().size(); + int totalCount = pagedList.getTotalCount(); + + assertThat(listSize).isEqualTo(totalCount); + + for (Contact contact : pagedList.getList()) { + assertThat(contact.getFirstName()).isEqualTo("SillyName"); + } + } + + @Test public void findIds() { From 0371043914fde1d09af482ebfd6e8961a303c607 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 5 Oct 2018 13:04:15 +1300 Subject: [PATCH 0483/1036] [maven-release-plugin] prepare release ebean-11.22.8 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 443584bd5..adf45a5a4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.8-SNAPSHOT + 11.22.8 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.8 From 82e68d7756dcbc5b6db24939849f882130818c87 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 5 Oct 2018 13:04:31 +1300 Subject: [PATCH 0484/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index adf45a5a4..b0267aa03 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.8 + 11.22.9-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.8 + HEAD From b87e360ac77cc1d11c3fbb6476508b39584bffa4 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Oct 2018 18:49:20 +1300 Subject: [PATCH 0485/1036] #1504 - ENH: Add SqlUpdate executeNow() method ... that executes now regardless of transaction batch mode --- src/main/java/io/ebean/SqlUpdate.java | 10 ++++++ .../io/ebeaninternal/api/SpiEbeanServer.java | 4 +++ .../server/core/DefaultServer.java | 5 +++ .../server/core/DefaultSqlUpdate.java | 9 +++++ .../server/core/PersistRequestUpdateSql.java | 15 +++++--- .../ebeaninternal/server/core/Persister.java | 7 +++- .../server/persist/DefaultPersister.java | 5 +++ .../ebeaninternal/api/TDSpiEbeanServer.java | 5 +++ .../org/tests/update/TestSqlUpdateInTxn.java | 36 +++++++++++++++++++ 9 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/ebean/SqlUpdate.java b/src/main/java/io/ebean/SqlUpdate.java index 9884c095c..27e7be39e 100644 --- a/src/main/java/io/ebean/SqlUpdate.java +++ b/src/main/java/io/ebean/SqlUpdate.java @@ -98,6 +98,11 @@ public interface SqlUpdate { /** * Execute the update returning the number of rows modified. *

    + * Note that if the transaction has batch mode on then this update will use JDBC batch and may not execute until + * later - at commit time or a transaction flush. In this case this method returns -1 indicating that the + * update has been batched for later execution. + *

    + *

    * After you have executed the SqlUpdate you can bind new variables using * {@link #setParameter(String, Object)} etc and then execute the SqlUpdate * again. @@ -112,6 +117,11 @@ public interface SqlUpdate { */ int execute(); + /** + * Execute the statement now regardless of the JDBC batch mode of the transaction. + */ + int executeNow(); + /** * Execute when addBatch() has been used to batch multiple bind executions. * diff --git a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java index 1971b4b24..f1936cf94 100644 --- a/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java +++ b/src/main/java/io/ebeaninternal/api/SpiEbeanServer.java @@ -312,4 +312,8 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanLoader, */ int[] executeBatch(SpiSqlUpdate defaultSqlUpdate, SpiTransaction transaction); + /** + * Execute the sql update regardless of transaction batch mode. + */ + int executeNow(SpiSqlUpdate sqlUpdate); } diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java index 2a7c4e1cc..be4693ff7 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java @@ -2054,6 +2054,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer { return persister.executeSqlUpdate(updSql, t); } + @Override + public int executeNow(SpiSqlUpdate sqlUpdate) { + return persister.executeSqlUpdateNow(sqlUpdate, null); + } + @Override public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) { persister.addBatch(sqlUpdate, transaction); diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java index d9d4e6500..4ea9a06b0 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultSqlUpdate.java @@ -133,6 +133,15 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate { } } + @Override + public int executeNow() { + if (server != null) { + return server.executeNow(this); + } else { + throw new IllegalStateException("server is null?"); + } + } + @Override public int[] executeBatch() { if (server == null) { diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java index 6aa17970c..289592cbe 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestUpdateSql.java @@ -28,18 +28,23 @@ public final class PersistRequestUpdateSql extends PersistRequest { private boolean addBatch; - /** - * Create. - */ + private boolean forceNoBatch; + public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate, - SpiTransaction t, PersistExecute persistExecute) { + SpiTransaction t, PersistExecute persistExecute, boolean forceNoBatch) { super(server, t, persistExecute, sqlUpdate.getLabel()); this.type = Type.UPDATESQL; this.updateSql = sqlUpdate; + this.forceNoBatch = forceNoBatch; updateSql.reset(); } + public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate, + SpiTransaction t, PersistExecute persistExecute) { + this(server, sqlUpdate, t, persistExecute, false); + } + @Override public void profile(long offset, int flushCount) { profileBase(EVT_UPDATESQL, offset, (short)0, flushCount); @@ -60,7 +65,7 @@ public final class PersistRequestUpdateSql extends PersistRequest { @Override public boolean isBatchThisRequest() { - return addBatch || super.isBatchThisRequest(); + return !forceNoBatch && (addBatch || super.isBatchThisRequest()); } @Override diff --git a/src/main/java/io/ebeaninternal/server/core/Persister.java b/src/main/java/io/ebeaninternal/server/core/Persister.java index c64daaa4e..a1b9eedbe 100644 --- a/src/main/java/io/ebeaninternal/server/core/Persister.java +++ b/src/main/java/io/ebeaninternal/server/core/Persister.java @@ -74,10 +74,15 @@ public interface Persister { int executeOrmUpdate(Update update, Transaction t); /** - * Execute the UpdateSql. + * Execute the SqlUpdate (taking into account transaction batch mode). */ int executeSqlUpdate(SqlUpdate update, Transaction t); + /** + * Execute the SqlUpdate now regardless of transaction batch mode. + */ + int executeSqlUpdateNow(SpiSqlUpdate update, Transaction t); + /** * Execute the CallableSql. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 884997f65..14f3b937b 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -150,6 +150,11 @@ public final class DefaultPersister implements Persister { return executeOrQueue(new PersistRequestUpdateSql(server, (SpiSqlUpdate) updSql, (SpiTransaction) t, persistExecute)); } + @Override + public int executeSqlUpdateNow(SpiSqlUpdate updSql, Transaction t) { + return executeOrQueue(new PersistRequestUpdateSql(server, updSql, (SpiTransaction) t, persistExecute, true)); + } + /** * Restore draft beans to match live beans given the query. */ diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java index d52327463..2100f8d7c 100644 --- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java +++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java @@ -854,6 +854,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer { return 0; } + @Override + public int executeNow(SpiSqlUpdate sqlUpdate) { + return 0; + } + @Override public void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction) { diff --git a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java index e306e477d..673f72b01 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateInTxn.java +++ b/src/test/java/org/tests/update/TestSqlUpdateInTxn.java @@ -3,6 +3,7 @@ package org.tests.update; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.SqlUpdate; +import io.ebean.Transaction; import io.ebean.meta.MetaTimedMetric; import org.junit.Assert; import org.junit.Test; @@ -38,6 +39,41 @@ public class TestSqlUpdateInTxn extends BaseTestCase { } } + @Test + public void testExecute_inTransaction_withBatch() { + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.setBatchMode(true); + + int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?") + .setParameter(1, 999999) + .execute(); + + // update statement using JDBC batch so not executed yet + assertThat(row).isEqualTo(-1); + + transaction.commit(); + } + + } + + @Test + public void testExecuteNow_inTransaction_withBatch() { + + try (Transaction transaction = Ebean.beginTransaction()) { + transaction.setBatchMode(true); + + int row = Ebean.createSqlUpdate("update audit_log set description = description where id = ?") + .setParameter(1, 999999) + .executeNow(); + + // update statement executed even though JDBC batch mode is on + assertThat(row).isEqualTo(0); + + transaction.commit(); + } + } + @Test public void testSqlUpdateWithWhitespace() { From 15cab24848c65707f9dc9bf817799f24bcbb09ec Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Oct 2018 20:33:59 +1300 Subject: [PATCH 0486/1036] #1504 - ENH: Add SqlUpdate executeNow() method ... that executes now regardless of transaction batch mode Add test for UpdateQuery (which executes immediately regardless) --- src/test/java/io/ebean/UpdateQueryTest.java | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index 00498227d..583341517 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -42,6 +42,32 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(ormQueryMetrics.get(0).getLabel()).isEqualTo("updateActive"); } + @Test + public void update_withTransactionBatch() { + + EbeanServer server = server(); + + try (Transaction transaction = server.beginTransaction()) { + transaction.setBatchMode(true); + + UpdateQuery update = server.update(Customer.class); + + Query query = update + .set("status", Customer.Status.ACTIVE) + .set("updtime", new Timestamp(System.currentTimeMillis())) + .where() + .eq("status", Customer.Status.NEW) + .gt("id", 99999) + .query(); + + // update executes now regardless of transaction batch mode + int rows = query.update(); + assertThat(rows).isEqualTo(0); + + transaction.commit(); + } + } + @Test @IgnorePlatform(Platform.SQLSERVER) public void withTableAlias() { From de9823b69bc7d053fb724a619b1e40b1315d5882 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 12 Oct 2018 22:30:06 +1300 Subject: [PATCH 0487/1036] #1505 - Unidirectional @OneToOne orphanRemoval=true ... does not delete orphan that is replaced --- .../server/core/PersistRequestBean.java | 21 ++++++++++++ .../deploy/parse/AnnotationAssocOnes.java | 2 ++ .../server/persist/DefaultPersister.java | 21 +++++++++--- .../onetoone/TestOneToOneOrphanStringId.java | 32 +++++++++++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 9a8d0f23b..44e5a32ad 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -19,6 +19,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanManager; import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; +import io.ebeaninternal.server.deploy.BeanPropertyAssocOne; import io.ebeaninternal.server.deploy.generatedproperty.GeneratedProperty; import io.ebeaninternal.server.deploy.id.ImportedId; import io.ebeaninternal.server.persist.BatchControl; @@ -131,6 +132,11 @@ public final class PersistRequestBean extends PersistRequest implements BeanP */ private boolean[] dirtyProperties; + /** + * Imported OneToOne orphan that needs to be deleted. + */ + private EntityBean orphanBean; + /** * Flag set when request is added to JDBC batch. */ @@ -1377,4 +1383,19 @@ public final class PersistRequestBean extends PersistRequest implements BeanP changeSet.addBeanUpdate(beanDescriptor, idValue, changes, updateNaturalKey, getVersion()); } } + + /** + * Set an orphan bean that needs to be deleted AFTER the request has persisted. + */ + public void setImportedOrphanForRemoval(BeanPropertyAssocOne prop) { + Object orphan = getOrigValue(prop); + if (orphan instanceof EntityBean) { + orphanBean = (EntityBean)orphan; + } + } + + public EntityBean getImportedOrphanForRemoval() { + return orphanBean; + } + } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index bb0bac37d..add0870e8 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -229,6 +229,8 @@ public class AnnotationAssocOnes extends AnnotationParser { if (!"".equals(propAnn.mappedBy())) { prop.setOneToOneExported(); prop.setOrphanRemoval(propAnn.orphanRemoval()); + } else if (propAnn.orphanRemoval()) { + prop.setOrphanRemoval(true); } setCascadeTypes(propAnn.cascade(), prop.getCascadeInfo()); diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index 14f3b937b..fea311ad1 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -901,6 +901,11 @@ public final class DefaultPersister implements Persister { BeanDescriptor desc = request.getBeanDescriptor(); SpiTransaction t = request.getTransaction(); + EntityBean orphanForRemoval = request.getImportedOrphanForRemoval(); + if (orphanForRemoval != null) { + delete(orphanForRemoval, request.getTransaction(), true); + } + // exported ones with cascade save for (BeanPropertyAssocOne prop : desc.propertiesOneExportedSave()) { // check for partial beans @@ -1097,6 +1102,10 @@ public final class DefaultPersister implements Persister { // imported ones with save cascade for (BeanPropertyAssocOne prop : desc.propertiesOneImportedSave()) { // check for partial objects + if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) { + request.setImportedOrphanForRemoval(prop); + } + if (request.isLoadedProperty(prop)) { EntityBean detailBean = prop.getValueAsEntityBean(request.getEntityBean()); if (detailBean != null @@ -1113,14 +1122,18 @@ public final class DefaultPersister implements Persister { for (BeanPropertyAssocOne prop : desc.propertiesOneExportedSave()) { if (prop.isOrphanRemoval() && request.isDirtyProperty(prop)) { - Object origValue = request.getOrigValue(prop); - if (origValue instanceof EntityBean) { - delete((EntityBean) origValue, request.getTransaction(), true); - } + deleteOrphan(request, prop); } } } + private void deleteOrphan(PersistRequestBean request, BeanPropertyAssocOne prop) { + Object origValue = request.getOrigValue(prop); + if (origValue instanceof EntityBean) { + delete((EntityBean) origValue, request.getTransaction(), true); + } + } + /** * Support for loading any Imported Associated One properties that are not * loaded but required for Delete cascade. diff --git a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java index 1a16f50d6..5f7a6f3f4 100644 --- a/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java +++ b/src/test/java/org/tests/model/onetoone/TestOneToOneOrphanStringId.java @@ -61,6 +61,38 @@ public class TestOneToOneOrphanStringId extends BaseTestCase { assertThat(deletes.get(0)).contains("delete from oto_atwo"); assertThat(deletes.get(1)).contains("delete from oto_aone"); } + + @Test + public void test_remove() { + + OtoAtwo b = new OtoAtwo("b3", "b test"); + Ebean.save(b); + + OtoAone a = new OtoAone("a3", "a test"); + b.setAone(a); + + Ebean.save(b); + + LoggedSqlCollector.start(); + + OtoAone a2 = new OtoAone("a4", "a test"); + b.setAone(a2); + Ebean.save(b); + + List sql = LoggedSqlCollector.current(); + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into oto_aone"); + assertThat(sql.get(1)).contains("update oto_atwo set aone_id=? where id=?"); + assertThat(sql.get(2)).contains("delete from oto_aone where id=?"); + + Ebean.delete(b); + + List deletes = LoggedSqlCollector.stop(); + assertThat(deletes).hasSize(2); + assertThat(deletes.get(0)).contains("delete from oto_atwo"); + assertThat(deletes.get(1)).contains("delete from oto_aone"); + + } } From 283943477350a42d76ed11c9613bcdd2fe809d59 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Sat, 13 Oct 2018 00:23:44 +1300 Subject: [PATCH 0488/1036] #1506 - @ElementCollection DDL generates 2 indexes on the same column --- .../dbmigration/model/build/ModelBuildElementTable.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java index 94a2526a8..0cbf2f2a4 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java +++ b/src/main/java/io/ebeaninternal/dbmigration/model/build/ModelBuildElementTable.java @@ -24,9 +24,6 @@ public class ModelBuildElementTable { VisitAllUsing.visitOne(targetDescriptor, new ModelBuildPropertyVisitor(ctx, table, targetDescriptor)); - ctx.fkeyBuilder(table) - .addForeignKey(manyProp.getBeanDescriptor(), manyProp.getTableJoin(), true); - ctx.addTable(table); } From aa7325b24960aa9810399737050af366bfcb2abb Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:12:39 +1300 Subject: [PATCH 0489/1036] #1507 - SqlUpdate.execute PersistenceException is not translated into more specific exception (like DuplicateKeyException) --- .../server/core/PersistRequest.java | 10 +++ .../server/persist/ExeUpdateSql.java | 4 +- .../tests/update/TestSqlUpdateExceptions.java | 72 +++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/tests/update/TestSqlUpdateExceptions.java diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequest.java b/src/main/java/io/ebeaninternal/server/core/PersistRequest.java index 102bfa07d..42b8efae0 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequest.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequest.java @@ -8,6 +8,9 @@ import io.ebeaninternal.server.persist.BatchPostExecute; import io.ebeaninternal.server.persist.BatchedSqlException; import io.ebeaninternal.server.persist.PersistExecute; +import javax.persistence.PersistenceException; +import java.sql.SQLException; + /** * Wraps all the objects used to persist a bean. */ @@ -95,6 +98,13 @@ public abstract class PersistRequest extends BeanRequest implements BatchPostExe return transaction.isBatchThisRequest(); } + /** + * Translate the SQLException into a specific exception given the platform. + */ + public PersistenceException translateSqlException(SQLException e) { + return transaction.translate(e.getMessage(), e); + } + /** * Execute the statement. */ diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java index 88879458d..01bacb57b 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeUpdateSql.java @@ -55,8 +55,8 @@ class ExeUpdateSql { request.postExecute(); return rowCount; } - } catch (SQLException ex) { - throw new PersistenceException(ex); + } catch (SQLException e) { + throw request.translateSqlException(e); } finally { if (!batchThisRequest) { diff --git a/src/test/java/org/tests/update/TestSqlUpdateExceptions.java b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java new file mode 100644 index 000000000..20007ce7e --- /dev/null +++ b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java @@ -0,0 +1,72 @@ +package org.tests.update; + +import io.ebean.BaseTestCase; +import io.ebean.DuplicateKeyException; +import io.ebean.Ebean; +import io.ebean.SqlUpdate; +import io.ebean.Transaction; +import org.junit.Test; + +import java.util.UUID; + +public class TestSqlUpdateExceptions extends BaseTestCase { + + private String sql = "insert into uuone (id, name, version) values (?,?,?)"; + + @Test(expected = DuplicateKeyException.class) + public void duplicateKey() { + + UUID id = UUID.randomUUID(); + + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql); + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "hi"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.execute(); + + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "fail"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.execute(); + } + + @Test(expected = DuplicateKeyException.class) + public void duplicateKey_executeNow() { + + + UUID id = UUID.randomUUID(); + + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql); + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "hi"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.executeNow(); + + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "fail"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.executeNow(); + } + + @Test(expected = DuplicateKeyException.class) + public void duplicateKey_inBatch() { + + UUID id = UUID.randomUUID(); + + try (Transaction transaction = Ebean.beginTransaction()) { + + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql); + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "hi in batch"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.addBatch(); + + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "fail in batch"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.addBatch(); + + transaction.commit(); + } + } +} From 9d643527713fd9e511fde7fe78ff2b5cd4fd805b Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:13:18 +1300 Subject: [PATCH 0490/1036] No effective change - add additional tests --- .../java/org/tests/cache/TestBeanCache.java | 12 ++++++ .../tests/softdelete/TestSoftDeleteBasic.java | 39 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/test/java/org/tests/cache/TestBeanCache.java b/src/test/java/org/tests/cache/TestBeanCache.java index 11a726475..2419d3b3c 100644 --- a/src/test/java/org/tests/cache/TestBeanCache.java +++ b/src/test/java/org/tests/cache/TestBeanCache.java @@ -2,6 +2,7 @@ package org.tests.cache; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import org.tests.model.basic.Country; import org.tests.model.basic.OCachedBean; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -41,4 +42,15 @@ public class TestBeanCache extends BaseTestCase { assertThat(sql).isEmpty(); } + + @Test + public void find_whenNotExits() { + + Country country = Ebean.find(Country.class) + .where() + .eq("name","NotValid") + .findOne(); + + assertThat(country).isNull(); + } } diff --git a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java index 511e68fd3..6240c49cd 100644 --- a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java +++ b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java @@ -14,9 +14,48 @@ import org.tests.model.softdelete.EBasicSoftDelete; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; public class TestSoftDeleteBasic extends BaseTestCase { + @Test + public void testCascadeSaveDelete_other() { + + EBasicSoftDelete bean = new EBasicSoftDelete(); + bean.setName("cascadeOne"); + bean.addChild("child1", 10); + bean.addChild("child2", 20); + bean.addChild("child3", 30); + bean.addNoSoftDeleteChild("nsd1", 101); + bean.addNoSoftDeleteChild("nsd2", 102); + + Ebean.save(bean); + + assertEquals(new Long(1), bean.getVersion()); + assertEquals(new Long(1), bean.getChildren().get(0).getVersion()); + + LoggedSqlCollector.start(); + + Ebean.delete(bean); + +// List loggedSql = LoggedSqlCollector.stop(); +// +// assertEquals(new Long(2), bean.getVersion()); +// assertEquals(new Long(2), bean.getChildren().get(0).getVersion()); // Fails with 1 +// +// // The children without SoftDelete are left as is (so no third statement) +// assertThat(loggedSql).hasSize(2); +// +// // first statement is a single bulk update of the children with SoftDelete +// assertThat(loggedSql.get(0)).contains("update ebasic_sdchild set deleted="); +// assertThat(loggedSql.get(0)).contains("where owner_id = ?"); +// +// // second statement is the top level bean +// assertThat(loggedSql.get(1)).contains( +// "update ebasic_soft_delete set version=?, deleted=? where id=? and version=?"); + + } + @Test public void testFindIdsWhenIncludeSoftDeletedChlld() { From 3eaf47fd7058334de2a075b8433901ffda39bc04 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:25:38 +1300 Subject: [PATCH 0491/1036] No effective change - add additional tests --- .../server/persist/ExeCallableSql.java | 2 +- src/test/java/io/ebean/UpdateQueryTest.java | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java index 3bc2dc3d2..b48d2d2cf 100644 --- a/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java +++ b/src/main/java/io/ebeaninternal/server/persist/ExeCallableSql.java @@ -48,7 +48,7 @@ class ExeCallableSql { } } catch (SQLException ex) { - throw new PersistenceException(ex); + throw request.translateSqlException(ex); } finally { if (!batchThisRequest) { diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java index 583341517..31285feb5 100644 --- a/src/test/java/io/ebean/UpdateQueryTest.java +++ b/src/test/java/io/ebean/UpdateQueryTest.java @@ -7,6 +7,7 @@ import io.ebean.meta.MetaOrmQueryMetric; import org.junit.Test; import org.tests.model.basic.Country; import org.tests.model.basic.Customer; +import org.tests.model.basic.EBasicWithUniqueCon; import java.sql.Timestamp; import java.util.List; @@ -225,4 +226,27 @@ public class UpdateQueryTest extends BaseTestCase { assertThat(rows).isEqualTo(0); } + + @Test(expected = DuplicateKeyException.class) + public void exceptionTranslation() { + + newEbasicWithUnique("o1","other1_a"); + Integer id = newEbasicWithUnique("o2", "other1_b"); + + Ebean.update(EBasicWithUniqueCon.class) + .set("other", "other1_a") + .set("otherOne", "other1_a") + .where().idEq(id) + .update(); + } + + private Integer newEbasicWithUnique(String name, String other) { + EBasicWithUniqueCon b0 = new EBasicWithUniqueCon(); + b0.setName(name); + b0.setOther(other); + b0.setOtherOne(other); + Ebean.save(b0); + + return b0.getId(); + } } From 2646e8c27fa24ca4a293c3dcd19306e4e4db789f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:30:42 +1300 Subject: [PATCH 0492/1036] #1507 - SqlUpdate.execute PersistenceException is not translated into more specific exception (like DuplicateKeyException) Support for sqlUpdate.executeBatch() --- .../server/persist/DefaultPersister.java | 2 +- .../tests/update/TestSqlUpdateExceptions.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java index fea311ad1..2a1651660 100644 --- a/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java +++ b/src/main/java/io/ebeaninternal/server/persist/DefaultPersister.java @@ -137,7 +137,7 @@ public final class DefaultPersister implements Persister { try { return batchControl.execute(sqlUpdate.getSql(), sqlUpdate.isGetGeneratedKeys()); } catch (SQLException e) { - throw new PersistenceException(e); + throw transaction.translate(e.getMessage(), e); } } diff --git a/src/test/java/org/tests/update/TestSqlUpdateExceptions.java b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java index 20007ce7e..7296811f2 100644 --- a/src/test/java/org/tests/update/TestSqlUpdateExceptions.java +++ b/src/test/java/org/tests/update/TestSqlUpdateExceptions.java @@ -69,4 +69,27 @@ public class TestSqlUpdateExceptions extends BaseTestCase { transaction.commit(); } } + + @Test(expected = DuplicateKeyException.class) + public void duplicateKey_executeBatch() { + + UUID id = UUID.randomUUID(); + + try (Transaction transaction = Ebean.beginTransaction()) { + + SqlUpdate sqlUpdate = Ebean.createSqlUpdate(sql); + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "hi in batch"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.addBatch(); + + sqlUpdate.setParameter(1, id); + sqlUpdate.setParameter(2, "fail in batch"); + sqlUpdate.setParameter(3, 1); + sqlUpdate.addBatch(); + int[] ints = sqlUpdate.executeBatch(); + + transaction.commit(); + } + } } From 249cc5df4968d51793ca0029bc4c608a6d0b9450 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:35:12 +1300 Subject: [PATCH 0493/1036] [maven-release-plugin] prepare release ebean-11.22.9 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b0267aa03..b44674332 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.9-SNAPSHOT + 11.22.9 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.9 From 6fd76ff697a4f9a8d5b6e88d4368b50f15230702 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Mon, 15 Oct 2018 22:35:28 +1300 Subject: [PATCH 0494/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b44674332..ba5c0f8d8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.9 + 11.22.10-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.9 + HEAD From 8160d1f01cb5660deaa464a03c21430ce1a31e9d Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 19 Oct 2018 15:56:39 +1300 Subject: [PATCH 0495/1036] #1508 - Invalid SQL used to fetch identity value for @Draftable with database platform that uses Identity but not getGeneratedKeys --- .../ebean/config/dbplatform/DbIdentity.java | 8 +- .../server/core/PersistRequestBean.java | 6 + .../server/deploy/BeanDescriptor.java | 13 ++- .../server/deploy/BeanDescriptorManager.java | 5 +- .../deploy/meta/DeployBeanDescriptor.java | 8 +- .../server/persist/dml/InsertHandler.java | 13 +-- .../server/persist/dml/InsertMeta.java | 20 ++-- .../config/PlatformNoGeneratedKeysTest.java | 103 ++++++++++++++++++ .../model/draftable/BasicDraftableBean.java | 32 ++++++ src/test/resources/extra-ddl.xml | 2 +- 10 files changed, 182 insertions(+), 28 deletions(-) create mode 100644 src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java create mode 100644 src/test/java/org/tests/model/draftable/BasicDraftableBean.java diff --git a/src/main/java/io/ebean/config/dbplatform/DbIdentity.java b/src/main/java/io/ebean/config/dbplatform/DbIdentity.java index af1f4574c..c57626b3f 100644 --- a/src/main/java/io/ebean/config/dbplatform/DbIdentity.java +++ b/src/main/java/io/ebean/config/dbplatform/DbIdentity.java @@ -8,7 +8,9 @@ import java.util.regex.Pattern; */ public class DbIdentity { - private static final Pattern TABLE_REPLACE = Pattern.compile("{table}", Pattern.LITERAL); + private static final String TABLE_PLACEHOLDER = "{table}"; + + private static final Pattern TABLE_REPLACE = Pattern.compile(TABLE_PLACEHOLDER, Pattern.LITERAL); /** * Set if this DB supports sequences. Note some DB's support both Sequences @@ -53,7 +55,9 @@ public class DbIdentity { if (selectLastInsertedIdTemplate == null) { return null; } - + if (!selectLastInsertedIdTemplate.contains(TABLE_PLACEHOLDER)) { + return selectLastInsertedIdTemplate; + } return TABLE_REPLACE.matcher(selectLastInsertedIdTemplate).replaceAll(Matcher.quoteReplacement(table)); } diff --git a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index 44e5a32ad..acaa7c57d 100644 --- a/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -1398,4 +1398,10 @@ public final class PersistRequestBean extends PersistRequest implements BeanP return orphanBean; } + /** + * Return the SQL used to fetch the last inserted id value. + */ + public String getSelectLastInsertedId() { + return beanDescriptor.getSelectLastInsertedId(publish); + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index f114970f9..6f951ab87 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -182,6 +182,7 @@ public class BeanDescriptor implements BeanType, STreeType { * getGeneratedKeys is not supported. */ private final String selectLastInsertedId; + private final String selectLastInsertedIdDraft; private final boolean autoTunable; @@ -473,6 +474,7 @@ public class BeanDescriptor implements BeanType, STreeType { this.sequenceInitialValue = deploy.getSequenceInitialValue(); this.sequenceAllocationSize = deploy.getSequenceAllocationSize(); this.selectLastInsertedId = deploy.getSelectLastInsertedId(); + this.selectLastInsertedIdDraft = deploy.getSelectLastInsertedIdDraft(); this.concurrencyMode = deploy.getConcurrencyMode(); this.updateChangesOnly = deploy.isUpdateChangesOnly(); this.indexDefinitions = deploy.getIndexDefinitions(); @@ -3086,8 +3088,15 @@ public class BeanDescriptor implements BeanType, STreeType { * supported. *

    */ - public String getSelectLastInsertedId() { - return selectLastInsertedId; + public String getSelectLastInsertedId(boolean publish) { + return publish ? selectLastInsertedId : selectLastInsertedIdDraft; + } + + /** + * Return true if this bean uses a SQL select to fetch the last inserted id value. + */ + public boolean supportsSelectLastInsertedId() { + return selectLastInsertedId != null; } @Override diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 470df5ac8..1083235cc 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -1387,9 +1387,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } if (IdType.IDENTITY == desc.getIdType()) { - // used when getGeneratedKeys is not supported (SQL Server 2000) + // used when getGeneratedKeys is not supported (SQL Server 2000, SAP Hana) String selectLastInsertedId = dbIdentity.getSelectLastInsertedId(desc.getBaseTable()); - desc.setSelectLastInsertedId(selectLastInsertedId); + String selectLastInsertedIdDraft = (!desc.isDraftable()) ? selectLastInsertedId : dbIdentity.getSelectLastInsertedId(desc.getDraftTable()); + desc.setSelectLastInsertedId(selectLastInsertedId, selectLastInsertedIdDraft); return; } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index e6688c222..76a54220a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -126,6 +126,7 @@ public class DeployBeanDescriptor { * Used with Identity columns but no getGeneratedKeys support. */ private String selectLastInsertedId; + private String selectLastInsertedIdDraft; /** * The concurrency mode for beans of this type. @@ -839,11 +840,16 @@ public class DeployBeanDescriptor { return selectLastInsertedId; } + public String getSelectLastInsertedIdDraft() { + return selectLastInsertedIdDraft; + } + /** * Set the SQL used to return the last inserted Id. */ - public void setSelectLastInsertedId(String selectLastInsertedId) { + public void setSelectLastInsertedId(String selectLastInsertedId, String selectLastInsertedIdDraft) { this.selectLastInsertedId = selectLastInsertedId; + this.selectLastInsertedIdDraft = selectLastInsertedIdDraft; } /** diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java index 8e7246730..70e2917c8 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/InsertHandler.java @@ -39,7 +39,7 @@ public class InsertHandler extends DmlHandler { * A SQL Select used to fetch back the Id where generatedKeys is not * supported. */ - private String selectLastInsertedId; + private boolean useSelectLastInsertedId; /** * Create to handle the insert execution. @@ -79,7 +79,7 @@ public class InsertHandler extends DmlHandler { useGeneratedKeys = true; } else { // use a query to get the last inserted id - selectLastInsertedId = meta.getSelectLastInsertedId(); + useSelectLastInsertedId = meta.supportsSelectLastInsertedId(); } } @@ -117,8 +117,7 @@ public class InsertHandler extends DmlHandler { } /** - * Execute the insert in a normal non batch fashion. Additionally using - * getGeneratedKeys if required. + * Execute non batched insert additionally using getGeneratedKeys if required. */ @Override public int execute() throws SQLException, OptimisticLockException { @@ -127,7 +126,7 @@ public class InsertHandler extends DmlHandler { // get the auto-increment value back and set into the bean getGeneratedKeys(); - } else if (selectLastInsertedId != null) { + } else if (useSelectLastInsertedId) { // fetch back the Id using a query fetchGeneratedKeyUsingSelect(); } @@ -167,12 +166,10 @@ public class InsertHandler extends DmlHandler { */ private void fetchGeneratedKeyUsingSelect() throws SQLException { - Connection conn = transaction.getConnection(); - PreparedStatement stmt = null; ResultSet rset = null; try { - stmt = conn.prepareStatement(selectLastInsertedId); + stmt = transaction.getConnection().prepareStatement(persistRequest.getSelectLastInsertedId()); rset = stmt.executeQuery(); setGeneratedKey(rset); } finally { diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java b/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java index ff11081aa..d38ae2952 100644 --- a/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java +++ b/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java @@ -38,7 +38,7 @@ public final class InsertMeta { /** * Used for DB that do not support getGeneratedKeys. */ - private final String selectLastInsertedId; + private final boolean supportsSelectLastInsertedId; private final Bindable shadowFKey; @@ -69,7 +69,7 @@ public final class InsertMeta { this.sqlNullId = null; this.sqlDraftNullId = null; this.supportsGetGeneratedKeys = false; - this.selectLastInsertedId = null; + this.supportsSelectLastInsertedId = false; } else { // insert sql for db identity or sequence insert @@ -77,11 +77,11 @@ public final class InsertMeta { if (id.getIdentityColumn() == null) { this.identityDbColumns = new String[]{}; this.supportsGetGeneratedKeys = false; - this.selectLastInsertedId = null; + this.supportsSelectLastInsertedId = false; } else { this.identityDbColumns = new String[]{id.getIdentityColumn()}; this.supportsGetGeneratedKeys = dbPlatform.getDbIdentity().isSupportsGetGeneratedKeys(); - this.selectLastInsertedId = desc.getSelectLastInsertedId(); + this.supportsSelectLastInsertedId = desc.supportsSelectLastInsertedId(); } this.sqlNullId = genSql(true, tableName, false); this.sqlDraftNullId = desc.isDraftable() ? genSql(true, draftTableName, true) : sqlNullId; @@ -116,15 +116,11 @@ public final class InsertMeta { } /** - * Returns sql that is used to fetch back the last inserted id. This will - * return null if it should not be used. - *

    - * This is only for DB's that do not support getGeneratedKeys. For MS - * SQLServer 2000 this could return "SELECT (at)(at)IDENTITY as id". - *

    + * Return true if we should use a SQL query to return the generated key. + * This can not be used with JDBC batch mode. */ - public String getSelectLastInsertedId() { - return selectLastInsertedId; + public boolean supportsSelectLastInsertedId() { + return supportsSelectLastInsertedId; } /** diff --git a/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java b/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java new file mode 100644 index 000000000..857577a9c --- /dev/null +++ b/src/test/java/io/ebean/config/PlatformNoGeneratedKeysTest.java @@ -0,0 +1,103 @@ +package io.ebean.config; + +import io.ebean.EbeanServer; +import io.ebean.EbeanServerFactory; +import io.ebean.Transaction; +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DbIdentity; +import io.ebean.config.dbplatform.IdType; +import io.ebean.config.dbplatform.h2.H2Platform; +import org.junit.Test; +import org.tests.model.basic.EBasicVer; +import org.tests.model.draftable.BasicDraftableBean; + +import static org.assertj.core.api.StrictAssertions.assertThat; + +public class PlatformNoGeneratedKeysTest { + + static EbeanServer server = testH2Server(); + + @Test + public void insertBatch_expect_noIdValuesFetched() { + + EBasicVer b0 = new EBasicVer("a"); + EBasicVer b1 = new EBasicVer("b"); + EBasicVer b2 = new EBasicVer("c"); + + try (Transaction transaction = server.beginTransaction()) { + transaction.setBatchMode(true); + + server.save(b0); + server.save(b1); + server.save(b2); + + transaction.commit(); + } + + assertThat(b0.getId()).isNull(); + assertThat(b1.getId()).isNull(); + assertThat(b2.getId()).isNull(); + + } + + @Test + public void insertNoBatch_expect_selectIdentity() { + + EBasicVer b0 = new EBasicVer("one"); + server.save(b0); + + assertThat(b0.getId()).isNotNull(); + + + BasicDraftableBean d0 = new BasicDraftableBean("done"); + server.save(d0); + + assertThat(d0.getId()).isNotNull(); + + server.publish(BasicDraftableBean.class, d0.getId()); + + BasicDraftableBean one = server.find(BasicDraftableBean.class, d0.getId()); + + assertThat(one.getName()).isEqualTo("done"); + assertThat(one.isDraft()).isFalse(); + } + + private static EbeanServer testH2Server() { + + ServerConfig config = new ServerConfig(); + config.setName("h2_noGeneratedKeys"); + + OtherH2Platform platform = new OtherH2Platform(); + DbIdentity dbIdentity = platform.getDbIdentity(); + dbIdentity.setIdType(IdType.IDENTITY); + dbIdentity.setSupportsIdentity(true); + dbIdentity.setSupportsGetGeneratedKeys(false); + dbIdentity.setSupportsSequence(false); + dbIdentity.setSelectLastInsertedIdTemplate("select identity() --{table}"); + + config.setDatabasePlatform(platform); + config.getDataSourceConfig().setUsername("sa"); + config.getDataSourceConfig().setPassword(""); + config.getDataSourceConfig().setUrl("jdbc:h2:mem:withPCQuery;"); + config.getDataSourceConfig().setDriver("org.h2.Driver"); + + config.setDisableL2Cache(true); + config.setDefaultServer(false); + config.setRegister(false); + config.setDdlGenerate(true); + config.setDdlRun(true); + config.getClasses().add(EBasicVer.class); + config.getClasses().add(BasicDraftableBean.class); + + + return EbeanServerFactory.create(config); + } + + static class OtherH2Platform extends H2Platform { + + OtherH2Platform() { + super(); + this.platform = Platform.GENERIC; + } + } +} diff --git a/src/test/java/org/tests/model/draftable/BasicDraftableBean.java b/src/test/java/org/tests/model/draftable/BasicDraftableBean.java new file mode 100644 index 000000000..98b79cb68 --- /dev/null +++ b/src/test/java/org/tests/model/draftable/BasicDraftableBean.java @@ -0,0 +1,32 @@ +package org.tests.model.draftable; + +import io.ebean.annotation.Draft; +import io.ebean.annotation.Draftable; + +import javax.persistence.Entity; + +@Entity +@Draftable +public class BasicDraftableBean extends BaseDomain { + + private String name; + + @Draft + boolean draft; + + public BasicDraftableBean(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isDraft() { + return draft; + } +} diff --git a/src/test/resources/extra-ddl.xml b/src/test/resources/extra-ddl.xml index 8ca843ad6..bb786221b 100644 --- a/src/test/resources/extra-ddl.xml +++ b/src/test/resources/extra-ddl.xml @@ -4,7 +4,7 @@ drop view order_agg_vw if exists; - + create or replace view order_agg_vw as select d.order_id, sum(d.order_qty * d.unit_price) as order_total, From 29aa395cd40c9a3cdbdcca3832aeb7ae2605e653 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 19 Oct 2018 16:24:06 +1300 Subject: [PATCH 0496/1036] #1509 - DBMigration add ... List getPendingDrops(); --- .../io/ebean/dbmigration/DbMigration.java | 6 +++++ .../dbmigration/DefaultDbMigration.java | 23 ++++++++++++++++--- .../DbMigrationDropHistoryTest.java | 7 ++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/ebean/dbmigration/DbMigration.java b/src/main/java/io/ebean/dbmigration/DbMigration.java index 1a1e0e9f6..8a9f3f427 100644 --- a/src/main/java/io/ebean/dbmigration/DbMigration.java +++ b/src/main/java/io/ebean/dbmigration/DbMigration.java @@ -7,6 +7,7 @@ import io.ebean.config.dbplatform.DatabasePlatform; import java.io.IOException; import java.util.Iterator; +import java.util.List; import java.util.ServiceLoader; /** @@ -147,6 +148,11 @@ public interface DbMigration { */ void addDatabasePlatform(DatabasePlatform databasePlatform, String prefix); + /** + * Return the list of versions that contain pending drops. + */ + List getPendingDrops(); + /** * Generate the next migration xml file and associated apply and rollback sql scripts. *

    diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index 122899571..bf662a91a 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -303,6 +303,23 @@ public class DefaultDbMigration implements DbMigration { } } + /** + * Return the versions containing pending drops. + */ + public List getPendingDrops() { + if (!online) { + DbOffline.setGenerateMigration(); + } + setDefaults(); + try { + return createRequest().getPendingDrops(); + } finally { + if (!online) { + DbOffline.reset(); + } + } + } + /** * Load the configuration for each of the target platforms. */ @@ -494,6 +511,9 @@ public class DefaultDbMigration implements DbMigration { if (nextDrop != null) { return nextDrop; } + if (generatePendingDrop != null) { + return generatePendingDrop; + } return migrationConfig.getGeneratePendingDrop(); } @@ -595,9 +615,6 @@ public class DefaultDbMigration implements DbMigration { if (name != null) { migrationConfig.setName(name); } - if (generatePendingDrop != null) { - migrationConfig.setGeneratePendingDrop(generatePendingDrop); - } } } diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationDropHistoryTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationDropHistoryTest.java index 10fd869d6..58b3a82bf 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationDropHistoryTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationDropHistoryTest.java @@ -2,7 +2,6 @@ package io.ebeaninternal.dbmigration; import io.ebean.EbeanServer; import io.ebean.EbeanServerFactory; -import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import org.junit.Test; import org.slf4j.Logger; @@ -13,6 +12,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.StrictAssertions.assertThatThrownBy; @@ -71,8 +71,11 @@ public class DbMigrationDropHistoryTest { assertThat(migration.generateMigration()).isNull(); // subsequent call + List pendingDrops = migration.getPendingDrops(); + assertThat(pendingDrops).contains("1.1"); - System.setProperty("ddl.migration.pendingDropsFor", "1.1"); + //System.setProperty("ddl.migration.pendingDropsFor", "1.1"); + migration.setGeneratePendingDrop("1.1"); assertThat(migration.generateMigration()).isEqualTo("1.2__dropsFor_1.1"); assertThatThrownBy(()->migration.generateMigration()) .isInstanceOf(IllegalArgumentException.class) From 4c2e9ccacd19079811e61ffb94c71050d12f6712 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 19 Oct 2018 20:07:16 +1300 Subject: [PATCH 0497/1036] [maven-release-plugin] prepare release ebean-11.22.10 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ba5c0f8d8..41eb76e00 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.10-SNAPSHOT + 11.22.10 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.22.10 From b1410cc660fae96c80f07cee6af4070d724e16bf Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 19 Oct 2018 20:07:32 +1300 Subject: [PATCH 0498/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 41eb76e00..b89db10dc 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.10 + 11.22.11-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.22.10 + HEAD From 158ee9a0817c89f1a223f986af1cbe214efdd653 Mon Sep 17 00:00:00 2001 From: Jonathan Bregler Date: Wed, 24 Oct 2018 10:38:17 +0200 Subject: [PATCH 0499/1036] Add SAP HANA support (#1511) --- howto-test.md | 15 ++ pom.xml | 9 +- .../config/dbplatform/DatabasePlatform.java | 28 ++- .../dbplatform/hana/HanaBasicSqlLimiter.java | 24 ++ .../dbplatform/hana/HanaHistorySupport.java | 27 ++ .../config/dbplatform/hana/HanaPlatform.java | 101 ++++++++ .../dbplatform/hana/HanaSqlLimiter.java | 35 +++ .../config/dbplatform/hana/package-info.java | 4 + .../dbmigration/DefaultDbMigration.java | 3 + .../ddlgeneration/BaseDdlHandler.java | 6 +- .../platform/AbstractHanaDdl.java | 226 +++++++++++++++++ .../ddlgeneration/platform/BaseTableDdl.java | 2 +- .../platform/DbTriggerBasedHistoryDdl.java | 6 +- .../platform/HanaColumnStoreDdl.java | 51 ++++ .../platform/HanaDdlHandler.java | 11 + .../platform/HanaHistoryDdl.java | 160 ++++++++++++ .../platform/HanaRowStoreDdl.java | 11 + .../ddlgeneration/platform/HanaTableDdl.java | 136 ++++++++++ .../ddlgeneration/platform/PlatformDdl.java | 39 ++- .../server/core/DatabasePlatformFactory.java | 6 + .../server/core/PlatformDdlBuilder.java | 3 + .../platform/DbExpressionHandlerFactory.java | 2 + .../expression/platform/HanaDbExpression.java | 60 +++++ .../server/query/CQueryBuilder.java | 2 +- .../dbmigration/builtin-extra-ddl.xml | 35 +++ src/test/java/io/ebean/BaseTestCase.java | 24 ++ .../java/io/ebean/DtoQueryFromOrmTest.java | 113 ++++----- src/test/java/io/ebean/SqlRowBooleanTest.java | 2 + .../dbplatform/HanaHistorySupportTest.java | 48 ++++ .../config/dbplatform/HanaPlatformTest.java | 67 +++++ .../dbmigration/DbMigrationGenerateTest.java | 2 + .../dbmigration/DbMigrationTest.java | 4 +- .../ddlgeneration/BaseDdlHandlerTest.java | 59 ++++- .../ddlgeneration/platform/HanaDdlTest.java | 42 ++++ .../platform/PlatformDdl_AlterColumnTest.java | 61 +++++ .../PlatformDdl_dropUniqueConstraintTest.java | 19 +- .../platform/HanaDbExpressionTest.java | 70 ++++++ .../server/grammer/EqlParserTest.java | 45 ++++ .../org/tests/basic/TestErrorBindLog.java | 7 +- .../batchinsert/TestBatchInsertFlush.java | 4 + .../batchinsert/TestBatchInsertSimple.java | 5 +- .../TestBatchOnCascadeExceptionHandling.java | 5 +- .../TestBatchSaveWithGetBeanId.java | 3 + .../java/org/tests/compositekeys/db/Type.java | 2 + .../java/org/tests/merge/TestMergeBasic.java | 42 +++- .../org/tests/merge/TestMergeCustomer.java | 34 ++- .../java/org/tests/merge/TestMergeM2M.java | 18 +- .../tests/model/array/TestDbArray_asSet.java | 6 + .../tests/model/array/TestDbArray_basic.java | 5 + .../cache/TestCacheViaComplexNaturalKey3.java | 4 + .../TestInsertBatchThenFlushThenUpdate.java | 4 + .../basic/xtra/TestInsertBatchThenUpdate.java | 5 + ...TestInsertBatchWithDifferentRootTypes.java | 4 + .../TestElementCollectionBasic.java | 50 +++- .../TestElementCollectionBasicCache.java | 21 +- .../TestElementCollectionBasicMap.java | 50 +++- .../TestElementCollectionBasicMapCache.java | 21 +- .../TestElementCollectionBasicSet.java | 48 +++- .../TestElementCollectionEmbeddedList.java | 48 +++- ...estElementCollectionEmbeddedListCache.java | 16 +- .../TestElementCollectionEmbeddedMap.java | 48 +++- ...TestElementCollectionEmbeddedMapCache.java | 14 +- .../tests/model/m2o/TestManyToOneAsOne.java | 2 +- .../album/DeleteById_SoftDelete_Tests.java | 21 +- .../o2m/jointable/TestOneToManyJoinTable.java | 35 ++- .../TestOneToManyJoinTableNoTableName.java | 11 +- .../aggregation/TestAggregationCount.java | 30 +-- .../transaction/TestBatchPersistCascade.java | 4 + .../transaction/TestNestedSubTransaction.java | 10 +- .../resources/assert/create-column-table.txt | 8 + .../migrationtest/hana/1.0__initial.sql | 235 ++++++++++++++++++ .../dbmigration/migrationtest/hana/1.1.sql | 176 +++++++++++++ .../migrationtest/hana/1.2__dropsFor_1.1.sql | 19 ++ .../dbmigration/migrationtest/hana/1.3.sql | 134 ++++++++++ .../migrationtest/hana/1.4__dropsFor_1.3.sql | 51 ++++ .../migrationtest/hana/I__create_procs.sql | 33 +++ .../hana/R__order_views_hana.sql | 7 + src/test/resources/ebean.properties | 5 + src/test/resources/extra-ddl.xml | 8 + 79 files changed, 2596 insertions(+), 215 deletions(-) create mode 100644 src/main/java/io/ebean/config/dbplatform/hana/HanaBasicSqlLimiter.java create mode 100644 src/main/java/io/ebean/config/dbplatform/hana/HanaHistorySupport.java create mode 100644 src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java create mode 100644 src/main/java/io/ebean/config/dbplatform/hana/HanaSqlLimiter.java create mode 100644 src/main/java/io/ebean/config/dbplatform/hana/package-info.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlHandler.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaRowStoreDdl.java create mode 100644 src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java create mode 100644 src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java create mode 100644 src/test/java/io/ebean/config/dbplatform/HanaHistorySupportTest.java create mode 100644 src/test/java/io/ebean/config/dbplatform/HanaPlatformTest.java create mode 100644 src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlTest.java create mode 100644 src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java create mode 100644 src/test/resources/assert/create-column-table.txt create mode 100644 src/test/resources/dbmigration/migrationtest/hana/1.0__initial.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/1.1.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/1.2__dropsFor_1.1.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/1.3.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/1.4__dropsFor_1.3.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/I__create_procs.sql create mode 100644 src/test/resources/dbmigration/migrationtest/hana/R__order_views_hana.sql diff --git a/howto-test.md b/howto-test.md index dcb2c727d..ed159cac2 100644 --- a/howto-test.md +++ b/howto-test.md @@ -151,3 +151,18 @@ In `InsertHandler.getPstmt` the `meta.getIdentityDbColumns()` contains TODO: not yet tested + +'hana' platform +-------------------- + +Requires an installed SAP HANA server - e.g. https://store.docker.com/images/sap-hana-express-edition + +- Create a user `EBEAN_TEST` with password `Eb3an_test` in the tenant database `HXE` +- Adjust the connection string and/or username in `ebean.properties` + +run: `mvn clean test -Ddatasource.default=hana` + +Current status: PASS +Tests run: 2486, Failures: 0, Errors: 0, Skipped: 84 + + diff --git a/pom.xml b/pom.xml index b89db10dc..c08c66ca6 100644 --- a/pom.xml +++ b/pom.xml @@ -117,7 +117,7 @@ io.ebean ebean-annotation - 4.2 + 4.3 @@ -270,6 +270,13 @@ 5.1.43 test + + + com.sap.cloud.db.jdbc + ngdbc + 2.3.48 + test + org.avaje.composite diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 152cd3588..035673c10 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -176,9 +176,17 @@ public class DatabasePlatform { * findIterate() and findVisit(). */ protected boolean forwardOnlyHintOnFindIterate; + + /** + * If set then use the CONCUR_UPDATABLE hint when creating ResultSets. + * + * This is {@code false} for HANA + */ + protected boolean supportsResultSetConcurrencyModeUpdatable = true; + /** - * By default we use JDBC batch when cascading (except for SQL Server). + * By default we use JDBC batch when cascading (except for SQL Server and HANA). */ protected PersistBatch persistBatchOnCascade = PersistBatch.ALL; @@ -516,6 +524,24 @@ public class DatabasePlatform { public void setForwardOnlyHintOnFindIterate(boolean forwardOnlyHintOnFindIterate) { this.forwardOnlyHintOnFindIterate = forwardOnlyHintOnFindIterate; } + + /** + * Return true if the ResultSet CONCUR_UPDATABLE Hint should be used on + * createNativeSqlTree() PreparedStatements. + *

    + * This specifically is required for Hana which doesn't support CONCUR_UPDATABLE + *

    + */ + public boolean isSupportsResultSetConcurrencyModeUpdatable() { + return supportsResultSetConcurrencyModeUpdatable; + } + + /** + * Set to true if the ResultSet CONCUR_UPDATABLE Hint should be used by default on createNativeSqlTree() PreparedStatements. + */ + public void setSupportsResultSetConcurrencyModeUpdatable(boolean supportsResultSetConcurrencyModeUpdatable) { + this.supportsResultSetConcurrencyModeUpdatable = supportsResultSetConcurrencyModeUpdatable; + } /** * Normally not needed - overridden in CockroachPlatform. diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaBasicSqlLimiter.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaBasicSqlLimiter.java new file mode 100644 index 000000000..42239fc1a --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaBasicSqlLimiter.java @@ -0,0 +1,24 @@ +package io.ebean.config.dbplatform.hana; + +import io.ebean.config.dbplatform.BasicSqlLimiter; + +public class HanaBasicSqlLimiter implements BasicSqlLimiter { + @Override + public String limit(String dbSql, int firstRow, int maxRows) { + StringBuilder sb = new StringBuilder(50 + dbSql.length()); + + sb.append(dbSql); + + if (maxRows > 0) { + sb.append(" ").append("limit"); + sb.append(" ").append(maxRows); + + if (firstRow > 0) { + sb.append(" ").append("offset").append(" "); + sb.append(firstRow); + } + } + + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaHistorySupport.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaHistorySupport.java new file mode 100644 index 000000000..ea2c20d18 --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaHistorySupport.java @@ -0,0 +1,27 @@ +package io.ebean.config.dbplatform.hana; + +import io.ebean.config.dbplatform.DbStandardHistorySupport; + +public class HanaHistorySupport extends DbStandardHistorySupport { + + @Override + public String getAsOfViewSuffix(String asOfViewSuffix) { + return " for system_time as of ?"; + } + + @Override + public String getVersionsBetweenSuffix(String asOfViewSuffix) { + return " for system_time between ? and ?"; + } + + @Override + public String getSysPeriodLower(String tableAlias, String sysPeriod) { + return tableAlias + "." + sysPeriod + "_start"; + } + + @Override + public String getSysPeriodUpper(String tableAlias, String sysPeriod) { + return tableAlias + "." + sysPeriod + "_end"; + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java new file mode 100644 index 000000000..f266bb931 --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java @@ -0,0 +1,101 @@ +package io.ebean.config.dbplatform.hana; + +import io.ebean.Query.ForUpdate; +import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; +import io.ebean.config.PlatformConfig; +import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.DbType; +import io.ebean.config.dbplatform.IdType; +import io.ebean.config.dbplatform.SqlErrorCodes; + +public class HanaPlatform extends DatabasePlatform { + public HanaPlatform() { + this.basicSqlLimiter = new HanaBasicSqlLimiter(); + + this.columnAliasPrefix = null; + + this.dbDefaultValue.setNow("current_timestamp"); + + this.dbIdentity.setIdType(IdType.IDENTITY); + this.dbIdentity.setSelectLastInsertedIdTemplate("select current_identity_value() from sys.dummy"); + this.dbIdentity.setSupportsGetGeneratedKeys(false); + this.dbIdentity.setSupportsIdentity(true); + + this.dbTypeMap.put(DbType.BIGINT, new DbPlatformType("bigint", false)); + this.dbTypeMap.put(DbType.BINARY, new DbPlatformType("varbinary", 255)); + this.dbTypeMap.put(DbType.BIT, new DbPlatformType("smallint", false)); + this.dbTypeMap.put(DbType.BLOB, new DbPlatformType("blob", false)); + this.dbTypeMap.put(DbType.CHAR, new DbPlatformType("nvarchar", 255)); + this.dbTypeMap.put(DbType.CLOB, new DbPlatformType("nclob", false)); + this.dbTypeMap.put(DbType.INTEGER, new DbPlatformType("integer", false)); + this.dbTypeMap.put(DbType.JSONVARCHAR, new DbPlatformType("nvarchar", 255)); + this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry")); + this.dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("blob", false)); + this.dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nclob", false)); + this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry")); + this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry")); + this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry")); + this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point")); + this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry")); + this.dbTypeMap.put(DbType.SMALLINT, new DbPlatformType("smallint", false)); + this.dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint", false)); + this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40)); + this.dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255)); + this.dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255)); + + this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("131", "133", "146") + .addDataIntegrity("130", "429", "461", "462").addDuplicateKey("144", "301", "349").build(); + + this.historySupport = new HanaHistorySupport(); + + this.likeClauseRaw = "like ?"; + + this.maxConstraintNameLength = 127; + this.maxTableNameLength = 127; + + this.persistBatchOnCascade = PersistBatch.NONE; + + this.platform = Platform.HANA; + + this.sqlLimiter = new HanaSqlLimiter(); + + this.supportsResultSetConcurrencyModeUpdatable = false; + } + + @Override + protected void addGeoTypes(int srid) { + this.dbTypeMap.put(DbType.LINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false)); + this.dbTypeMap.put(DbType.MULTILINESTRING, new DbPlatformType("st_geometry(" + srid + ")", false)); + this.dbTypeMap.put(DbType.MULTIPOINT, new DbPlatformType("st_geometry(" + srid + ")", false)); + this.dbTypeMap.put(DbType.MULTIPOLYGON, new DbPlatformType("st_geometry(" + srid + ")", false)); + this.dbTypeMap.put(DbType.POINT, new DbPlatformType("st_point(" + srid + ")", false)); + this.dbTypeMap.put(DbType.POLYGON, new DbPlatformType("st_geometry(" + srid + ")", false)); + } + + @Override + protected String withForUpdate(String sql, ForUpdate forUpdateMode) { + switch (forUpdateMode) { + case BASE: + return sql + " for update"; + case NOWAIT: + return sql + " for update nowait"; + case SKIPLOCKED: + return sql + " for update ignore locked"; + default: + throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name()); + } + } + + @Override + protected void configure(PlatformConfig config, boolean allQuotedIdentifiers) { + super.configure(config, allQuotedIdentifiers); + if (config.getDbUuid().useBinary()) { + this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varbinary", 16)); + } else { + this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40)); + } + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaSqlLimiter.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaSqlLimiter.java new file mode 100644 index 000000000..bf8ca4e7b --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaSqlLimiter.java @@ -0,0 +1,35 @@ +package io.ebean.config.dbplatform.hana; + +import io.ebean.config.dbplatform.SqlLimitRequest; +import io.ebean.config.dbplatform.SqlLimitResponse; +import io.ebean.config.dbplatform.SqlLimiter; + +public class HanaSqlLimiter implements SqlLimiter { + @Override + public SqlLimitResponse limit(SqlLimitRequest request) { + String dbSql = request.getDbSql(); + + StringBuilder sb = new StringBuilder(50 + dbSql.length()); + sb.append("select "); + if (request.isDistinct()) { + sb.append("distinct "); + } + + sb.append(dbSql); + + int firstRow = request.getFirstRow(); + int maxRows = request.getMaxRows(); + + if (maxRows > 0) { + sb.append(" ").append("limit ").append(maxRows); + if (firstRow > 0) { + sb.append(" ").append("offset "); + sb.append(firstRow); + } + } + + String sql = request.getDbPlatform().completeSql(sb.toString(), request.getOrmQuery()); + + return new SqlLimitResponse(sql, false); + } +} \ No newline at end of file diff --git a/src/main/java/io/ebean/config/dbplatform/hana/package-info.java b/src/main/java/io/ebean/config/dbplatform/hana/package-info.java new file mode 100644 index 000000000..55fc12c5e --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/hana/package-info.java @@ -0,0 +1,4 @@ +/** + * SAP HANA specific support. + */ +package io.ebean.config.dbplatform.hana; diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index bf662a91a..19817a924 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -10,6 +10,7 @@ import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; @@ -679,6 +680,8 @@ public class DefaultDbMigration implements DbMigration { return new DB2Platform(); case SQLITE: return new SQLitePlatform(); + case HANA: + return new HanaPlatform(); case GENERIC: return new DatabasePlatform(); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandler.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandler.java index ac5f64557..29ee263bc 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandler.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandler.java @@ -28,7 +28,11 @@ public class BaseDdlHandler implements DdlHandler { protected final TableDdl tableDdl; public BaseDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl) { - this.tableDdl = new BaseTableDdl(serverConfig, platformDdl); + this(serverConfig, platformDdl, new BaseTableDdl(serverConfig, platformDdl)); + } + + protected BaseDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl, TableDdl tableDdl) { + this.tableDdl = tableDdl; } @Override diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java new file mode 100644 index 000000000..b898c02a6 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java @@ -0,0 +1,226 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import java.io.IOException; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.ebean.config.ServerConfig; +import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; +import io.ebeaninternal.dbmigration.migration.AlterColumn; + +public abstract class AbstractHanaDdl extends PlatformDdl { + + private static final Pattern ARRAY_PATTERN = Pattern.compile("(\\w+)\\s*\\[\\s*\\]\\s*(\\(\\d+\\))?", + Pattern.CASE_INSENSITIVE); + + public AbstractHanaDdl(DatabasePlatform platform) { + super(platform); + this.addColumn = "add ("; + this.addColumnSuffix = ")"; + this.alterColumn = "alter ("; + this.alterColumnSuffix = ")"; + this.columnDropDefault = " default null"; + this.columnSetDefault = " default"; + this.columnSetNotnull = " not null"; + this.columnSetNull = " null"; + this.dropColumn = "drop ("; + this.dropColumnSuffix = ")"; + this.dropConstraintIfExists = "drop constraint "; + this.dropIndexIfExists = "drop index "; + this.dropSequenceIfExists = "drop sequence "; + this.dropTableCascade = " cascade"; + this.dropTableIfExists = "drop table "; + this.fallbackArrayType = "nvarchar(1000)"; + this.historyDdl = new HanaHistoryDdl(); + this.identitySuffix = " generated by default as identity"; + } + + @Override + public String alterColumnBaseAttributes(AlterColumn alter) { + String tableName = alter.getTableName(); + String columnName = alter.getColumnName(); + String currentType = alter.getCurrentType(); + String type = alter.getType() != null ? alter.getType() : currentType; + type = convert(type, false); + currentType = convert(currentType, false); + boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull()); + String notnullClause = notnull ? " not null" : ""; + String defaultValue = DdlHelp.isDropDefault(alter.getDefaultValue()) ? "null" + : (alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue()); + String defaultValueClause = (defaultValue == null || defaultValue.isEmpty()) ? "" : " default " + defaultValue; + + try { + DdlBuffer buffer = new BaseDdlBuffer(null); + if (!isConvertible(currentType, type)) { + // add an intermediate conversion if possible + if (isNumberType(currentType)) { + // numbers can always be converted to decimal + buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) + .append(" decimal ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) + .endOfStatement(); + } else if (isStringType(currentType)) { + // strings can always be converted to nclob + buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) + .append(" nclob ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) + .endOfStatement(); + } + } + + buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) + .append(" ").append(type).append(defaultValueClause).append(notnullClause).append(alterColumnSuffix); + + return buffer.getBuffer(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { + throw new UnsupportedOperationException(); + } + + @Override + public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { + return null; + } + + @Override + public DdlHandler createDdlHandler(ServerConfig serverConfig) { + return new HanaDdlHandler(serverConfig, this); + } + + @Override + public String alterColumnType(String tableName, String columnName, String type) { + return null; + } + + @Override + protected String convertArrayType(String logicalArrayType) { + Matcher matcher = ARRAY_PATTERN.matcher(logicalArrayType); + if (matcher.matches()) { + return convert(matcher.group(1), false) + " array" + (matcher.group(2) == null ? "" : matcher.group(2)); + } else { + return fallbackArrayType; + } + } + + @Override + public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, + String[] nullableColumns) { + if (nullableColumns == null || nullableColumns.length == 0) { + return super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns); + } else { + return "-- cannot create unique index \"" + uqName + "\" on table \"" + tableName + "\" with nullable columns"; + } + } + + @Override + public String alterTableDropUniqueConstraint(String tableName, String uniqueConstraintName) { + DdlBuffer buffer = new BaseDdlBuffer(null); + try { + buffer.append("delimiter $$").newLine(); + buffer.append("do").newLine(); + buffer.append("begin").newLine(); + buffer.append("declare exit handler for sql_error_code 397 begin end").endOfStatement(); + buffer.append("exec 'alter table ").append(tableName).append(" ").append(dropUniqueConstraint).append(" ") + .append(maxConstraintName(uniqueConstraintName)).append("'").endOfStatement(); + buffer.append("end").endOfStatement(); + buffer.append("$$"); + return buffer.getBuffer(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public String alterTableDropConstraint(String tableName, String constraintName) { + return alterTableDropUniqueConstraint(tableName, constraintName); + } + + /** + * It is rather complex to delete a column on HANA as there must not exist any + * foreign keys. That's why we call a user stored procedure here + */ + @Override + public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { + buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')") + .endOfStatement(); + } + + /** + * Check if a data type can be converted to another data type. Data types can't + * be converted if the target type has a lower precision than the source type. + * + * @param sourceType The source data type + * @param targetType the target data type + * @return {@code true} if the type can be converted, {@code false} otherwise + */ + private boolean isConvertible(String sourceType, String targetType) { + if (Objects.equals(sourceType, targetType)) { + return true; + } + + if (sourceType == null || targetType == null) { + return true; + } + + if ("bigint".equals(sourceType)) { + if ("integer".equals(targetType) || "smallint".equals(targetType) || "tinyint".equals(targetType)) { + return false; + } + } else if ("integer".equals(sourceType)) { + if ("smallint".equals(targetType) || "tinyint".equals(targetType)) { + return false; + } + } else if ("smallint".equals(sourceType)) { + if ("tinyint".equals(targetType)) { + return false; + } + } else if ("double".equals(sourceType)) { + if ("real".equals(targetType)) { + return false; + } + } + + DbPlatformType dbPlatformSourceType = DbPlatformType.parse(sourceType); + + if ("float".equals(dbPlatformSourceType.getName())) { + if ("real".equals(targetType)) { + return false; + } + } else if ("varchar".equals(dbPlatformSourceType.getName()) || "nvarchar".equals(dbPlatformSourceType.getName())) { + DbPlatformType dbPlatformTargetType = DbPlatformType.parse(targetType); + if ("varchar".equals(dbPlatformTargetType.getName()) || "nvarchar".equals(dbPlatformTargetType.getName())) { + if (dbPlatformSourceType.getDefaultLength() > dbPlatformTargetType.getDefaultLength()) { + return false; + } + } + } else if ("decimal".equals(dbPlatformSourceType.getName())) { + DbPlatformType dbPlatformTargetType = DbPlatformType.parse(targetType); + if ("decimal".equals(dbPlatformTargetType.getName())) { + if (dbPlatformSourceType.getDefaultLength() > dbPlatformTargetType.getDefaultLength() + || dbPlatformSourceType.getDefaultScale() > dbPlatformTargetType.getDefaultScale()) { + return false; + } + } + } + + return true; + } + + private boolean isNumberType(String type) { + return type != null + && ("bigint".equals(type) || "integer".equals(type) || "smallint".equals(type) || "tinyint".equals(type) + || type.startsWith("float") || "real".equals(type) || "double".equals(type) || type.startsWith("decimal")); + } + + private boolean isStringType(String type) { + return type != null + && (type.startsWith("varchar") || type.startsWith("nvarchar") || "clob".equals(type) || "nclob".equals(type)); + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java index 7b3c72bb9..2a46f83a0 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/BaseTableDdl.java @@ -260,7 +260,7 @@ public class BaseTableDdl implements TableDdl { String partitionMode = createTable.getPartitionMode(); DdlBuffer apply = writer.apply(); - apply.append("create table ").append(tableName).append(" ("); + apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(tableName).append(" ("); writeTableColumns(apply, columns, useIdentity); writeCheckConstraints(apply, createTable); writeUniqueConstraints(apply, createTable); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DbTriggerBasedHistoryDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DbTriggerBasedHistoryDdl.java index 5eb3d6978..a425cf9be 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DbTriggerBasedHistoryDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/DbTriggerBasedHistoryDdl.java @@ -175,7 +175,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl { protected void createHistoryTable(DdlBuffer apply, MTable table) throws IOException { - apply.append("create table ").append(table.getName()).append(historySuffix).append("(").newLine(); + apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(table.getName()).append(historySuffix).append("(").newLine(); Collection cols = table.allColumns(); for (MColumn column : cols) { @@ -238,8 +238,8 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl { } protected void dropSysPeriodColumns(DdlBuffer buffer, String baseTableName) throws IOException { - buffer.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriodStart).endOfStatement(); - buffer.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriodEnd).endOfStatement(); + platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodStart); + platformDdl.alterTableDropColumn(buffer, baseTableName, sysPeriodEnd); } protected void appendInsertIntoHistory(DdlBuffer buffer, String historyTable, List columns) throws IOException { diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java new file mode 100644 index 000000000..b3b36c3ef --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaColumnStoreDdl.java @@ -0,0 +1,51 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import java.io.IOException; + +import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; + +public class HanaColumnStoreDdl extends AbstractHanaDdl { + + public HanaColumnStoreDdl(DatabasePlatform platform) { + super(platform); + this.createTable = "create column table"; + } + + @Override + public String createIndex(String indexName, String tableName, String[] columns) { + if (columns == null || columns.length == 0) { + return "-- cannot create index: no columns given"; + } + + if (columns.length == 1) { + return "-- explicit index \"" + indexName + "\" for single column \"" + columns[0] + "\" of table \"" + tableName + + "\" is not necessary"; + } + + StringBuilder buffer = new StringBuilder(); + buffer.append("create inverted hash index ").append(maxConstraintName(indexName)).append(" on ").append(tableName); + appendColumns(columns, buffer); + + return buffer.toString(); + } + + @Override + public String dropIndex(String indexName, String tableName) { + DdlBuffer buffer = new BaseDdlBuffer(null); + try { + buffer.append("delimiter $$").newLine(); + buffer.append("do").newLine(); + buffer.append("begin").newLine(); + buffer.append("declare exit handler for sql_error_code 261 begin end").endOfStatement(); + buffer.append("exec '").append(dropIndexIfExists).append(maxConstraintName(indexName)).append("'") + .endOfStatement(); + buffer.append("end").endOfStatement(); + buffer.append("$$"); + return buffer.getBuffer(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlHandler.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlHandler.java new file mode 100644 index 000000000..b3355e280 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlHandler.java @@ -0,0 +1,11 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.config.ServerConfig; +import io.ebeaninternal.dbmigration.ddlgeneration.BaseDdlHandler; + +public class HanaDdlHandler extends BaseDdlHandler { + + public HanaDdlHandler(ServerConfig serverConfig, PlatformDdl platformDdl) { + super(serverConfig, platformDdl, new HanaTableDdl(serverConfig, platformDdl)); + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java new file mode 100644 index 000000000..0ea165ba3 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java @@ -0,0 +1,160 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + +import io.ebean.config.ServerConfig; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; +import io.ebeaninternal.dbmigration.migration.AddHistoryTable; +import io.ebeaninternal.dbmigration.migration.DropHistoryTable; +import io.ebeaninternal.dbmigration.model.MColumn; +import io.ebeaninternal.dbmigration.model.MTable; + +public class HanaHistoryDdl implements PlatformHistoryDdl { + + private String systemPeriodStart; + private String systemPeriodEnd; + private PlatformDdl platformDdl; + private String historySuffix; + private final AtomicInteger counter = new AtomicInteger(0); + private Map createdHistoryTables = new ConcurrentHashMap<>(); + + @Override + public void configure(ServerConfig serverConfig, PlatformDdl platformDdl) { + this.systemPeriodStart = serverConfig.getAsOfSysPeriod() + "_start"; + this.systemPeriodEnd = serverConfig.getAsOfSysPeriod() + "_end"; + this.platformDdl = platformDdl; + this.historySuffix = serverConfig.getHistoryTableSuffix(); + } + + @Override + public void createWithHistory(DdlWrite writer, MTable table) throws IOException { + String tableName = table.getName(); + String historyTableName = tableName + historySuffix; + DdlBuffer apply = writer.applyHistoryView(); + if (apply.isEmpty()) { + createdHistoryTables.clear(); + } + + apply.append(platformDdl.getCreateTableCommandPrefix()).append(" ").append(historyTableName).append(" (").newLine(); + + // create history table + Collection cols = table.allColumns(); + for (MColumn column : cols) { + if (!column.isDraftOnly()) { + writeColumnDefinition(apply, column.getName(), column.getType(), column.getDefaultValue(), column.isNotnull(), + column.isIdentity() ? platformDdl.identitySuffix : null); + apply.append(",").newLine(); + } + } + writeColumnDefinition(apply, systemPeriodStart, "TIMESTAMP", null, false, null); + apply.append(",").newLine(); + writeColumnDefinition(apply, systemPeriodEnd, "TIMESTAMP", null, false, null); + apply.newLine().append(")").endOfStatement(); + + // enable system versioning + apply.append("alter table ").append(tableName).append(" add (").newLine(); + apply.append(" ").append(systemPeriodStart).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, ") + .newLine(); + apply.append(" ").append(systemPeriodEnd).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END").newLine(); + apply.append(")").endOfStatement(); + + apply.append("alter table ").append(tableName).append(" add period for system_time(").append(systemPeriodStart) + .append(",").append(systemPeriodEnd).append(")").endOfStatement(); + + enableSystemVersioning(apply, tableName, historyTableName, true, false); + + createdHistoryTables.put(tableName, historyTableName); + + dropHistoryTable(writer.dropAll(), tableName, historyTableName); + } + + @Override + public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException { + dropHistoryTable(writer.applyDropDependencies(), dropHistoryTable.getBaseTable(), + dropHistoryTable.getBaseTable() + historySuffix); + } + + protected void dropHistoryTable(DdlBuffer apply, String baseTable, String historyTable) throws IOException { + // disable system versioning + disableSystemVersioning(apply, baseTable); + + apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement(); + + // drop the period columns + apply.append("alter table ").append(baseTable).append(" drop (").append(systemPeriodStart).append(",") + .append(systemPeriodEnd).append(")").endOfStatement(); + + // drop the history table + apply.append("drop table ").append(historyTable).append(" cascade").endOfStatement(); + } + + @Override + public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException { + MTable table = writer.getTable(addHistoryTable.getBaseTable()); + if (table == null) { + throw new IllegalStateException( + "MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)"); + } + createWithHistory(writer, table); + } + + @Override + public void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) throws IOException { + // nothing to do + } + + protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue, + boolean isNotNull, String generated) throws IOException { + + String platformType = platformDdl.convert(type, false); + buffer.append(" ").append(platformDdl.lowerColumnName(columnName)); + buffer.append(" ").append(platformType); + if (defaultValue != null) { + buffer.append(" default ").append(defaultValue); + } + if (isNotNull) { + buffer.append(" not null"); + } + if (generated != null) { + buffer.append(" ").append(generated); + } + } + + public void disableSystemVersioning(DdlBuffer apply, String tableName) throws IOException { + disableSystemVersioning(apply, tableName, false); + } + + public void disableSystemVersioning(DdlBuffer apply, String tableName, boolean uniqueStatement) throws IOException { + apply.append("alter table ").append(tableName).append(" drop system versioning"); + if (uniqueStatement) { + // needed for the DB migration test to prevent the statement from being filtered + // out as a duplicate + apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */"); + } + apply.endOfStatement(); + } + + public void enableSystemVersioning(DdlBuffer apply, String tableName, String historyTableName, boolean validated, + boolean uniqueStatement) throws IOException { + apply.append("alter table ").append(tableName).append(" add system versioning history table ") + .append(historyTableName); + if (!validated) { + apply.append(" not validated"); + } + if (uniqueStatement) { + // needed for the DB migration test to prevent the statement from being filtered + // out as a duplicate + apply.append(" /* ").append(String.valueOf(counter.getAndIncrement())).append(" */"); + } + apply.endOfStatement(); + } + + public boolean isSystemVersioningEnabled(String tableName) { + return !createdHistoryTables.containsKey(tableName); + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaRowStoreDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaRowStoreDdl.java new file mode 100644 index 000000000..d662f1039 --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaRowStoreDdl.java @@ -0,0 +1,11 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import io.ebean.config.dbplatform.DatabasePlatform; + +public class HanaRowStoreDdl extends AbstractHanaDdl { + + public HanaRowStoreDdl(DatabasePlatform platform) { + super(platform); + this.createTable = "create row table"; + } +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java new file mode 100644 index 000000000..1d0b47abc --- /dev/null +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java @@ -0,0 +1,136 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import java.io.IOException; +import java.util.List; + +import io.ebean.config.PropertiesWrapper; +import io.ebean.config.ServerConfig; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; +import io.ebeaninternal.dbmigration.migration.AddColumn; +import io.ebeaninternal.dbmigration.migration.AlterColumn; +import io.ebeaninternal.dbmigration.migration.Column; +import io.ebeaninternal.dbmigration.migration.DropColumn; +import io.ebeaninternal.dbmigration.model.MTable; + +public class HanaTableDdl extends BaseTableDdl { + + private final HanaHistoryDdl historyDdl; + private final boolean generateUniqueDdl; + + public HanaTableDdl(ServerConfig serverConfig, PlatformDdl platformDdl) { + super(serverConfig, platformDdl); + this.historyDdl = (HanaHistoryDdl) platformDdl.historyDdl; + if (serverConfig.getProperties() != null) { + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "hana", serverConfig.getProperties(), + serverConfig.getClassLoadConfig()); + this.generateUniqueDdl = wrapper.getBoolean("generateUniqueDdl", false); + } else { + this.generateUniqueDdl = false; + } + } + + @Override + protected void alterColumnDefaultValue(DdlWrite writer, AlterColumn alter) throws IOException { + String ddl = platformDdl.alterColumnBaseAttributes(alter); + if (hasValue(ddl)) { + writer.apply().append(ddl).endOfStatement(); + } + } + + @Override + public void generate(DdlWrite writer, AddColumn addColumn) throws IOException { + String tableName = addColumn.getTableName(); + MTable table = writer.getTable(tableName); + if (table == null) { + super.generate(writer, addColumn); + return; + } + + boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName); + + if (manageSystemVersioning) { + historyDdl.disableSystemVersioning(writer.apply(), table.getName(), this.generateUniqueDdl); + } + + super.generate(writer, addColumn); + + if (manageSystemVersioning) { + // make same changes to the history table + String historyTable = historyTable(tableName); + List columns = addColumn.getColumn(); + for (Column column : columns) { + alterTableAddColumn(writer.apply(), historyTable, column, true, true); + } + + historyDdl.enableSystemVersioning(writer.apply(), table.getName(), historyTable, false, this.generateUniqueDdl); + } + } + + @Override + public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException { + String tableName = alterColumn.getTableName(); + MTable table = writer.getTable(tableName); + if (table == null) { + super.generate(writer, alterColumn); + return; + } + + boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName); + + if (manageSystemVersioning) { + historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl); + } + + super.generate(writer, alterColumn); + + if (manageSystemVersioning) { + // make same changes to the history table + String historyTable = historyTable(tableName); + if (hasValue(alterColumn.getType()) || hasValue(alterColumn.getDefaultValue()) + || alterColumn.isNotnull() != null) { + AlterColumn alterHistoryColumn = new AlterColumn(); + alterHistoryColumn.setTableName(historyTable); + alterHistoryColumn.setColumnName(alterColumn.getColumnName()); + alterHistoryColumn.setType(alterColumn.getType()); + alterHistoryColumn.setDefaultValue(alterColumn.getDefaultValue()); + alterHistoryColumn.setNotnull(alterColumn.isNotnull()); + alterHistoryColumn.setCurrentType(alterColumn.getCurrentType()); + alterHistoryColumn.setCurrentDefaultValue(alterColumn.getCurrentDefaultValue()); + alterHistoryColumn.setCurrentNotnull(alterColumn.isCurrentNotnull()); + String histColumnDdl = platformDdl.alterColumnBaseAttributes(alterHistoryColumn); + + // write the apply to history table + writer.apply().append(histColumnDdl).endOfStatement(); + } + + historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl); + } + } + + @Override + public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException { + String tableName = dropColumn.getTableName(); + MTable table = writer.getTable(tableName); + if (table == null) { + super.generate(writer, dropColumn); + return; + } + + boolean manageSystemVersioning = isTrue(table.isWithHistory()) && historyDdl.isSystemVersioningEnabled(tableName); + + if (manageSystemVersioning) { + historyDdl.disableSystemVersioning(writer.apply(), tableName, this.generateUniqueDdl); + } + + super.generate(writer, dropColumn); + + if (manageSystemVersioning) { + // also drop from the history table + String historyTable = historyTable(tableName); + alterTableDropColumn(writer.apply(), historyTable, dropColumn.getColumnName()); + + historyDdl.enableSystemVersioning(writer.apply(), tableName, historyTable, false, this.generateUniqueDdl); + } + } + +} diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java index 515004bd5..a07dcdfd6 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl.java @@ -78,12 +78,16 @@ public class PlatformDdl { protected String dropIndexIfExists = "drop index if exists "; protected String alterColumn = "alter column"; + + protected String alterColumnSuffix = ""; protected String dropUniqueConstraint = "drop constraint"; protected String addConstraint = "add constraint"; protected String addColumn = "add column"; + + protected String addColumnSuffix = ""; protected String columnSetType = ""; @@ -96,6 +100,12 @@ public class PlatformDdl { protected String columnSetNull = "set null"; protected String updateNullWithDefault = "update ${table} set ${column} = ${default} where ${column} is null"; + + protected String createTable = "create table"; + + protected String dropColumn = "drop column"; + + protected String dropColumnSuffix = ""; /** * Set false for MsSqlServer to allow multiple nulls for OneToOne mapping. @@ -458,6 +468,7 @@ public class PlatformDdl { if (isTrue(column.isNotnull())) { buffer.append(" not null"); } + buffer.append(addColumnSuffix); buffer.endOfStatement(); // check constraints cannot be added in one statement for h2 @@ -467,14 +478,15 @@ public class PlatformDdl { buffer.append(ddl).endOfStatement(); } } else { + buffer.append(addColumnSuffix); buffer.endOfStatement(); } } public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { - buffer.append("alter table ").append(tableName).append(" drop column ").append(columnName) - .endOfStatement(); + buffer.append("alter table ").append(tableName).append(" ").append(dropColumn).append(" ").append(columnName) + .append(dropColumnSuffix).endOfStatement(); } /** @@ -494,19 +506,19 @@ public class PlatformDdl { */ public String alterColumnType(String tableName, String columnName, String type) { - return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type, false); + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + columnSetType + convert(type, false) + alterColumnSuffix; } /** * Alter a column adding or removing the not null constraint. *

    - * Note that that MySql and SQL Server instead use alterColumnBaseAttributes() + * Note that that MySql, SQL Server, and HANA instead use alterColumnBaseAttributes() *

    */ public String alterColumnNotnull(String tableName, String columnName, boolean notnull) { String suffix = notnull ? columnSetNotnull : columnSetNull; - return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix; + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; } /** @@ -522,17 +534,17 @@ public class PlatformDdl { */ public String alterColumnDefaultValue(String tableName, String columnName, String defaultValue) { String suffix = DdlHelp.isDropDefault(defaultValue) ? columnDropDefault : columnSetDefault + " " + convertDefaultValue(defaultValue); - return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix; + return "alter table " + tableName + " " + alterColumn + " " + columnName + " " + suffix + alterColumnSuffix; } /** * Alter column setting both the type and not null constraint. *

    - * Used by MySql and SQL Server as these require both column attributes to be set together. + * Used by MySql, SQL Server, and HANA as these require both column attributes to be set together. *

    */ public String alterColumnBaseAttributes(AlterColumn alter) { - // by default do nothing, only used by mysql and sql server as they can only + // by default do nothing, only used by mysql, sql server, and HANA as they can only // modify the column with the full column definition return null; } @@ -662,6 +674,17 @@ public class PlatformDdl { public void unlockTables(DdlBuffer buffer, Collection tables) throws IOException { } + + /** + * Returns the database-specific "create table" command prefix. For HANA this is + * either "create column table" or "create row table", for all other databases + * it is "create table". + * + * @return The "create table" command prefix + */ + public String getCreateTableCommandPrefix() { + return createTable; + } public boolean suppressPrimaryKeyOnPartition() { return false; diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index efeb3d9e0..acf955620 100644 --- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -5,6 +5,7 @@ import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.cockroach.CockroachPlatform; import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; @@ -106,6 +107,9 @@ public class DatabasePlatformFactory { if (dbName.equals("sqlite")) { return new SQLitePlatform(); } + if (dbName.equals("hana")) { + return new HanaPlatform(); + } throw new RuntimeException("database platform " + dbName + " is not known?"); } @@ -156,6 +160,8 @@ public class DatabasePlatformFactory { return new DB2Platform(); } else if (dbProductName.contains("sql anywhere")) { return new SqlAnywherePlatform(); + }else if (dbProductName.contains("hdb")) { + return new HanaPlatform(); } // use the standard one diff --git a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java index bf901ed50..dbf657c49 100644 --- a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java +++ b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java @@ -4,6 +4,7 @@ import io.ebean.config.dbplatform.DatabasePlatform; import io.ebeaninternal.dbmigration.ddlgeneration.platform.CockroachDdl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.DB2Ddl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl; +import io.ebeaninternal.dbmigration.ddlgeneration.platform.HanaColumnStoreDdl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.HsqldbDdl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.MySqlDdl; import io.ebeaninternal.dbmigration.ddlgeneration.platform.Oracle10Ddl; @@ -47,6 +48,8 @@ public class PlatformDdlBuilder { case SQLSERVER17: case SQLSERVER: return new SqlServerDdl(platform); + case HANA: + return new HanaColumnStoreDdl(platform); default: return new PlatformDdl(platform); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java index e9696e5b6..1bebb5e96 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java @@ -25,6 +25,8 @@ public class DbExpressionHandlerFactory { case SQLSERVER17: case SQLSERVER: return new SqlServerDbExpression(); + case HANA: + return new HanaDbExpression(); default: return new BasicDbExpression(); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java new file mode 100644 index 000000000..0593bdb84 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java @@ -0,0 +1,60 @@ +package io.ebeaninternal.server.expression.platform; + +import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.BitwiseOp; +import io.ebeaninternal.server.expression.Op; + +/** + * HANA handling of platform specific expressions. + */ +public class HanaDbExpression extends BaseDbExpression { + + @Override + public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, + long match) { + bitwiseFunction(request, propName, operator, compare); + } + + @Override + public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + request.append("json_value(").append(propName).append(", '$.").append(path).append("')"); + request.append(operator.bind()); + } + + @Override + public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { + request.append("cardinality(").append(propName).append(")"); + if (empty) { + request.append(" = 0"); + } else { + request.append(" <> 0"); + } + } + + @Override + public String concat(String property0, String separator, String property1, String suffix) { + StringBuilder sb = new StringBuilder(); + sb.append("concat(").append(property0).append(", '").append(separator).append("'||").append(property1); + if (suffix != null && !suffix.isEmpty()) { + sb.append("||'").append(suffix).append('\''); + } + sb.append(")"); + return sb.toString(); + } + + @Override + public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) { + for (int i = 0; i < values.length; i++) { + if (i > 0) { + request.append(" and "); + } + request.append("(?"); + if (!contains) { + request.append(" not "); + } + request.append(" member of ").append(propName).append(")"); + + } + } + +} diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index a58c7b6ec..eeacc87df 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -426,7 +426,7 @@ class CQueryBuilder { try { // For SqlServer we need either "selectMethod=cursor" in the connection string or fetch explicitly a cursorable // statement here by specifying ResultSet.CONCUR_UPDATABLE - PreparedStatement statement = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + PreparedStatement statement = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, dbPlatform.isSupportsResultSetConcurrencyModeUpdatable() ? ResultSet.CONCUR_UPDATABLE : ResultSet.CONCUR_READ_ONLY); predicates.bind(statement, connection); ResultSet resultSet = statement.executeQuery(); diff --git a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml index 825171455..d50eef8b6 100644 --- a/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml +++ b/src/main/resources/io/ebeaninternal/dbmigration/builtin-extra-ddl.xml @@ -159,4 +159,39 @@ BEGIN 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/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java index cee47bcaf..7fd97fa9e 100644 --- a/src/test/java/io/ebean/BaseTestCase.java +++ b/src/test/java/io/ebean/BaseTestCase.java @@ -1,5 +1,6 @@ package io.ebean; +import io.ebean.annotation.PersistBatch; import io.ebean.annotation.Platform; import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaTimedMetric; @@ -10,6 +11,9 @@ import io.ebeaninternal.api.SpiQuery; import io.ebeaninternal.server.core.HelpCreateQueryRequest; import io.ebeaninternal.server.core.OrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.expression.platform.DbExpressionHandler; +import io.ebeaninternal.server.expression.platform.DbExpressionHandlerFactory; + import org.avaje.agentloader.AgentLoader; import org.junit.runner.RunWith; import org.slf4j.Logger; @@ -144,6 +148,10 @@ public abstract class BaseTestCase { public boolean isMySql() { return Platform.MYSQL == platform(); } + + public boolean isHana() { + return Platform.HANA == platform(); + } public boolean isPlatformBooleanNative() { return Types.BOOLEAN == spiEbeanServer().getDatabasePlatform().getBooleanDbType(); @@ -152,6 +160,10 @@ public abstract class BaseTestCase { public boolean isPlatformOrderNullsSupport() { return isH2() || isPostgres(); } + + public boolean isPersistBatchOnCascade() { + return spiEbeanServer().getDatabasePlatform().getPersistBatchOnCascade() != PersistBatch.NONE; + } /** * Wait for the L2 cache to propagate changes post-commit. @@ -205,6 +217,18 @@ public abstract class BaseTestCase { assertThat(sql).contains(containsIn+" not in "); } } + + /** + * Platform specific CONCAT clause. + */ + protected String concat(String property0, String separator, String property1) { + return concat(property0, separator, property1, null); + } + + protected String concat(String property0, String separator, String property1, String suffix) { + DbExpressionHandler dbExpressionHandler = DbExpressionHandlerFactory.from(spiEbeanServer().getDatabasePlatform()); + return dbExpressionHandler.concat(property0, separator, property1, suffix); + } protected OrmQueryRequest createQueryRequest(SpiQuery.Type type, Query query, Transaction t) { return HelpCreateQueryRequest.create(server(), type, query, t); diff --git a/src/test/java/io/ebean/DtoQueryFromOrmTest.java b/src/test/java/io/ebean/DtoQueryFromOrmTest.java index 07e8b3122..3a1adf02c 100644 --- a/src/test/java/io/ebean/DtoQueryFromOrmTest.java +++ b/src/test/java/io/ebean/DtoQueryFromOrmTest.java @@ -3,6 +3,7 @@ package io.ebean; import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaQueryMetric; import io.ebean.meta.MetaTimedMetric; + import org.ebeantest.LoggedSqlCollector; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -43,17 +44,13 @@ public class DtoQueryFromOrmTest extends BaseTestCase { resetAllMetrics(); - String[] prefix = {"Bl", "B", "Red", "jim"}; + String[] prefix = { "Bl", "B", "Red", "jim" }; for (String val : prefix) { List list = Ebean.find(Contact.class) - .select("email, concat(lastName,', ',firstName) as fullName") - .where().istartsWith("concat(lastName,', ',firstName)", val) - .orderBy().asc("lastName") - .setMaxRows(10) - .asDto(ContactDto.class) - .setLabel("prefixLoop") - .findList(); + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where() + .istartsWith(concat("lastName", ", ", "firstName"), val).orderBy().asc("lastName").setMaxRows(10) + .asDto(ContactDto.class).setLabel("prefixLoop").findList(); System.out.println("List:" + list); } @@ -77,14 +74,10 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - DtoQuery query = - Ebean.find(Contact.class) + DtoQuery query = Ebean.find(Contact.class) // we must explicitly add the id property for DTO query (if we want it) - .select("id, email, concat(lastName,', ',firstName) as fullName") - .where().isNotNull("email").isNotNull("lastName") - .orderBy().asc("lastName") - .asDto(ContactDto.class) - .setLabel("explicitId") + .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class).setLabel("explicitId") .setRelaxedMode(); List dtos = query.findList(); @@ -98,7 +91,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } @Test @@ -108,12 +102,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - DtoQuery query = - Ebean.find(Contact.class) - .select("email, concat(lastName,', ',firstName) as fullName") - .where().isNotNull("email").isNotNull("lastName") - .orderBy().asc("lastName") - .asDto(ContactDto.class); + DtoQuery query = Ebean.find(Contact.class) + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").asDto(ContactDto.class); List dtos = query.findList(); @@ -126,10 +117,10 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } - @Test public void example() { @@ -137,15 +128,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - List contactDtos - = Ebean.find(Contact.class) - .setLabel("emailFullName") - .select("email, concat(lastName,', ',firstName) as fullName") - .where().isNotNull("email").isNotNull("lastName") - .orderBy().asc("lastName") - .setMaxRows(10) - .asDto(ContactDto.class) - .findList(); + List contactDtos = Ebean.find(Contact.class).setLabel("emailFullName") + .select("email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); assertThat(contactDtos).isNotEmpty(); @@ -158,10 +143,12 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List sql = LoggedSqlCollector.stop(); if (isSqlServer()) { - assertThat(sql.get(0)).contains("select top 10 t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select top 10 t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } else { - assertThat(sql.get(0)).contains("select t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } } @@ -172,14 +159,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - List contactDtos - = Ebean.find(Contact.class) - .select("id, email, concat(lastName,', ',firstName) as fullName") - .where().isNotNull("email").isNotNull("lastName") - .orderBy().asc("lastName") - .setMaxRows(10) - .asDto(ContactDto.class) - .findList(); + List contactDtos = Ebean.find(Contact.class) + .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("email") + .isNotNull("lastName").orderBy().asc("lastName").setMaxRows(10).asDto(ContactDto.class).findList(); assertThat(contactDtos).isNotEmpty(); @@ -192,9 +174,12 @@ public class DtoQueryFromOrmTest extends BaseTestCase { List sql = LoggedSqlCollector.stop(); if (isSqlServer()) { - assertThat(sql.get(0)).contains("select top 10 t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select top 10 t0.id, t0.email, " + + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } else { - assertThat(sql.get(0)).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); + assertThat(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + + " fullName from contact t0 where t0.email is not null and t0.last_name is not null order by t0.last_name"); } } @@ -205,15 +190,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - List contactDtos - = Ebean.find(Contact.class) - .select("concat(lastName,', ',firstName) as fullName") - .where().isNotNull("lastName") - .orderBy().asc("lastName") - .asDto(ContactDto.class) - .setFirstRow(2) - .setMaxRows(5) - .findList(); + List contactDtos = Ebean.find(Contact.class) + .select(concat("lastName", ", ", "firstName") + " as fullName").where().isNotNull("lastName").orderBy() + .asc("lastName").asDto(ContactDto.class).setFirstRow(2).setMaxRows(5).findList(); assertThat(contactDtos).isNotEmpty(); @@ -225,10 +204,10 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select concat(t0.last_name,', ',t0.first_name) fullName from contact t0 where"); + assertThat(sql.get(0)) + .contains("select " + concat("t0.last_name", ", ", "t0.first_name") + " fullName from contact t0 where"); } - @Test public void example_aggregate() { @@ -236,14 +215,9 @@ public class DtoQueryFromOrmTest extends BaseTestCase { LoggedSqlCollector.start(); - List contactDtos - = Ebean.find(Contact.class) - .select("lastName, count(*) as totalCount") - .where().isNotNull("lastName") - .having().gt("count(*)", 1) - .orderBy().desc("count(*)") - .asDto(ContactTotals.class) - .findList(); + List contactDtos = Ebean.find(Contact.class).select("lastName, count(*) as totalCount").where() + .isNotNull("lastName").having().gt("count(*)", 1).orderBy().desc("count(*)").asDto(ContactTotals.class) + .findList(); assertThat(contactDtos).isNotEmpty(); @@ -253,7 +227,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(sql.get(0)).contains("select t0.last_name, count(*) totalCount from contact t0 where t0.last_name is not null group by t0.last_name having count(*) > ?"); + assertThat(sql.get(0)).contains( + "select t0.last_name, count(*) totalCount from contact t0 where t0.last_name is not null group by t0.last_name having count(*) > ?"); } @Test @@ -261,12 +236,8 @@ public class DtoQueryFromOrmTest extends BaseTestCase { ResetBasicData.reset(); - List contactDtos - = Ebean.find(Contact.class) - .select("lastName, count(*) as totalCount") - .where().isNotNull("lastName") - .asDto(ContactTotals.class) - .findList(); + List contactDtos = Ebean.find(Contact.class).select("lastName, count(*) as totalCount").where() + .isNotNull("lastName").asDto(ContactTotals.class).findList(); assertThat(contactDtos).isNotEmpty(); } diff --git a/src/test/java/io/ebean/SqlRowBooleanTest.java b/src/test/java/io/ebean/SqlRowBooleanTest.java index 3496b02cd..e5aa7d148 100644 --- a/src/test/java/io/ebean/SqlRowBooleanTest.java +++ b/src/test/java/io/ebean/SqlRowBooleanTest.java @@ -16,6 +16,8 @@ public class SqlRowBooleanTest extends BaseTestCase { sqlQuery = Ebean.createSqlQuery("SELECT 1 AS ISNT_NULL from dual"); } else if (isDb2()) { sqlQuery = Ebean.createSqlQuery("SELECT 1 AS ISNT_NULL from SYSIBM.SYSDUMMY1"); + } else if (isHana()) { + sqlQuery = Ebean.createSqlQuery("SELECT 1 AS ISNT_NULL from sys.dummy"); } else { sqlQuery = Ebean.createSqlQuery("SELECT 1 IS NOT NULL AS ISNT_NULL"); } diff --git a/src/test/java/io/ebean/config/dbplatform/HanaHistorySupportTest.java b/src/test/java/io/ebean/config/dbplatform/HanaHistorySupportTest.java new file mode 100644 index 000000000..c40ceaf41 --- /dev/null +++ b/src/test/java/io/ebean/config/dbplatform/HanaHistorySupportTest.java @@ -0,0 +1,48 @@ +package io.ebean.config.dbplatform; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +import io.ebean.config.dbplatform.hana.HanaHistorySupport; + +public class HanaHistorySupportTest { + + private HanaHistorySupport support = new HanaHistorySupport(); + + @Test + public void getAsOfPredicate() { + + String asOfPredicate = support.getAsOfPredicate("t0", "sys_period"); + assertNull(asOfPredicate); + } + + @Test + public void getAsOfViewSuffix() { + + String asOfViewSuffix = support.getAsOfViewSuffix("_with_history"); + assertEquals(asOfViewSuffix, " for system_time as of ?"); + } + + @Test + public void getVersionsBetweenSuffix() { + + String asOfViewSuffix = support.getVersionsBetweenSuffix("_with_history"); + assertEquals(asOfViewSuffix, " for system_time between ? and ?"); + } + + @Test + public void getLower() throws Exception { + + String lower = support.getSysPeriodLower("t0", "sys_period"); + assertEquals(lower, "t0.sys_period_start"); + } + + @Test + public void getUpper() throws Exception { + + String upper = support.getSysPeriodUpper("t0", "sys_period"); + assertEquals(upper, "t0.sys_period_end"); + } +} diff --git a/src/test/java/io/ebean/config/dbplatform/HanaPlatformTest.java b/src/test/java/io/ebean/config/dbplatform/HanaPlatformTest.java new file mode 100644 index 000000000..948513a05 --- /dev/null +++ b/src/test/java/io/ebean/config/dbplatform/HanaPlatformTest.java @@ -0,0 +1,67 @@ +package io.ebean.config.dbplatform; + +import io.ebean.config.PlatformConfig; +import io.ebean.config.dbplatform.hana.HanaPlatform; +import io.ebeaninternal.dbmigration.ddlgeneration.platform.PlatformDdl; +import io.ebeaninternal.server.core.PlatformDdlBuilder; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HanaPlatformTest { + + HanaPlatform platform = new HanaPlatform(); + + @Test + public void testTypeConversion() { + + PlatformDdl ddl = PlatformDdlBuilder.create(platform); + + assertThat(ddl.convert("clob", false)).isEqualTo("nclob"); + assertThat(ddl.convert("blob", false)).isEqualTo("blob"); + assertThat(ddl.convert("json", false)).isEqualTo("nclob"); + assertThat(ddl.convert("jsonb", false)).isEqualTo("nclob"); + assertThat(ddl.convert("jsonvarchar", false)).isEqualTo("nvarchar(255)"); + + assertThat(ddl.convert("double", false)).isEqualTo("double"); + assertThat(ddl.convert("varchar(20)", false)).isEqualTo("nvarchar(20)"); + assertThat(ddl.convert("decimal(10)", false)).isEqualTo("decimal(10)"); + assertThat(ddl.convert("decimal(8,4)", false)).isEqualTo("decimal(8,4)"); + assertThat(ddl.convert("boolean", false)).isEqualTo("boolean"); + assertThat(ddl.convert("bit", false)).isEqualTo("smallint"); + assertThat(ddl.convert("tinyint", false)).isEqualTo("smallint"); + assertThat(ddl.convert("binary", false)).isEqualTo("varbinary(255)"); + assertThat(ddl.convert("binary(16)", false)).isEqualTo("varbinary(16)"); + + assertThat(ddl.convert("point", false)).isEqualTo("st_point"); + + assertThat(ddl.convert("multilinestring", false)).isEqualTo("st_geometry"); + assertThat(ddl.convert("multipolygon", false)).isEqualTo("st_geometry"); + assertThat(ddl.convert("multipoint", false)).isEqualTo("st_geometry"); + assertThat(ddl.convert("linestring", false)).isEqualTo("st_geometry"); + assertThat(ddl.convert("polygon", false)).isEqualTo("st_geometry"); + } + + @Test + public void uuid_default() { + + HanaPlatform platform = new HanaPlatform(); + platform.configure(new PlatformConfig()); + DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); + + assertThat(dbType.renderType(0, 0)).isEqualTo("varchar(40)"); + } + + @Test + public void uuid_as_binary() { + + HanaPlatform platform = new HanaPlatform(); + PlatformConfig config = new PlatformConfig(); + config.setDbUuid(PlatformConfig.DbUuid.AUTO_BINARY); + + platform.configure(config); + + DbPlatformType dbType = platform.getDbTypeMap().get(DbPlatformType.UUID); + assertThat(dbType.renderType(0, 0)).isEqualTo("varbinary(16)"); + } +} diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java index 635a9b9ac..27fda6d25 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationGenerateTest.java @@ -53,12 +53,14 @@ public class DbMigrationGenerateTest { migration.addPlatform(Platform.ORACLE, "oracle"); migration.addPlatform(Platform.SQLITE, "sqlite"); migration.addPlatform(Platform.SQLSERVER17, "sqlserver17"); + migration.addPlatform(Platform.HANA, "hana"); ServerConfig config = new ServerConfig(); config.setName("migrationtest"); config.loadFromProperties(); config.setRegister(false); config.setDefaultServer(false); + config.getProperties().put("ebean.hana.generateUniqueDdl", "true"); // need to generate unique statements to prevent them from being filtered out as duplicates by the DdlRunner config.setPackages(Arrays.asList("misc.migration.v1_0")); diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java index 218b2ced8..00b99161f 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java @@ -7,7 +7,6 @@ import io.ebean.SqlUpdate; import io.ebean.Transaction; import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.Platform; -import io.ebean.migration.MigrationConfig; import io.ebean.migration.ddl.DdlRunner; import io.ebeaninternal.dbmigration.ddlgeneration.Helper; @@ -90,7 +89,7 @@ public class DbMigrationTest extends BaseTestCase { runScript(false, "1.0__initial.sql"); - if (isOracle()) { + if (isOracle() || isHana()) { SqlUpdate update = server().createSqlUpdate("insert into migtest_e_basic (id, old_boolean, user_id) values (1, :false, 1)"); update.setParameter("false", false); assertThat(server().execute(update)).isEqualTo(1); @@ -199,6 +198,7 @@ public class DbMigrationTest extends BaseTestCase { for (String table : tables) { // simple and stupid try to execute all commands on all dialects. sb.append("alter table ").append(table).append(" set ( system_versioning = OFF );\n"); + sb.append("alter table ").append(table).append(" drop system versioning;\n"); sb.append("drop table ").append(table).append(";\n"); sb.append("drop table ").append(table).append(" cascade;\n"); sb.append("drop table ").append(table).append("_history;\n"); diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java index e185e8df7..bfb7b0b64 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/BaseDdlHandlerTest.java @@ -5,6 +5,7 @@ import io.ebean.Ebean; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.api.SpiEbeanServer; @@ -16,7 +17,6 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; - public class BaseDdlHandlerTest extends BaseTestCase { private ServerConfig serverConfig = new ServerConfig(); @@ -37,6 +37,10 @@ public class BaseDdlHandlerTest extends BaseTestCase { return handler(new SqlServer17Platform()); } + private DdlHandler hanaHandler() { + return handler(new HanaPlatform()); + } + @Test public void addColumn_nullable_noConstraint() throws Exception { @@ -47,6 +51,10 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAddColumn()); assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add added_to_foo nvarchar(20);\n\n"); + + write = new DdlWrite(); + hanaHandler().generate(write, Helper.getAddColumn()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( added_to_foo nvarchar(20));\n\n"); } @Test @@ -56,10 +64,16 @@ public class BaseDdlHandlerTest extends BaseTestCase { h2Handler().generate(write, Helper.getAlterTableAddColumnWithCheckConstraint()); assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column status integer;\n" + "alter table foo add constraint ck_ordering_status check ( status in (0,1));\n\n"); + + write = new DdlWrite(); + hanaHandler().generate(write, Helper.getAlterTableAddColumnWithCheckConstraint()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( status integer);\n" + + "alter table foo add constraint ck_ordering_status check ( status in (0,1));\n\n"); } /** - * Test the functionality of the Ebean {@literal @}DbArray extension during DDL generation. + * Test the functionality of the Ebean {@literal @}DbArray extension during DDL + * generation. */ @Test public void addColumn_dbarray() throws Exception { @@ -76,6 +90,12 @@ public class BaseDdlHandlerTest extends BaseTestCase { DdlHandler sqlserverHandler = sqlserverHandler(); sqlserverHandler.generate(write, Helper.getAlterTableAddDbArrayColumn()); assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add dbarray_added_to_foo varchar(1000);\n\n"); + + write = new DdlWrite(); + + DdlHandler hanaHandler = hanaHandler(); + hanaHandler.generate(write, Helper.getAlterTableAddDbArrayColumn()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_added_to_foo nvarchar(255) array);\n\n"); } @Test @@ -93,6 +113,10 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAlterTableAddDbArrayColumnWithLength()); assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add dbarray_ninety varchar(90);\n\n"); + + write = new DdlWrite(); + hanaHandler().generate(write, Helper.getAlterTableAddDbArrayColumnWithLength()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_ninety nvarchar(255) array(90));\n\n"); } @Test @@ -113,6 +137,14 @@ public class BaseDdlHandlerTest extends BaseTestCase { write = new DdlWrite(); sqlserverHandler().generate(write, Helper.getAlterTableAddDbArrayColumnInteger()); assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add dbarray_integer varchar(1000);\n\n"); + + write = new DdlWrite(); + hanaHandler().generate(write, Helper.getAlterTableAddDbArrayColumnIntegerWithLength()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_integer integer array(90));\n\n"); + + write = new DdlWrite(); + hanaHandler().generate(write, Helper.getAlterTableAddDbArrayColumnInteger()); + assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add ( dbarray_integer integer array);\n\n"); } @Test @@ -127,7 +159,8 @@ public class BaseDdlHandlerTest extends BaseTestCase { assertThat(buffer).contains("alter table foo add column some_id integer;"); String fkBuffer = write.applyForeignKeys().getBuffer(); - assertThat(fkBuffer).contains("alter table foo add constraint fk_foo_some_id foreign key (some_id) references bar (id) on delete restrict on update restrict;"); + assertThat(fkBuffer).contains( + "alter table foo add constraint fk_foo_some_id foreign key (some_id) references bar (id) on delete restrict on update restrict;"); assertThat(fkBuffer).contains("create index idx_foo_some_id on foo (some_id);"); assertThat(write.dropAll().getBuffer()).isEqualTo(""); } @@ -142,8 +175,15 @@ public class BaseDdlHandlerTest extends BaseTestCase { assertThat(write.apply().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n"); assertThat(write.dropAll().getBuffer()).isEqualTo(""); - } + write = new DdlWrite(); + DdlHandler hanaHandler = hanaHandler(); + + hanaHandler.generate(write, Helper.getDropColumn()); + + assertThat(write.apply().getBuffer()).isEqualTo("CALL usp_ebean_drop_column('foo', 'col2');\n\n"); + assertThat(write.dropAll().getBuffer()).isEqualTo(""); + } @Test public void createTable() throws Exception { @@ -157,6 +197,16 @@ public class BaseDdlHandlerTest extends BaseTestCase { assertThat(write.apply().getBuffer()).isEqualTo(createTableDDL); assertThat(write.dropAll().getBuffer().trim()).isEqualTo("drop table if exists foo;"); + + write = new DdlWrite(); + DdlHandler hanaHandler = hanaHandler(); + + hanaHandler.generate(write, Helper.getCreateTable()); + + String createColumnTableDDL = Helper.asText(this, "/assert/create-column-table.txt"); + + assertThat(write.apply().getBuffer()).isEqualTo(createColumnTableDDL); + assertThat(write.dropAll().getBuffer().trim()).isEqualTo("drop table foo cascade;"); } @Test @@ -174,7 +224,6 @@ public class BaseDdlHandlerTest extends BaseTestCase { assertThat(write.dropAll().getBuffer()).isEqualTo(rollbackLast); } - @Ignore @Test public void generateChangeSetFromModel() throws Exception { diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlTest.java new file mode 100644 index 000000000..911a28964 --- /dev/null +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaDdlTest.java @@ -0,0 +1,42 @@ +package io.ebeaninternal.dbmigration.ddlgeneration.platform; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; + +import io.ebean.config.dbplatform.hana.HanaPlatform; +import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; +import io.ebeaninternal.dbmigration.migration.Column; + +public class HanaDdlTest { + + @Test + public void alterTableDropColumn() throws IOException { + HanaColumnStoreDdl ddl = new HanaColumnStoreDdl(new HanaPlatform()); + DdlWrite write = new DdlWrite(); + ddl.alterTableDropColumn(write.apply(), "my_table", "my_column"); + assertEquals("CALL usp_ebean_drop_column('my_table', 'my_column');\n", write.apply().getBuffer()); + } + + @Test + public void alterTableAddColumn() throws IOException { + HanaColumnStoreDdl ddl = new HanaColumnStoreDdl(new HanaPlatform()); + DdlWrite write = new DdlWrite(); + Column column = new Column(); + column.setName("my_column"); + column.setComment("comment"); + column.setDefaultValue("1"); + column.setNotnull(Boolean.TRUE); + column.setType("int"); + column.setUnique("unique"); + column.setPrimaryKey(Boolean.TRUE); + column.setCheckConstraint("CHECK(my_column > 0)"); + column.setCheckConstraintName("check_constraint"); + column.setHistoryExclude(Boolean.TRUE); + column.setIdentity(Boolean.TRUE); + ddl.alterTableAddColumn(write.apply(), "my_table", column, false, "1"); + assertEquals("alter table my_table add ( my_column int default 1 not null);\nalter table my_table add constraint check_constraint CHECK(my_column > 0);\n", write.apply().getBuffer()); + } +} diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java index d19d4cc28..7d5279990 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_AlterColumnTest.java @@ -4,6 +4,7 @@ import io.ebean.Ebean; import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.IdType; import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; @@ -16,6 +17,8 @@ import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; public class PlatformDdl_AlterColumnTest { @@ -24,6 +27,7 @@ public class PlatformDdl_AlterColumnTest { private PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); private PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform()); private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform()); + private PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform()); { ServerConfig serverConfig = Ebean.getDefaultServer().getPluginApi().getServerConfig(); @@ -63,6 +67,14 @@ public class PlatformDdl_AlterColumnTest { assertThat(pgDdl.convertArrayType("varchar[]")).isEqualTo("varchar[]"); assertThat(pgDdl.convertArrayType("integer[]")).isEqualTo("integer[]"); } + + @Test + public void convertArrayType_hana() { + assertThat(hanaDdl.convertArrayType("varchar[](90)")).isEqualTo("nvarchar(255) array(90)"); + assertThat(hanaDdl.convertArrayType("integer[](60)")).isEqualTo("integer array(60)"); + assertThat(hanaDdl.convertArrayType("varchar[]")).isEqualTo("nvarchar(255) array"); + assertThat(hanaDdl.convertArrayType("integer[]")).isEqualTo("integer array"); + } @Test public void testAlterColumnBaseAttributes() throws Exception { @@ -77,20 +89,32 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnBaseAttributes(alterColumn); assertEquals("alter table mytab alter column acol nvarchar(5) not null", sql); + + sql = hanaDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab alter ( acol nvarchar(5) not null)", sql); alterColumn.setNotnull(Boolean.FALSE); sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); assertEquals("alter table mytab modify acol varchar(5)", sql); + + sql = hanaDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab alter ( acol nvarchar(5))", sql); alterColumn.setNotnull(null); alterColumn.setType("varchar(100)"); sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); assertEquals("alter table mytab modify acol varchar(100)", sql); + + sql = hanaDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab alter ( acol nvarchar(100))", sql); alterColumn.setCurrentNotnull(Boolean.TRUE); sql = mysqlDdl.alterColumnBaseAttributes(alterColumn); assertEquals("alter table mytab modify acol varchar(100) not null", sql); + + sql = hanaDdl.alterColumnBaseAttributes(alterColumn); + assertEquals("alter table mytab alter ( acol nvarchar(100) not null)", sql); } @Test @@ -110,6 +134,9 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnType("mytab", "acol", "varchar(20)"); assertNull(sql); + + sql = hanaDdl.alterColumnType("mytab", "acol", "varchar(20)"); + assertNull(sql); } @Test @@ -129,6 +156,9 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnNotnull("mytab", "acol", true); assertNull(sql); + + sql = hanaDdl.alterColumnNotnull("mytab", "acol", true); + assertNull(sql); } @Test @@ -148,6 +178,9 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnNotnull("mytab", "acol", false); assertNull(sql); + + sql = hanaDdl.alterColumnNotnull("mytab", "acol", false); + assertNull(sql); } @Test @@ -167,6 +200,15 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnDefaultValue("mytab", "acol", "'hi'"); assertEquals("alter table mytab add default 'hi' for acol", sql); + + boolean exceptionCaught = false; + try { + hanaDdl.alterColumnDefaultValue("mytab", "acol", "'hi'"); + } + catch (UnsupportedOperationException e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); } @Test @@ -186,6 +228,15 @@ public class PlatformDdl_AlterColumnTest { sql = sqlServerDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); assertEquals("EXEC usp_ebean_drop_default_constraint mytab, acol", sql); + + boolean exceptionCaught = false; + try { + hanaDdl.alterColumnDefaultValue("mytab", "acol", "DROP DEFAULT"); + } + catch (UnsupportedOperationException e) { + exceptionCaught = true; + } + assertTrue(exceptionCaught); } @Test @@ -226,4 +277,14 @@ public class PlatformDdl_AlterColumnTest { assertEquals(oraDdl.useIdentityType(IdentityType.GENERATOR), IdType.GENERATOR); assertEquals(oraDdl.useIdentityType(IdentityType.EXTERNAL), IdType.EXTERNAL); } + + @Test + public void useIdentityType_hana() { + + assertEquals(hanaDdl.useIdentityType(null), IdType.IDENTITY); + assertEquals(hanaDdl.useIdentityType(IdentityType.SEQUENCE), IdType.IDENTITY); + assertEquals(hanaDdl.useIdentityType(IdentityType.IDENTITY), IdType.IDENTITY); + assertEquals(hanaDdl.useIdentityType(IdentityType.GENERATOR), IdType.GENERATOR); + assertEquals(hanaDdl.useIdentityType(IdentityType.EXTERNAL), IdType.EXTERNAL); + } } diff --git a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java index e68ece07c..50bd331b6 100644 --- a/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java +++ b/src/test/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/PlatformDdl_dropUniqueConstraintTest.java @@ -1,6 +1,8 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; +import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.h2.H2Platform; +import io.ebean.config.dbplatform.hana.HanaPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; @@ -12,12 +14,12 @@ import static org.junit.Assert.assertEquals; public class PlatformDdl_dropUniqueConstraintTest { - private PlatformDdl h2Ddl = PlatformDdlBuilder.create(new H2Platform()); private PlatformDdl pgDdl = PlatformDdlBuilder.create(new PostgresPlatform()); private PlatformDdl mysqlDdl = PlatformDdlBuilder.create(new MySqlPlatform()); private PlatformDdl oraDdl = PlatformDdlBuilder.create(new OraclePlatform()); private PlatformDdl sqlServerDdl = PlatformDdlBuilder.create(new SqlServer17Platform()); + private PlatformDdl hanaDdl = PlatformDdlBuilder.create(new HanaPlatform()); @Test public void test() throws Exception { @@ -30,11 +32,22 @@ public class PlatformDdl_dropUniqueConstraintTest { assertEquals("alter table mytab drop constraint uq_name", sql); sql = sqlServerDdl.alterTableDropUniqueConstraint("mytab", "uq_name"); assertEquals("IF (OBJECT_ID('uq_name', 'UQ') IS NOT NULL) alter table mytab drop constraint uq_name;\n" - + "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mytab','U') AND name = 'uq_name') drop index uq_name ON mytab", sql); - + + "IF EXISTS (SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('mytab','U') AND name = 'uq_name') drop index uq_name ON mytab", + sql); sql = mysqlDdl.alterTableDropUniqueConstraint("mytab", "uq_name"); assertEquals("alter table mytab drop index uq_name", sql); + + ServerConfig serverConfig = new ServerConfig(); + hanaDdl.configure(serverConfig); + sql = hanaDdl.alterTableDropUniqueConstraint("mytab", "uq_name"); + assertEquals("delimiter $$\n" + + "do\n" + + "begin\n" + + "declare exit handler for sql_error_code 397 begin end;\n" + + "exec 'alter table mytab drop constraint uq_name';\n" + + "end;\n" + + "$$", sql); } } diff --git a/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java b/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java new file mode 100644 index 000000000..c67fe6de5 --- /dev/null +++ b/src/test/java/io/ebeaninternal/server/expression/platform/HanaDbExpressionTest.java @@ -0,0 +1,70 @@ +package io.ebeaninternal.server.expression.platform; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import io.ebeaninternal.api.SpiExpressionRequest; +import io.ebeaninternal.server.expression.DefaultExpressionRequest; +import io.ebeaninternal.server.expression.Op; + +public class HanaDbExpressionTest { + private HanaDbExpression expression = new HanaDbExpression(); + + @Test + public void testArrayContains() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.arrayContains(request, "arrayproperty", true, "v1", "v2", "v3"); + assertEquals("(? member of arrayproperty) and (? member of arrayproperty) and (? member of arrayproperty)", + request.getSql()); + } + + @Test + public void testArrayNotContains() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.arrayContains(request, "arrayproperty", false, "v1", "v2", "v3"); + assertEquals( + "(? not member of arrayproperty) and (? not member of arrayproperty) and (? not member of arrayproperty)", + request.getSql()); + } + + @Test + public void testArrayContainsEmpty() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.arrayContains(request, "arrayproperty", true); + assertEquals("", request.getSql()); + } + + @Test + public void testArrayIsEmpty() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.arrayIsEmpty(request, "arrayproperty", true); + assertEquals("cardinality(arrayproperty) = 0", request.getSql()); + } + + @Test + public void testArrayIsNotEmpty() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.arrayIsEmpty(request, "arrayproperty", false); + assertEquals("cardinality(arrayproperty) <> 0", request.getSql()); + } + + @Test + public void testConcat() { + String concat = expression.concat("property0", "separator", "property1", "suffix"); + assertEquals("concat(property0, 'separator'||property1||'suffix')", concat); + } + + @Test + public void testConcatNullSuffix() { + String concat = expression.concat("property0", "separator", "property1", null); + assertEquals("concat(property0, 'separator'||property1)", concat); + } + + @Test + public void testJson() { + SpiExpressionRequest request = new DefaultExpressionRequest(null); + expression.json(request, "jsonproperty", "path", Op.EQ, "val"); + assertEquals("json_value(jsonproperty, '$.path') = ? ", request.getSql()); + } +} diff --git a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java index 0f09a79a1..ccf3aab1f 100644 --- a/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java +++ b/src/test/java/io/ebeaninternal/server/grammer/EqlParserTest.java @@ -3,6 +3,9 @@ package io.ebeaninternal.server.grammer; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; import io.ebeaninternal.api.SpiQuery; import org.junit.Test; import org.tests.model.basic.Customer; @@ -11,6 +14,8 @@ import org.tests.model.basic.ResetBasicData; import java.util.Arrays; import java.util.List; +import javax.xml.ws.RequestWrapper; + import static org.assertj.core.api.Assertions.assertThat; public class EqlParserTest extends BaseTestCase { @@ -127,6 +132,7 @@ public class EqlParserTest extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' public void where_or1() { Query query = parse("where name = 'Rob' or (status = 'NEW' and smallnote is null)"); @@ -134,8 +140,19 @@ public class EqlParserTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("where (t0.name = ? or (t0.status = ? and t0.smallnote is null ) )"); } + + @Test + @ForPlatform(Platform.HANA) + public void where_or1_hana() { + + Query query = parse("where name = 'Rob' or (status = 'N' and smallnote is null)"); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("where (t0.name = ? or (t0.status = ? and t0.smallnote is null ) )"); + } @Test + @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' public void where_or2() { Query query = parse("where (name = 'Rob' or status = 'NEW') and smallnote is null"); @@ -143,8 +160,19 @@ public class EqlParserTest extends BaseTestCase { assertThat(query.getGeneratedSql()).contains("where ((t0.name = ? or t0.status = ? ) and t0.smallnote is null )"); } + + @Test + @ForPlatform(Platform.HANA) + public void where_or2_hana() { + + Query query = parse("where (name = 'Rob' or status = 'N') and smallnote is null"); + query.findList(); + + assertThat(query.getGeneratedSql()).contains("where ((t0.name = ? or t0.status = ? ) and t0.smallnote is null )"); + } @Test + @IgnorePlatform(Platform.HANA) // The HANA JDBC driver checks the field length on binding and rejects 'NEW' public void test_simplifyExpressions() { Query query = parse("where not (name = 'Rob' and status = 'NEW')"); @@ -159,6 +187,23 @@ public class EqlParserTest extends BaseTestCase { query.findList(); assertThat(query.getGeneratedSql()).contains("where not (t0.name = ? and t0.status = ? )"); } + + @Test + @ForPlatform(Platform.HANA) + public void test_simplifyExpressions_hana() { + + Query query = parse("where not (name = 'Rob' and status = 'N')"); + query.findList(); + assertThat(query.getGeneratedSql()).contains("where not (t0.name = ? and t0.status = ? )"); + + query = parse("where not ((name = 'Rob' and status = 'N'))"); + query.findList(); + assertThat(query.getGeneratedSql()).contains("where not (t0.name = ? and t0.status = ? )"); + + query = parse("where not (((name = 'Rob') and (status = 'N')))"); + query.findList(); + assertThat(query.getGeneratedSql()).contains("where not (t0.name = ? and t0.status = ? )"); + } @Test diff --git a/src/test/java/org/tests/basic/TestErrorBindLog.java b/src/test/java/org/tests/basic/TestErrorBindLog.java index 0b90f485a..75b1bd7c5 100644 --- a/src/test/java/org/tests/basic/TestErrorBindLog.java +++ b/src/test/java/org/tests/basic/TestErrorBindLog.java @@ -18,7 +18,12 @@ public class TestErrorBindLog extends BaseTestCase { } catch (PersistenceException e) { String msg = e.getMessage(); - Assert.assertTrue(msg.contains("Bind values:")); + if (isHana()) { + Assert.assertTrue(msg.contains("Error with property[1] dt[12]data[JUNK]")); + } + else { + Assert.assertTrue(msg.contains("Bind values:")); + } } } } diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java index 8bc76c951..c818a3287 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertFlush.java @@ -4,7 +4,9 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; import io.ebean.meta.BasicMetricVisitor; import io.ebean.meta.MetaTimedMetric; @@ -119,6 +121,7 @@ public class TestBatchInsertFlush extends BaseTestCase { @Test @Transactional(batch = PersistBatch.ALL) + @IgnorePlatform(Platform.HANA) public void transactional_flushOnGetId() { EbeanServer server = Ebean.getDefaultServer(); @@ -141,6 +144,7 @@ public class TestBatchInsertFlush extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void testFlushOnGetId() { EbeanServer server = Ebean.getDefaultServer(); diff --git a/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java b/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java index 8245f31ea..497b9d137 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java +++ b/src/test/java/org/tests/batchinsert/TestBatchInsertSimple.java @@ -3,7 +3,9 @@ package org.tests.batchinsert; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; import org.junit.Test; import org.tests.model.basic.UTDetail; @@ -46,6 +48,7 @@ public class TestBatchInsertSimple extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void testTransactional() { saveWithFullBatchMode(); @@ -131,7 +134,7 @@ public class TestBatchInsertSimple extends BaseTestCase { Transaction transaction = Ebean.beginTransaction(); try { transaction.setBatch(PersistBatch.NONE); - transaction.setBatchOnCascade(PersistBatch.ALL); + transaction.setBatchOnCascade(spiEbeanServer().getDatabasePlatform().getPersistBatchOnCascade()); transaction.setBatchSize(20); // escalate based on batchOnCascade value diff --git a/src/test/java/org/tests/batchinsert/TestBatchOnCascadeExceptionHandling.java b/src/test/java/org/tests/batchinsert/TestBatchOnCascadeExceptionHandling.java index 568dd0e8b..d28dcc974 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchOnCascadeExceptionHandling.java +++ b/src/test/java/org/tests/batchinsert/TestBatchOnCascadeExceptionHandling.java @@ -3,7 +3,9 @@ package org.tests.batchinsert; import io.ebean.BaseTestCase; import io.ebean.EbeanServer; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; import io.ebeaninternal.api.SpiTransaction; import io.ebeaninternal.server.persist.BatchControl; import org.tests.model.basic.EBasicWithUniqueCon; @@ -20,6 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestBatchOnCascadeExceptionHandling extends BaseTestCase { + @IgnorePlatform(Platform.HANA) @Test public void testBatchScenarioWithSavepoint() throws SQLException { server().save(createEntityWithName("conflict", "before")); @@ -84,7 +87,7 @@ public class TestBatchOnCascadeExceptionHandling extends BaseTestCase { Transaction txn = server.beginTransaction(); try { assertThat(txn.getBatch()).isSameAs(PersistBatch.NONE); - assertThat(txn.getBatchOnCascade()).isSameAs(PersistBatch.ALL); + assertThat(txn.getBatchOnCascade()).isSameAs(spiEbeanServer().getDatabasePlatform().getPersistBatchOnCascade()); failingOperation.run(); Assertions.fail("PersistenceException expected"); diff --git a/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java b/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java index 2fab37ff9..3b3230581 100644 --- a/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java +++ b/src/test/java/org/tests/batchinsert/TestBatchSaveWithGetBeanId.java @@ -3,6 +3,8 @@ package org.tests.batchinsert; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; import io.ebean.annotation.Transactional; import org.tests.model.basic.Customer; import org.junit.Test; @@ -18,6 +20,7 @@ public class TestBatchSaveWithGetBeanId extends BaseTestCase { */ @Transactional(batchSize = 10) @Test + @IgnorePlatform(Platform.HANA) // HANA doesn't support insert batching public void test() { EbeanServer server = Ebean.getDefaultServer(); diff --git a/src/test/java/org/tests/compositekeys/db/Type.java b/src/test/java/org/tests/compositekeys/db/Type.java index 0b5784b8a..298d6bc4b 100644 --- a/src/test/java/org/tests/compositekeys/db/Type.java +++ b/src/test/java/org/tests/compositekeys/db/Type.java @@ -6,10 +6,12 @@ import javax.persistence.JoinColumn; import javax.persistence.JoinColumns; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.Table; import javax.persistence.Version; import java.util.List; @Entity +@Table(name="`type`") // needs to be quoted because it's a keyword on HANA public class Type { @Id private TypeKey key; diff --git a/src/test/java/org/tests/merge/TestMergeBasic.java b/src/test/java/org/tests/merge/TestMergeBasic.java index 03938fa71..d02861c5e 100644 --- a/src/test/java/org/tests/merge/TestMergeBasic.java +++ b/src/test/java/org/tests/merge/TestMergeBasic.java @@ -59,12 +59,23 @@ public class TestMergeBasic extends BaseTestCase { assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?"); // persist children ... - assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); - assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); - assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); - assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); - assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + } + else { + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + + assertThat(sql.get(4)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + + assertThat(sql.get(7)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + } } @Test @@ -97,12 +108,23 @@ public class TestMergeBasic extends BaseTestCase { assertThat(sql.get(2)).contains("update uuone set name=?, description=?, version=? where id=? and version=?"); // persist children ... - assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); - assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + assertThat(sql.get(4)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + } + else { + assertThat(sql.get(3)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); - assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); - assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); - assertThat(sql.get(7)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(4)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(5)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + assertThat(sql.get(6)).contains("update uutwo set name=?, notes=?, version=?, master_id=? where id=? and version=?"); + + assertThat(sql.get(7)).contains("insert into uutwo (id, name, notes, version, master_id) values (?,?,?,?,?);"); + } } diff --git a/src/test/java/org/tests/merge/TestMergeCustomer.java b/src/test/java/org/tests/merge/TestMergeCustomer.java index c796d702b..6068d034d 100644 --- a/src/test/java/org/tests/merge/TestMergeCustomer.java +++ b/src/test/java/org/tests/merge/TestMergeCustomer.java @@ -277,10 +277,18 @@ public class TestMergeCustomer extends BaseTestCase { assertThat(sql.get(2)).contains("delete from mcontact where id=?"); assertThat(sql.get(5)).contains("update mcustomer set name=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); - assertThat(sql.get(6)).contains("insert into mcontact"); - assertThat(sql.get(7)).contains("insert into mcontact"); - assertThat(sql.get(8)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); - assertThat(sql.get(11)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(6)).contains("insert into mcontact"); + assertThat(sql.get(7)).contains("insert into mcontact"); + assertThat(sql.get(8)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + assertThat(sql.get(11)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + } + else { + assertThat(sql.get(6)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + assertThat(sql.get(7)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + assertThat(sql.get(10)).contains("insert into mcontact"); + assertThat(sql.get(11)).contains("insert into mcontact"); + } } @Test @@ -305,7 +313,7 @@ public class TestMergeCustomer extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql.get(0)).contains("select t0.id, t3.id, t1.id, t2.id from mcustomer t0 left join maddress t3 on t3.id = t0.shipping_address_id left join maddress t1 on t1.id = t0.billing_address_id left join mcontact t2 on t2.customer_id = t0.id where t0.id = ?"); - if (isH2()) { + if (isH2() || isHana()) { // with nested OneToMany .. we need a second query to read the contact message ids assertThat(sql.get(1)).contains("select t0.contact_id, t0.id from mcontact_message t0 where (t0.contact_id) in (?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"); } @@ -317,10 +325,18 @@ public class TestMergeCustomer extends BaseTestCase { assertThat(sql.get(6)).contains("update maddress set street=?, city=?, version=? where id=? and version=?"); assertThat(sql.get(7)).contains("update mcustomer set name=?, notes=?, version=?, shipping_address_id=?, billing_address_id=? where id=? and version=?"); - assertThat(sql.get(8)).contains("insert into mcontact"); - assertThat(sql.get(9)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); - - assertThat(sql.get(13)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(8)).contains("insert into mcontact"); + assertThat(sql.get(9)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + + assertThat(sql.get(13)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?"); + } + else { + assertThat(sql.get(8)).contains("update mcontact set email=?, first_name=?, last_name=?, version=?, customer_id=? where id=? and version=?"); + assertThat(sql.get(9)).contains("update mcontact_message set title=?, subject=?, notes=?, version=?, contact_id=? where id=? and version=?"); + + assertThat(sql.get(sql.size()-1)).contains("insert into mcontact"); + } } diff --git a/src/test/java/org/tests/merge/TestMergeM2M.java b/src/test/java/org/tests/merge/TestMergeM2M.java index 930d2def1..784e53025 100644 --- a/src/test/java/org/tests/merge/TestMergeM2M.java +++ b/src/test/java/org/tests/merge/TestMergeM2M.java @@ -40,10 +40,20 @@ public class TestMergeM2M extends BaseTestCase { Ebean.merge(machine, options); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("select"); - assertThat(sql.get(1)).contains("insert into mmachine"); - assertThat(sql.get(2)).contains("insert into mmachine_mgroup"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("select"); + assertThat(sql.get(1)).contains("insert into mmachine"); + assertThat(sql.get(2)).contains("insert into mmachine_mgroup"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("select"); + assertThat(sql.get(1)).contains("insert into mmachine"); + assertThat(sql.get(2)).contains("insert into mmachine_mgroup"); + assertThat(sql.get(3)).contains("insert into mmachine_mgroup"); + assertThat(sql.get(4)).contains("insert into mmachine_mgroup"); + } machine.setName("mac1-mod"); machine.getGroups().remove(group2); diff --git a/src/test/java/org/tests/model/array/TestDbArray_asSet.java b/src/test/java/org/tests/model/array/TestDbArray_asSet.java index ac970b2e4..b87726c53 100644 --- a/src/test/java/org/tests/model/array/TestDbArray_asSet.java +++ b/src/test/java/org/tests/model/array/TestDbArray_asSet.java @@ -3,6 +3,9 @@ package org.tests.model.array; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -22,6 +25,7 @@ public class TestDbArray_asSet extends BaseTestCase { private EArraySetBean found; @Test + @IgnorePlatform(Platform.HANA) public void insert() { bean.setName("some stuff"); @@ -122,6 +126,7 @@ public class TestDbArray_asSet extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void insertNulls() { EArraySetBean bean = new EArraySetBean(); @@ -135,6 +140,7 @@ public class TestDbArray_asSet extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void insertAll_when_hasNulls() { EArraySetBean bean = new EArraySetBean(); diff --git a/src/test/java/org/tests/model/array/TestDbArray_basic.java b/src/test/java/org/tests/model/array/TestDbArray_basic.java index 6a3e938c5..4da3ada4a 100644 --- a/src/test/java/org/tests/model/array/TestDbArray_basic.java +++ b/src/test/java/org/tests/model/array/TestDbArray_basic.java @@ -17,6 +17,8 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Query; import io.ebean.SqlRow; +import io.ebean.annotation.IgnorePlatform; +import io.ebean.annotation.Platform; public class TestDbArray_basic extends BaseTestCase { @@ -25,6 +27,7 @@ public class TestDbArray_basic extends BaseTestCase { private EArrayBean found; @Test + @IgnorePlatform(Platform.HANA) public void insert() throws SQLException { bean.setName("some stuff"); @@ -159,6 +162,7 @@ public class TestDbArray_basic extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void insertNulls() { EArrayBean bean = new EArrayBean(); @@ -172,6 +176,7 @@ public class TestDbArray_basic extends BaseTestCase { } @Test + @IgnorePlatform(Platform.HANA) public void insertAll_when_hasNulls() { EArrayBean bean = new EArrayBean(); diff --git a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java index 9a42ea601..34a484ce9 100644 --- a/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java +++ b/src/test/java/org/tests/model/basic/cache/TestCacheViaComplexNaturalKey3.java @@ -280,6 +280,8 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code) in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2-1000,3-1000})"); } else if (isPostgres()) { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||'-'||t0.code)"); + } else if (isHana()) { + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, '-'||t0.code)"); } else { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,'-',t0.code)"); } @@ -319,6 +321,8 @@ public class TestCacheViaComplexNaturalKey3 extends BaseTestCase { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo') in (?, ? ) order by t0.sku desc; --bind(def,Array[2]={2:1000-foo,3:1000-foo})"); } else if (isPostgres()){ assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and (t0.sku||':'||t0.code||'-foo')"); + } else if (isHana()){ + assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku, ':'||t0.code||'-foo')"); } else { assertThat(sql.get(0)).contains("from o_cached_natkey3 t0 where t0.store = ? and concat(t0.sku,':',t0.code,'-foo')"); } diff --git a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenFlushThenUpdate.java b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenFlushThenUpdate.java index 59b29a499..b10abc2df 100644 --- a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenFlushThenUpdate.java +++ b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenFlushThenUpdate.java @@ -3,7 +3,10 @@ package org.tests.model.basic.xtra; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -16,6 +19,7 @@ import static org.junit.Assert.assertTrue; public class TestInsertBatchThenFlushThenUpdate extends BaseTestCase { @Test + @IgnorePlatform(Platform.HANA) public void test() { LoggedSqlCollector.start(); diff --git a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenUpdate.java b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenUpdate.java index 08d86c0de..cc2dd8185 100644 --- a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenUpdate.java +++ b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchThenUpdate.java @@ -3,7 +3,10 @@ package org.tests.model.basic.xtra; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -16,6 +19,7 @@ import static org.junit.Assert.assertEquals; public class TestInsertBatchThenUpdate extends BaseTestCase { @Test + @IgnorePlatform(Platform.HANA) public void test() { LoggedSqlCollector.start(); @@ -60,6 +64,7 @@ public class TestInsertBatchThenUpdate extends BaseTestCase { @Test + @IgnorePlatform(Platform.HANA) public void test_noFlushOn_getterOfNonGeneratedProperty() { LoggedSqlCollector.start(); diff --git a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchWithDifferentRootTypes.java b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchWithDifferentRootTypes.java index 487e98a09..da54417e1 100644 --- a/src/test/java/org/tests/model/basic/xtra/TestInsertBatchWithDifferentRootTypes.java +++ b/src/test/java/org/tests/model/basic/xtra/TestInsertBatchWithDifferentRootTypes.java @@ -3,7 +3,10 @@ package org.tests.model.basic.xtra; import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -15,6 +18,7 @@ import static org.junit.Assert.assertEquals; public class TestInsertBatchWithDifferentRootTypes extends BaseTestCase { @Test + @IgnorePlatform(Platform.HANA) public void testDifferRootTypes() { LoggedSqlCollector.start(); diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java index 0dea97952..bcbb642f8 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasic.java @@ -29,9 +29,17 @@ public class TestElementCollectionBasic extends BaseTestCase { assertThat(eventLog()).containsExactly("preInsert", "postInsert"); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("insert into ec_person"); - assertThat(sql.get(1)).contains("insert into ec_person_phone"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ec_person"); + assertThat(sql.get(1)).contains("insert into ec_person_phone"); + } + else { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into ec_person"); + assertThat(sql.get(1)).contains("insert into ec_person_phone"); + assertThat(sql.get(2)).contains("insert into ec_person_phone"); + } EcPerson person1 = new EcPerson("Fiona09"); person1.getPhoneNumbers().add("09 1234"); @@ -121,10 +129,20 @@ public class TestElementCollectionBasic extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("update ec_person set name=?, version=? where id=? and version=?"); - assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); - assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ec_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("update ec_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(3)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(4)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + } assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); @@ -189,9 +207,21 @@ public class TestElementCollectionBasic extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); - assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + } + else { + assertThat(sql).hasSize(7); + assertThat(sql.get(0)).contains("delete from ec_person_phone where owner_id=?"); + assertThat(sql.get(1)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(2)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(3)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(4)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(5)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + assertThat(sql.get(6)).contains("insert into ec_person_phone (owner_id,phone) values (?,?)"); + } assertThat(eventLog()).containsExactly("preUpdate", "postUpdate"); diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java index a73220ce1..13a41e66d 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicCache.java @@ -1,6 +1,9 @@ package org.tests.model.elementcollection; import io.ebean.Ebean; +import io.ebean.annotation.PersistBatch; +import io.ebeaninternal.api.SpiEbeanServer; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -39,7 +42,12 @@ public class TestElementCollectionBasicCache { Ebean.save(two); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + } + else { + assertThat(sql).hasSize(5); + } Ebean.save(two); @@ -60,7 +68,12 @@ public class TestElementCollectionBasicCache { Ebean.save(three); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); // cache hit + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); // cache hit + } + else { + assertThat(sql).hasSize(5); // cache hit + } EcPerson four = Ebean.find(EcPerson.class) .setId(person.getId()) @@ -77,4 +90,8 @@ public class TestElementCollectionBasicCache { LoggedSqlCollector.stop(); } + + public boolean isPersistBatchOnCascade() { + return ((SpiEbeanServer) Ebean.getDefaultServer()).getDatabasePlatform().getPersistBatchOnCascade() != PersistBatch.NONE; + } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java index a2e181892..3ae0ddb19 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMap.java @@ -2,6 +2,8 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.annotation.PersistBatch; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -24,9 +26,17 @@ public class TestElementCollectionBasicMap extends BaseTestCase { Ebean.save(person); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("insert into ecm_person"); - assertThat(sql.get(1)).contains("insert into ecm_person_phone"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecm_person"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone"); + } + else { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into ecm_person"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone"); + assertThat(sql.get(2)).contains("insert into ecm_person_phone"); + } EcmPerson person1 = new EcmPerson("Fiona09"); person1.getPhoneNumbers().put("home", "09 1234"); @@ -96,10 +106,20 @@ public class TestElementCollectionBasicMap extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("update ecm_person set name=?, version=? where id=? and version=?"); - assertThat(sql.get(1)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); - assertThat(sql.get(2)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("update ecm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + assertThat(sql.get(3)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + assertThat(sql.get(4)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + } updateNothing(bean); } @@ -120,9 +140,19 @@ public class TestElementCollectionBasicMap extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); - assertThat(sql.get(1)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("delete from ecm_person_phone_numbers where ecm_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + assertThat(sql.get(2)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + assertThat(sql.get(3)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + assertThat(sql.get(4)).contains("insert into ecm_person_phone_numbers (ecm_person_id,type,number) values (?,?,?)"); + } delete(bean); } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java index 137e8e495..e92ba9324 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicMapCache.java @@ -1,6 +1,9 @@ package org.tests.model.elementcollection; import io.ebean.Ebean; +import io.ebean.annotation.PersistBatch; +import io.ebeaninternal.api.SpiEbeanServer; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -41,7 +44,12 @@ public class TestElementCollectionBasicMapCache { Ebean.save(two); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + } + else { + assertThat(sql).hasSize(5); + } Ebean.save(two); @@ -64,7 +72,12 @@ public class TestElementCollectionBasicMapCache { Ebean.save(three); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); // cache hit + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); // cache hit + } + else { + assertThat(sql).hasSize(3); // cache hit + } EcmPerson four = Ebean.find(EcmPerson.class) .setId(person.getId()) @@ -82,4 +95,8 @@ public class TestElementCollectionBasicMapCache { LoggedSqlCollector.stop(); } + + public boolean isPersistBatchOnCascade() { + return ((SpiEbeanServer) Ebean.getDefaultServer()).getDatabasePlatform().getPersistBatchOnCascade() != PersistBatch.NONE; + } } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java index 2d3124351..2d240671a 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionBasicSet.java @@ -23,9 +23,17 @@ public class TestElementCollectionBasicSet extends BaseTestCase { Ebean.save(person); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("insert into ecs_person"); - assertThat(sql.get(1)).contains("insert into ecs_person_phone"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecs_person"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone"); + } + else { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into ecs_person"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone"); + assertThat(sql.get(2)).contains("insert into ecs_person_phone"); + } EcsPerson person1 = new EcsPerson("Fiona09"); person1.getPhoneNumbers().add("09 1234"); @@ -94,10 +102,20 @@ public class TestElementCollectionBasicSet extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("update ecs_person set name=?, version=? where id=? and version=?"); - assertThat(sql.get(1)).contains("delete from ecs_person_phone where ecs_person_id=?"); - assertThat(sql.get(2)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecs_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("update ecs_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(2)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + assertThat(sql.get(3)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + assertThat(sql.get(4)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + } updateNothing(bean); } @@ -118,9 +136,19 @@ public class TestElementCollectionBasicSet extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("delete from ecs_person_phone where ecs_person_id=?"); - assertThat(sql.get(1)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("delete from ecs_person_phone where ecs_person_id=?"); + assertThat(sql.get(1)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + assertThat(sql.get(2)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + assertThat(sql.get(3)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + assertThat(sql.get(4)).contains("insert into ecs_person_phone (ecs_person_id,phone) values (?,?)"); + } delete(bean); } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java index 8b86e6477..8d4cfbd0c 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedList.java @@ -22,9 +22,17 @@ public class TestElementCollectionEmbeddedList extends BaseTestCase { Ebean.save(person); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("insert into ecbl_person"); - assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecbl_person"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers"); + } + else { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into ecbl_person"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers"); + } EcblPerson person1 = new EcblPerson("Fiona6409"); person1.getPhoneNumbers().add(new EcPhone("61","09","1234")); @@ -94,10 +102,20 @@ public class TestElementCollectionEmbeddedList extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("update ecbl_person set name=?, version=? where id=? and version=?"); - assertThat(sql.get(1)).contains("delete from ecbl_person_phone_numbers where person_id=?"); - assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecbl_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("update ecbl_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(3)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(4)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } updateNothing(bean); } @@ -118,9 +136,19 @@ public class TestElementCollectionEmbeddedList extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); - assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(3)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(4)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } delete(bean); } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java index c9cbaf4d4..cd236e4eb 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedListCache.java @@ -2,6 +2,8 @@ package org.tests.model.elementcollection; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.annotation.PersistBatch; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; @@ -47,9 +49,17 @@ public class TestElementCollectionEmbeddedListCache extends BaseTestCase { Ebean.save(two); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); // update of collection only - assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); - assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } + else { + assertThat(sql).hasSize(3); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbl_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + assertThat(sql.get(2)).contains("insert into ecbl_person_phone_numbers (person_id,country_code,area,number) values (?,?,?,?)"); + } EcblPerson three = Ebean.find(EcblPerson.class) .setId(person.getId()) diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java index 50b37480c..4a6419c0e 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMap.java @@ -23,9 +23,17 @@ public class TestElementCollectionEmbeddedMap extends BaseTestCase { Ebean.save(person); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("insert into ecbm_person"); - assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into ecbm_person"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers"); + } + else { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("insert into ecbm_person"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers"); + } EcbmPerson person1 = new EcbmPerson("Fiona6409"); person1.getPhoneNumbers().put("home",new EcPhone("64","09","1234")); @@ -87,10 +95,20 @@ public class TestElementCollectionEmbeddedMap extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(3); - assertThat(sql.get(0)).contains("update ecbm_person set name=?, version=? where id=? and version=?"); - assertThat(sql.get(1)).contains("delete from ecbm_person_phone_numbers where person_id=?"); - assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(3); + assertThat(sql.get(0)).contains("update ecbm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("update ecbm_person set name=?, version=? where id=? and version=?"); + assertThat(sql.get(1)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); + assertThat(sql.get(3)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); + assertThat(sql.get(4)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number)"); + } updateNothing(bean); } @@ -111,9 +129,19 @@ public class TestElementCollectionEmbeddedMap extends BaseTestCase { Ebean.save(bean); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); - assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + } + else { + assertThat(sql).hasSize(5); + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + assertThat(sql.get(3)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + assertThat(sql.get(4)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + } delete(bean); } diff --git a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java index 1c29bfc55..4aa75ed22 100644 --- a/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java +++ b/src/test/java/org/tests/model/elementcollection/TestElementCollectionEmbeddedMapCache.java @@ -48,9 +48,17 @@ public class TestElementCollectionEmbeddedMapCache extends BaseTestCase { Ebean.save(two); sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(2); // update of collection only - assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); - assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(2); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + } + else { + assertThat(sql).hasSize(3); // update of collection only + assertThat(sql.get(0)).contains("delete from ecbm_person_phone_numbers where person_id=?"); + assertThat(sql.get(1)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + assertThat(sql.get(2)).contains("insert into ecbm_person_phone_numbers (person_id,mkey,country_code,area,number) values (?,?,?,?,?)"); + } EcbmPerson three = Ebean.find(EcbmPerson.class) .setId(person.getId()) diff --git a/src/test/java/org/tests/model/m2o/TestManyToOneAsOne.java b/src/test/java/org/tests/model/m2o/TestManyToOneAsOne.java index b7d1cc7b6..eb993da93 100644 --- a/src/test/java/org/tests/model/m2o/TestManyToOneAsOne.java +++ b/src/test/java/org/tests/model/m2o/TestManyToOneAsOne.java @@ -18,7 +18,7 @@ public class TestManyToOneAsOne extends BaseTestCase { @Transactional(batchSize = 20) @Test - @IgnorePlatform({Platform.SQLSERVER, Platform.ORACLE}) // probably due the use of sequences - Empl has already an ID and Addr refers to it. + @IgnorePlatform({Platform.SQLSERVER, Platform.ORACLE, Platform.HANA}) // probably due the use of sequences - Empl has already an ID and Addr refers to it. public void test_when_jdbcBatch() { runInserts(); } diff --git a/src/test/java/org/tests/model/onetoone/album/DeleteById_SoftDelete_Tests.java b/src/test/java/org/tests/model/onetoone/album/DeleteById_SoftDelete_Tests.java index bb27d3c5a..5beea394f 100644 --- a/src/test/java/org/tests/model/onetoone/album/DeleteById_SoftDelete_Tests.java +++ b/src/test/java/org/tests/model/onetoone/album/DeleteById_SoftDelete_Tests.java @@ -216,7 +216,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + } + else { + assertThat(sql.get(0)).contains("update cover set deleted=? where id=?"); + } } @Test @@ -232,7 +237,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + } + else { + assertThat(sql.get(0)).contains("update cover set deleted=? where id=?"); + } } @Test @@ -254,7 +264,12 @@ public class DeleteById_SoftDelete_Tests extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + if (isPersistBatchOnCascade()) { + assertThat(sql.get(0)).contains("update cover set s3url=?, deleted=? where id=?"); + } + else { + assertThat(sql.get(0)).contains("update cover set deleted=? where id=?"); + } } @Test diff --git a/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java index dd7f6b6c1..1a377b7e5 100644 --- a/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java +++ b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTable.java @@ -2,10 +2,13 @@ package org.tests.o2m.jointable; import io.ebean.BaseTestCase; import io.ebean.Ebean; +import io.ebean.annotation.PersistBatch; + import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -37,8 +40,15 @@ public class TestOneToManyJoinTable extends BaseTestCase { Ebean.save(troop); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)"); + } + else { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)"); + assertThat(sql.get(1)).contains("insert into troop_monkey (troop_pid, monkey_mid) values (?, ?)"); + } int intersectionRows = Ebean.createSqlQuery("select count(*) as total from troop_monkey where troop_pid = ?") .setParameter(1, troop.getPid()) @@ -87,12 +97,23 @@ public class TestOneToManyJoinTable extends BaseTestCase { Ebean.save(trainer); List sql = LoggedSqlCollector.current(); + //Collections.sort(sql); - assertThat(sql).hasSize(6); - assertThat(sql.get(0)).contains("insert into trainer "); - assertThat(sql.get(1)).contains("insert into monkey "); - assertThat(sql.get(4)).contains("update monkey set name=?, food_preference=?, version=? where mid=? and version=?"); - assertThat(sql.get(5)).contains("insert into trainer_monkey "); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(6); + assertThat(sql.get(0)).contains("insert into trainer "); + assertThat(sql.get(1)).contains("insert into monkey "); + assertThat(sql.get(4)).contains("update monkey set name=?, food_preference=?, version=? where mid=? and version=?"); + assertThat(sql.get(5)).contains("insert into trainer_monkey "); + } + else { + assertThat(sql).hasSize(10); + assertThat(sql.get(0)).contains("insert into trainer "); + assertThat(sql.get(1)).contains("update monkey set food_preference=?, version=? where mid=? and version=?"); + assertThat(sql.get(2)).contains("insert into monkey "); + assertThat(sql.get(5)).contains("insert into trainer_monkey "); + assertThat(sql.get(9)).contains("insert into trainer_monkey "); + } int intersectionRows = Ebean.createSqlQuery("select count(*) as total from trainer_monkey where trainer_tid = ?") diff --git a/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTableNoTableName.java b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTableNoTableName.java index dc8b93738..3ba5331e2 100644 --- a/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTableNoTableName.java +++ b/src/test/java/org/tests/o2m/jointable/TestOneToManyJoinTableNoTableName.java @@ -37,8 +37,15 @@ public class TestOneToManyJoinTableNoTableName extends BaseTestCase { Ebean.save(troop); List sql = LoggedSqlCollector.current(); - assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("insert into mkeygroup_monkey (mkeygroup_pid, monkey_mid) values (?, ?)"); + if (isPersistBatchOnCascade()) { + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("insert into mkeygroup_monkey (mkeygroup_pid, monkey_mid) values (?, ?)"); + } + else { + assertThat(sql).hasSize(2); + assertThat(sql.get(0)).contains("insert into mkeygroup_monkey (mkeygroup_pid, monkey_mid) values (?, ?)"); + assertThat(sql.get(1)).contains("insert into mkeygroup_monkey (mkeygroup_pid, monkey_mid) values (?, ?)"); + } int intersectionRows = Ebean.createSqlQuery("select count(*) as total from mkeygroup_monkey where mkeygroup_pid = ?") .setParameter(1, troop.getPid()) diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index 3c027b662..cbd55510e 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -1,8 +1,12 @@ package org.tests.query.aggregation; -import io.ebean.BaseTestCase; -import io.ebean.Ebean; -import io.ebean.Query; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.StrictAssertions.assertThat; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; + import org.ebeantest.LoggedSqlCollector; import org.junit.BeforeClass; import org.junit.Test; @@ -13,11 +17,9 @@ import org.tests.model.basic.ResetBasicData; import org.tests.model.tevent.TEventMany; import org.tests.model.tevent.TEventOne; -import java.sql.Timestamp; -import java.time.Instant; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; +import io.ebean.BaseTestCase; +import io.ebean.Ebean; +import io.ebean.Query; public class TestAggregationCount extends BaseTestCase { @@ -383,7 +385,7 @@ public class TestAggregationCount extends BaseTestCase { List names = Ebean.find(Contact.class) - .select("concat(lastName,', ',firstName)") + .select(concat("lastName",", ","firstName")) .where().isNull("phone") .orderBy().asc("lastName") .findSingleAttributeList(); @@ -391,7 +393,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(names).isNotEmpty(); List sql = LoggedSqlCollector.stop(); - assertThat(trimSql(sql.get(0))).contains("select concat(t0.last_name,', ',t0.first_name) from contact t0 where t0.phone is null order by t0.last_name"); + assertThat(trimSql(sql.get(0))).contains("select " + concat("t0.last_name",", ","t0.first_name") + " from contact t0 where t0.phone is null order by t0.last_name"); } @Test @@ -404,7 +406,7 @@ public class TestAggregationCount extends BaseTestCase { List names = Ebean.find(Contact.class) - .select("concat(updtime,', ',firstName)") + .select(concat("updtime",", ","firstName")) .where().isNull("phone") .orderBy().asc("lastName") .findSingleAttributeList(); @@ -412,7 +414,7 @@ public class TestAggregationCount extends BaseTestCase { assertThat(names).isNotEmpty(); List sql = LoggedSqlCollector.stop(); - assertThat(trimSql(sql.get(0))).contains("select concat(t0.updtime,', ',t0.first_name) from contact t0"); + assertThat(trimSql(sql.get(0))).contains("select " + concat("t0.updtime",", ","t0.first_name") + " from contact t0"); } @Test @@ -446,7 +448,7 @@ public class TestAggregationCount extends BaseTestCase { List contacts = Ebean.find(Contact.class) - .select("email, concat(lastName,', ',firstName) as lastName") + .select("email, " + concat("lastName",", ","firstName") + " as lastName") .where().isNull("phone") .orderBy().asc("lastName") .findList(); @@ -459,7 +461,7 @@ public class TestAggregationCount extends BaseTestCase { } List sql = LoggedSqlCollector.stop(); - assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.email, concat(t0.last_name,', ',t0.first_name) lastName from contact t0 where t0.phone is null order by t0.last_name; --bind()"); + assertThat(trimSql(sql.get(0))).contains("select t0.id, t0.email, " + concat("t0.last_name",", ","t0.first_name") + " lastName from contact t0 where t0.phone is null order by t0.last_name; --bind()"); } } diff --git a/src/test/java/org/tests/transaction/TestBatchPersistCascade.java b/src/test/java/org/tests/transaction/TestBatchPersistCascade.java index 5c35a381d..982a127fb 100644 --- a/src/test/java/org/tests/transaction/TestBatchPersistCascade.java +++ b/src/test/java/org/tests/transaction/TestBatchPersistCascade.java @@ -4,7 +4,10 @@ import io.ebean.BaseTestCase; import io.ebean.Ebean; import io.ebean.EbeanServer; import io.ebean.Transaction; +import io.ebean.annotation.IgnorePlatform; import io.ebean.annotation.PersistBatch; +import io.ebean.annotation.Platform; + import org.tests.model.basic.UTDetail; import org.tests.model.basic.UTMaster; import org.ebeantest.LoggedSqlCollector; @@ -21,6 +24,7 @@ public class TestBatchPersistCascade extends BaseTestCase { Logger logger = LoggerFactory.getLogger(TestBatchPersistCascade.class); @Test + @IgnorePlatform(Platform.HANA) public void test() { EbeanServer ebeanServer = Ebean.getServer(null); diff --git a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java index dc9e3d147..a30d5a104 100644 --- a/src/test/java/org/tests/transaction/TestNestedSubTransaction.java +++ b/src/test/java/org/tests/transaction/TestNestedSubTransaction.java @@ -20,7 +20,7 @@ public class TestNestedSubTransaction extends BaseTestCase { /** * MySql only supports named savepoints - review. */ - @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER}) + @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER, Platform.HANA}) @Test public void ebeanServer_commitTransaction_expect_sameAsTransactionCommit() { @@ -65,7 +65,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } - @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA}) @Test public void nestedUseSavepoint_doubleNested_rollbackCommit() { @@ -102,7 +102,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } } - @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA}) @Test public void nestedUseSavepoint_doubleNested_commitRollback() { @@ -139,7 +139,7 @@ public class TestNestedSubTransaction extends BaseTestCase { } } - @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA}) @Test public void nestedUseSavepoint_nested_RequiresNew() { @@ -175,7 +175,7 @@ public class TestNestedSubTransaction extends BaseTestCase { assertNull(after); } - @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL}) + @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.HANA}) @Test public void nestedUseSavepoint() { diff --git a/src/test/resources/assert/create-column-table.txt b/src/test/resources/assert/create-column-table.txt new file mode 100644 index 000000000..879972680 --- /dev/null +++ b/src/test/resources/assert/create-column-table.txt @@ -0,0 +1,8 @@ +create column table foo ( + col1 nvarchar(4) generated by default as identity not null, + col2 nvarchar(30) not null, + col3 nvarchar(30) not null, + constraint pk_foo primary key (col1) +); +comment on table foo is 'comment'; + diff --git a/src/test/resources/dbmigration/migrationtest/hana/1.0__initial.sql b/src/test/resources/dbmigration/migrationtest/hana/1.0__initial.sql new file mode 100644 index 000000000..cb6d8e6d4 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/1.0__initial.sql @@ -0,0 +1,235 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create column table migtest_ckey_assoc ( + id integer generated by default as identity not null, + assoc_one nvarchar(255), + constraint pk_migtest_ckey_assoc primary key (id) +); + +create column table migtest_ckey_detail ( + id integer generated by default as identity not null, + something nvarchar(255), + constraint pk_migtest_ckey_detail primary key (id) +); + +create column table migtest_ckey_parent ( + one_key integer not null, + two_key nvarchar(127) not null, + name nvarchar(255), + version integer not null, + constraint pk_migtest_ckey_parent primary key (one_key,two_key) +); + +create column table migtest_fk_cascade ( + id bigint generated by default as identity not null, + one_id bigint, + constraint pk_migtest_fk_cascade primary key (id) +); + +create column table migtest_fk_cascade_one ( + id bigint generated by default as identity not null, + constraint pk_migtest_fk_cascade_one primary key (id) +); + +create column table migtest_fk_none ( + id bigint generated by default as identity not null, + one_id bigint, + constraint pk_migtest_fk_none primary key (id) +); + +create column table migtest_fk_none_via_join ( + id bigint generated by default as identity not null, + one_id bigint, + constraint pk_migtest_fk_none_via_join primary key (id) +); + +create column table migtest_fk_one ( + id bigint generated by default as identity not null, + constraint pk_migtest_fk_one primary key (id) +); + +create column table migtest_fk_set_null ( + id bigint generated by default as identity not null, + one_id bigint, + constraint pk_migtest_fk_set_null primary key (id) +); + +create column table migtest_e_basic ( + id integer generated by default as identity not null, + status nvarchar(1), + name nvarchar(127), + description nvarchar(127), + some_date timestamp, + old_boolean boolean default false not null, + old_boolean2 boolean, + eref_id integer, + indextest1 nvarchar(127), + indextest2 nvarchar(127), + indextest3 nvarchar(127), + indextest4 nvarchar(127), + indextest5 nvarchar(127), + indextest6 nvarchar(127), + user_id integer not null, + constraint ck_migtest_e_basic_status check ( status in ('N','A','I')), + constraint uq_migtest_e_basic_indextest2 unique (indextest2), + constraint uq_migtest_e_basic_indextest6 unique (indextest6), + constraint pk_migtest_e_basic primary key (id) +); + +create column table migtest_e_enum ( + id integer generated by default as identity not null, + test_status nvarchar(1), + constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I')), + constraint pk_migtest_e_enum primary key (id) +); + +create column table migtest_e_history ( + id integer generated by default as identity not null, + test_string nvarchar(255), + constraint pk_migtest_e_history primary key (id) +); + +create column table migtest_e_history2 ( + id integer generated by default as identity not null, + test_string nvarchar(255), + obsolete_string1 nvarchar(255), + obsolete_string2 nvarchar(255), + constraint pk_migtest_e_history2 primary key (id) +); + +create column table migtest_e_history3 ( + id integer generated by default as identity not null, + test_string nvarchar(255), + constraint pk_migtest_e_history3 primary key (id) +); + +create column table migtest_e_history4 ( + id integer generated by default as identity not null, + test_number integer, + constraint pk_migtest_e_history4 primary key (id) +); + +create column table migtest_e_history5 ( + id integer generated by default as identity not null, + test_number integer, + constraint pk_migtest_e_history5 primary key (id) +); + +create column table migtest_e_history6 ( + id integer generated by default as identity not null, + test_number1 integer, + test_number2 integer not null, + constraint pk_migtest_e_history6 primary key (id) +); + +create column table migtest_e_ref ( + id integer generated by default as identity not null, + name nvarchar(127) not null, + constraint uq_migtest_e_ref_name unique (name), + constraint pk_migtest_e_ref primary key (id) +); + +create column table migtest_e_softdelete ( + id integer generated by default as identity not null, + test_string nvarchar(255), + constraint pk_migtest_e_softdelete primary key (id) +); + +create column table migtest_mtm_c ( + id integer generated by default as identity not null, + name nvarchar(255), + constraint pk_migtest_mtm_c primary key (id) +); + +create column table migtest_mtm_m ( + id bigint generated by default as identity not null, + name nvarchar(255), + constraint pk_migtest_mtm_m primary key (id) +); + +create column table migtest_oto_child ( + id integer generated by default as identity not null, + name nvarchar(255), + constraint pk_migtest_oto_child primary key (id) +); + +create column table migtest_oto_master ( + id bigint generated by default as identity not null, + name nvarchar(255), + constraint pk_migtest_oto_master primary key (id) +); + +-- explicit index "ix_migtest_e_basic_indextest1" for single column "indextest1" of table "migtest_e_basic" is not necessary; +-- explicit index "ix_migtest_e_basic_indextest5" for single column "indextest5" of table "migtest_e_basic" is not necessary; +-- explicit index "ix_migtest_fk_cascade_one_id" for single column "one_id" of table "migtest_fk_cascade" is not necessary; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; + +-- explicit index "ix_migtest_fk_set_null_one_id" for single column "one_id" of table "migtest_fk_set_null" is not necessary; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; + +-- explicit index "ix_migtest_e_basic_eref_id" for single column "eref_id" of table "migtest_e_basic" is not necessary; +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; + +create column table migtest_e_history2_history ( + id integer, + test_string nvarchar(255), + obsolete_string1 nvarchar(255), + obsolete_string2 nvarchar(255), + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history2 add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history2 add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history; +create column table migtest_e_history3_history ( + id integer, + test_string nvarchar(255), + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history3 add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history3 add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history3 add system versioning history table migtest_e_history3_history; +create column table migtest_e_history4_history ( + id integer, + test_number integer, + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history4 add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history4 add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history4 add system versioning history table migtest_e_history4_history; +create column table migtest_e_history5_history ( + id integer, + test_number integer, + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history5 add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history5 add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history5 add system versioning history table migtest_e_history5_history; +create column table migtest_e_history6_history ( + id integer, + test_number1 integer, + test_number2 integer not null, + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history6 add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history6 add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history6 add system versioning history table migtest_e_history6_history; diff --git a/src/test/resources/dbmigration/migrationtest/hana/1.1.sql b/src/test/resources/dbmigration/migrationtest/hana/1.1.sql new file mode 100644 index 000000000..efa06b208 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/1.1.sql @@ -0,0 +1,176 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create column table migtest_e_user ( + id integer generated by default as identity not null, + constraint pk_migtest_e_user primary key (id) +); + +create column table migtest_mtm_c_migtest_mtm_m ( + migtest_mtm_c_id integer not null, + migtest_mtm_m_id bigint not null, + constraint pk_migtest_mtm_c_migtest_mtm_m primary key (migtest_mtm_c_id,migtest_mtm_m_id) +); + +create column table migtest_mtm_m_migtest_mtm_c ( + migtest_mtm_m_id bigint not null, + migtest_mtm_c_id integer not null, + constraint pk_migtest_mtm_m_migtest_mtm_c primary key (migtest_mtm_m_id,migtest_mtm_c_id) +); + +alter table migtest_ckey_detail add ( one_key integer); +alter table migtest_ckey_detail add ( two_key nvarchar(127)); + +alter table migtest_ckey_detail add constraint fk_migtest_ckey_detail_parent foreign key (one_key,two_key) references migtest_ckey_parent (one_key,two_key) on delete restrict on update restrict; +alter table migtest_ckey_parent add ( assoc_id integer); + +alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete restrict on update restrict; +alter table migtest_fk_none add constraint fk_migtest_fk_none_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; +alter table migtest_fk_none_via_join add constraint fk_migtest_fk_none_via_join_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; +alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete restrict on update restrict; + +update migtest_e_basic set status = 'A' where status is null; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status'; +end; +$$; +alter table migtest_e_basic alter ( status nvarchar(1) default 'A' not null); +alter table migtest_e_basic alter ( status nvarchar(1) default 'A' not null); +alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I','?')); + +-- rename all collisions; +-- cannot create unique index "uq_migtest_e_basic_description" on table "migtest_e_basic" with nullable columns; + +insert into migtest_e_user (id) select distinct user_id from migtest_e_basic; +alter table migtest_e_basic add constraint fk_migtest_e_basic_user_id foreign key (user_id) references migtest_e_user (id) on delete restrict on update restrict; +alter table migtest_e_basic alter ( user_id integer); +alter table migtest_e_basic add ( new_string_field nvarchar(255) default 'foo''bar' not null); +alter table migtest_e_basic add ( new_boolean_field boolean default true not null); +update migtest_e_basic set new_boolean_field = old_boolean; + +alter table migtest_e_basic add ( new_boolean_field2 boolean default true not null); +alter table migtest_e_basic add ( progress integer default 0 not null); +alter table migtest_e_basic add constraint ck_migtest_e_basic_progress check ( progress in (0,1,2)); +alter table migtest_e_basic add ( new_integer integer default 42 not null); + +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest2'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest6'; +end; +$$; +-- cannot create unique index "uq_migtest_e_basic_status_indextest1" on table "migtest_e_basic" with nullable columns; +-- cannot create unique index "uq_migtest_e_basic_name" on table "migtest_e_basic" with nullable columns; +-- cannot create unique index "uq_migtest_e_basic_indextest4" on table "migtest_e_basic" with nullable columns; +-- cannot create unique index "uq_migtest_e_basic_indextest5" on table "migtest_e_basic" with nullable columns; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status'; +end; +$$; +comment on column migtest_e_history.test_string is 'Column altered to long now'; +alter table migtest_e_history alter ( test_string bigint); +comment on table migtest_e_history is 'We have history now'; +alter table migtest_e_history2 drop system versioning /* 0 */; + +-- NOTE: table has @History - special migration may be necessary +update migtest_e_history2 set test_string = 'unknown' where test_string is null; +alter table migtest_e_history2 alter ( test_string nvarchar(255) default 'unknown' not null); +alter table migtest_e_history2 alter ( test_string nvarchar(255) default 'unknown' not null); +alter table migtest_e_history2_history alter ( test_string nvarchar(255) default 'unknown' not null); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 1 */; +alter table migtest_e_history2 drop system versioning /* 2 */; +alter table migtest_e_history2 add ( test_string2 nvarchar(255)); +alter table migtest_e_history2 add ( test_string3 nvarchar(255) default 'unknown' not null); +alter table migtest_e_history2 add ( new_column nvarchar(20)); + +alter table migtest_e_history2_history add ( test_string2 nvarchar(255)); +alter table migtest_e_history2_history add ( test_string3 nvarchar(255) default 'unknown'); +alter table migtest_e_history2_history add ( new_column nvarchar(20)); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 3 */; +alter table migtest_e_history3 drop system versioning /* 4 */; +alter table migtest_e_history3 add system versioning history table migtest_e_history3_history not validated /* 5 */; +alter table migtest_e_history4 drop system versioning /* 6 */; +alter table migtest_e_history4 alter ( test_number bigint); +alter table migtest_e_history4_history alter ( test_number bigint); +alter table migtest_e_history4 add system versioning history table migtest_e_history4_history not validated /* 7 */; +alter table migtest_e_history5 drop system versioning /* 8 */; +alter table migtest_e_history5 add ( test_boolean boolean default false not null); + +alter table migtest_e_history5_history add ( test_boolean boolean default false); +alter table migtest_e_history5 add system versioning history table migtest_e_history5_history not validated /* 9 */; +alter table migtest_e_history6 drop system versioning /* 10 */; + +-- NOTE: table has @History - special migration may be necessary +update migtest_e_history6 set test_number1 = 42 where test_number1 is null; +alter table migtest_e_history6 alter ( test_number1 integer default 42 not null); +alter table migtest_e_history6 alter ( test_number1 integer default 42 not null); +alter table migtest_e_history6_history alter ( test_number1 integer default 42 not null); +alter table migtest_e_history6 add system versioning history table migtest_e_history6_history not validated /* 11 */; +alter table migtest_e_history6 drop system versioning /* 12 */; +alter table migtest_e_history6 alter ( test_number2 integer); +alter table migtest_e_history6_history alter ( test_number2 integer); +alter table migtest_e_history6 add system versioning history table migtest_e_history6_history not validated /* 13 */; +alter table migtest_e_softdelete add ( deleted boolean default false not null); + +alter table migtest_oto_child add ( master_id bigint); + +-- explicit index "ix_migtest_e_basic_indextest3" for single column "indextest3" of table "migtest_e_basic" is not necessary; +-- explicit index "ix_migtest_e_basic_indextest6" for single column "indextest6" of table "migtest_e_basic" is not necessary; +delimiter $$ +do +begin +declare exit handler for sql_error_code 261 begin end; +exec 'drop index ix_migtest_e_basic_indextest1'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 261 begin end; +exec 'drop index ix_migtest_e_basic_indextest5'; +end; +$$; +-- explicit index "ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c" for single column "migtest_mtm_c_id" of table "migtest_mtm_c_migtest_mtm_m" is not necessary; +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; + +-- explicit index "ix_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m" for single column "migtest_mtm_m_id" of table "migtest_mtm_c_migtest_mtm_m" is not necessary; +alter table migtest_mtm_c_migtest_mtm_m add constraint fk_migtest_mtm_c_migtest_mtm_m_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; + +-- explicit index "ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m" for single column "migtest_mtm_m_id" of table "migtest_mtm_m_migtest_mtm_c" is not necessary; +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_m foreign key (migtest_mtm_m_id) references migtest_mtm_m (id) on delete restrict on update restrict; + +-- explicit index "ix_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c" for single column "migtest_mtm_c_id" of table "migtest_mtm_m_migtest_mtm_c" is not necessary; +alter table migtest_mtm_m_migtest_mtm_c add constraint fk_migtest_mtm_m_migtest_mtm_c_migtest_mtm_c foreign key (migtest_mtm_c_id) references migtest_mtm_c (id) on delete restrict on update restrict; + +-- explicit index "ix_migtest_ckey_parent_assoc_id" for single column "assoc_id" of table "migtest_ckey_parent" is not necessary; +alter table migtest_ckey_parent add constraint fk_migtest_ckey_parent_assoc_id foreign key (assoc_id) references migtest_ckey_assoc (id) on delete restrict on update restrict; + +alter table migtest_oto_child add constraint fk_migtest_oto_child_master_id foreign key (master_id) references migtest_oto_master (id) on delete restrict on update restrict; + +create column table migtest_e_history_history ( + id integer, + test_string bigint, + sys_period_start timestamp, + sys_period_end timestamp +); +alter table migtest_e_history add ( + sys_period_start TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, + sys_period_end TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END +); +alter table migtest_e_history add period for system_time(sys_period_start,sys_period_end); +alter table migtest_e_history add system versioning history table migtest_e_history_history; diff --git a/src/test/resources/dbmigration/migrationtest/hana/1.2__dropsFor_1.1.sql b/src/test/resources/dbmigration/migrationtest/hana/1.2__dropsFor_1.1.sql new file mode 100644 index 000000000..a69417f3e --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/1.2__dropsFor_1.1.sql @@ -0,0 +1,19 @@ +-- Migrationscripts for ebean unittest +-- apply changes +CALL usp_ebean_drop_column('migtest_e_basic', 'old_boolean'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'old_boolean2'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'eref_id'); + +alter table migtest_e_history2 drop system versioning /* 0 */; +CALL usp_ebean_drop_column('migtest_e_history2', 'obsolete_string1'); + +CALL usp_ebean_drop_column('migtest_e_history2_history', 'obsolete_string1'); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 1 */; +alter table migtest_e_history2 drop system versioning /* 2 */; +CALL usp_ebean_drop_column('migtest_e_history2', 'obsolete_string2'); + +CALL usp_ebean_drop_column('migtest_e_history2_history', 'obsolete_string2'); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 3 */; +drop table migtest_e_ref cascade; diff --git a/src/test/resources/dbmigration/migrationtest/hana/1.3.sql b/src/test/resources/dbmigration/migrationtest/hana/1.3.sql new file mode 100644 index 000000000..11221535d --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/1.3.sql @@ -0,0 +1,134 @@ +-- Migrationscripts for ebean unittest +-- apply changes +create column table migtest_e_ref ( + id integer generated by default as identity not null, + name nvarchar(127) not null, + constraint uq_migtest_e_ref_name unique (name), + constraint pk_migtest_e_ref primary key (id) +); + +alter table migtest_ckey_detail drop constraint fk_migtest_ckey_detail_parent; +alter table migtest_fk_cascade drop constraint fk_migtest_fk_cascade_one_id; +alter table migtest_fk_cascade add constraint fk_migtest_fk_cascade_one_id foreign key (one_id) references migtest_fk_cascade_one (id) on delete cascade on update cascade; +alter table migtest_fk_none drop constraint fk_migtest_fk_none_one_id; +alter table migtest_fk_none_via_join drop constraint fk_migtest_fk_none_via_join_one_id; +alter table migtest_fk_set_null drop constraint fk_migtest_fk_set_null_one_id; +alter table migtest_fk_set_null add constraint fk_migtest_fk_set_null_one_id foreign key (one_id) references migtest_fk_one (id) on delete set null on update set null; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint ck_migtest_e_basic_status'; +end; +$$; +alter table migtest_e_basic alter ( status nvarchar(1) default null); +alter table migtest_e_basic alter ( status nvarchar(1) default null); +alter table migtest_e_basic add constraint ck_migtest_e_basic_status check ( status in ('N','A','I')); +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_description'; +end; +$$; + +update migtest_e_basic set user_id = 23 where user_id is null; +alter table migtest_e_basic drop constraint fk_migtest_e_basic_user_id; +alter table migtest_e_basic alter ( user_id integer default 23 not null); +alter table migtest_e_basic alter ( user_id integer default 23 not null); +alter table migtest_e_basic add ( old_boolean boolean default false not null); +alter table migtest_e_basic add ( old_boolean2 boolean); +alter table migtest_e_basic add ( eref_id integer); + +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_status_indextest1'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_name'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest4'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_basic drop constraint uq_migtest_e_basic_indextest5'; +end; +$$; +-- cannot create unique index "uq_migtest_e_basic_indextest2" on table "migtest_e_basic" with nullable columns; +-- cannot create unique index "uq_migtest_e_basic_indextest6" on table "migtest_e_basic" with nullable columns; +delimiter $$ +do +begin +declare exit handler for sql_error_code 397 begin end; +exec 'alter table migtest_e_enum drop constraint ck_migtest_e_enum_test_status'; +end; +$$; +alter table migtest_e_enum add constraint ck_migtest_e_enum_test_status check ( test_status in ('N','A','I')); +comment on column migtest_e_history.test_string is ''; +comment on table migtest_e_history is ''; +alter table migtest_e_history2 drop system versioning /* 0 */; +alter table migtest_e_history2 alter ( test_string nvarchar(255) default null); +alter table migtest_e_history2 alter ( test_string nvarchar(255) default null); +alter table migtest_e_history2_history alter ( test_string nvarchar(255) default null); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 1 */; +alter table migtest_e_history2 drop system versioning /* 2 */; +alter table migtest_e_history2 add ( obsolete_string1 nvarchar(255)); +alter table migtest_e_history2 add ( obsolete_string2 nvarchar(255)); + +alter table migtest_e_history2_history add ( obsolete_string1 nvarchar(255)); +alter table migtest_e_history2_history add ( obsolete_string2 nvarchar(255)); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 3 */; +alter table migtest_e_history3 drop system versioning /* 4 */; +alter table migtest_e_history3 add system versioning history table migtest_e_history3_history not validated /* 5 */; +alter table migtest_e_history4 drop system versioning /* 6 */; +alter table migtest_e_history4 alter ( test_number decimal ); +alter table migtest_e_history4 alter ( test_number integer); +alter table migtest_e_history4_history alter ( test_number decimal ); +alter table migtest_e_history4_history alter ( test_number integer); +alter table migtest_e_history4 add system versioning history table migtest_e_history4_history not validated /* 7 */; +alter table migtest_e_history6 drop system versioning /* 8 */; +alter table migtest_e_history6 alter ( test_number1 integer default null); +alter table migtest_e_history6 alter ( test_number1 integer default null); +alter table migtest_e_history6_history alter ( test_number1 integer default null); +alter table migtest_e_history6 add system versioning history table migtest_e_history6_history not validated /* 9 */; +alter table migtest_e_history6 drop system versioning /* 10 */; + +-- NOTE: table has @History - special migration may be necessary +update migtest_e_history6 set test_number2 = 7 where test_number2 is null; +alter table migtest_e_history6 alter ( test_number2 integer default 7 not null); +alter table migtest_e_history6 alter ( test_number2 integer default 7 not null); +alter table migtest_e_history6_history alter ( test_number2 integer default 7 not null); +alter table migtest_e_history6 add system versioning history table migtest_e_history6_history not validated /* 11 */; +-- explicit index "ix_migtest_e_basic_indextest1" for single column "indextest1" of table "migtest_e_basic" is not necessary; +-- explicit index "ix_migtest_e_basic_indextest5" for single column "indextest5" of table "migtest_e_basic" is not necessary; +delimiter $$ +do +begin +declare exit handler for sql_error_code 261 begin end; +exec 'drop index ix_migtest_e_basic_indextest3'; +end; +$$; +delimiter $$ +do +begin +declare exit handler for sql_error_code 261 begin end; +exec 'drop index ix_migtest_e_basic_indextest6'; +end; +$$; +-- explicit index "ix_migtest_e_basic_eref_id" for single column "eref_id" of table "migtest_e_basic" is not necessary; +alter table migtest_e_basic add constraint fk_migtest_e_basic_eref_id foreign key (eref_id) references migtest_e_ref (id) on delete restrict on update restrict; + diff --git a/src/test/resources/dbmigration/migrationtest/hana/1.4__dropsFor_1.3.sql b/src/test/resources/dbmigration/migrationtest/hana/1.4__dropsFor_1.3.sql new file mode 100644 index 000000000..fe5d6371f --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/1.4__dropsFor_1.3.sql @@ -0,0 +1,51 @@ +-- Migrationscripts for ebean unittest +-- drop dependencies +alter table migtest_e_history drop system versioning; +alter table migtest_e_history drop period for system_time; +alter table migtest_e_history drop (sys_period_start,sys_period_end); +drop table migtest_e_history_history cascade; + +-- apply changes +CALL usp_ebean_drop_column('migtest_ckey_detail', 'one_key'); + +CALL usp_ebean_drop_column('migtest_ckey_detail', 'two_key'); + +CALL usp_ebean_drop_column('migtest_ckey_parent', 'assoc_id'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'new_string_field'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'new_boolean_field'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'new_boolean_field2'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'progress'); + +CALL usp_ebean_drop_column('migtest_e_basic', 'new_integer'); + +alter table migtest_e_history2 drop system versioning /* 0 */; +CALL usp_ebean_drop_column('migtest_e_history2', 'test_string2'); + +CALL usp_ebean_drop_column('migtest_e_history2_history', 'test_string2'); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 1 */; +alter table migtest_e_history2 drop system versioning /* 2 */; +CALL usp_ebean_drop_column('migtest_e_history2', 'test_string3'); + +CALL usp_ebean_drop_column('migtest_e_history2_history', 'test_string3'); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 3 */; +alter table migtest_e_history2 drop system versioning /* 4 */; +CALL usp_ebean_drop_column('migtest_e_history2', 'new_column'); + +CALL usp_ebean_drop_column('migtest_e_history2_history', 'new_column'); +alter table migtest_e_history2 add system versioning history table migtest_e_history2_history not validated /* 5 */; +alter table migtest_e_history5 drop system versioning /* 6 */; +CALL usp_ebean_drop_column('migtest_e_history5', 'test_boolean'); + +CALL usp_ebean_drop_column('migtest_e_history5_history', 'test_boolean'); +alter table migtest_e_history5 add system versioning history table migtest_e_history5_history not validated /* 7 */; +CALL usp_ebean_drop_column('migtest_e_softdelete', 'deleted'); + +CALL usp_ebean_drop_column('migtest_oto_child', 'master_id'); + +drop table migtest_e_user cascade; +drop table migtest_mtm_c_migtest_mtm_m cascade; +drop table migtest_mtm_m_migtest_mtm_c cascade; diff --git a/src/test/resources/dbmigration/migrationtest/hana/I__create_procs.sql b/src/test/resources/dbmigration/migrationtest/hana/I__create_procs.sql new file mode 100644 index 000000000..6abbe7a96 --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/I__create_procs.sql @@ -0,0 +1,33 @@ +-- 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/src/test/resources/dbmigration/migrationtest/hana/R__order_views_hana.sql b/src/test/resources/dbmigration/migrationtest/hana/R__order_views_hana.sql new file mode 100644 index 000000000..85b1dce9f --- /dev/null +++ b/src/test/resources/dbmigration/migrationtest/hana/R__order_views_hana.sql @@ -0,0 +1,7 @@ + + create view order_agg_vw as + select d.order_id, sum(d.order_qty * d.unit_price) as order_total, + sum(d.ship_qty * d.unit_price) as ship_total + from o_order_detail d + group by d.order_id; + \ No newline at end of file diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties index 5080db655..0e9fc7c8a 100644 --- a/src/test/resources/ebean.properties +++ b/src/test/resources/ebean.properties @@ -158,6 +158,11 @@ datasource.db2.password=veryverysecret#1234 datasource.db2.databaseUrl=jdbc:db2://127.0.0.1:50000/SAMPLE datasource.db2.databaseDriver=com.ibm.db2.jcc.DB2Driver +datasource.hana.username=EBEAN_TEST +datasource.hana.password=Eb3an_test +datasource.hana.databaseUrl=jdbc:sap://hxehost:39013/?databaseName=HXE +datasource.hana.databaseDriver=com.sap.db.jdbc.Driver + # parameters for migration test datasource.migrationtest.username=SA datasource.migrationtest.password=SA diff --git a/src/test/resources/extra-ddl.xml b/src/test/resources/extra-ddl.xml index bb786221b..aaf69b523 100644 --- a/src/test/resources/extra-ddl.xml +++ b/src/test/resources/extra-ddl.xml @@ -21,6 +21,14 @@ from o_order_detail d group by d.order_id;
    + + + create view order_agg_vw as + select d.order_id, sum(d.order_qty * d.unit_price) as order_total, + sum(d.ship_qty * d.unit_price) as ship_total + from o_order_detail d + group by d.order_id; + drop view if exists order_agg_vw; From 2dbb5ea80dedc25a6bcac19cfd2b2f0ce0b3132f Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 21:49:48 +1300 Subject: [PATCH 0500/1036] #1511 - Add SAP HANA support - format only changes --- .../config/dbplatform/hana/HanaPlatform.java | 51 +++++++++---------- .../dbmigration/DefaultDbMigration.java | 3 +- .../platform/AbstractHanaDdl.java | 45 ++++++++-------- .../platform/HanaHistoryDdl.java | 35 ++++++------- .../ddlgeneration/platform/HanaTableDdl.java | 6 +-- .../server/core/DatabasePlatformFactory.java | 2 +- .../expression/platform/HanaDbExpression.java | 3 +- 7 files changed, 67 insertions(+), 78 deletions(-) diff --git a/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java index f266bb931..3e06d0094 100644 --- a/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/hana/HanaPlatform.java @@ -11,13 +11,26 @@ import io.ebean.config.dbplatform.IdType; import io.ebean.config.dbplatform.SqlErrorCodes; public class HanaPlatform extends DatabasePlatform { + public HanaPlatform() { - this.basicSqlLimiter = new HanaBasicSqlLimiter(); - + this.platform = Platform.HANA; + this.sqlLimiter = new HanaSqlLimiter(); + this.persistBatchOnCascade = PersistBatch.NONE; + this.supportsResultSetConcurrencyModeUpdatable = false; this.columnAliasPrefix = null; + this.historySupport = new HanaHistorySupport(); + this.basicSqlLimiter = new HanaBasicSqlLimiter(); + + this.likeClauseRaw = "like ?"; + this.maxConstraintNameLength = 127; + this.maxTableNameLength = 127; + this.dbDefaultValue.setNow("current_timestamp"); + this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("131", "133", "146") + .addDataIntegrity("130", "429", "461", "462").addDuplicateKey("144", "301", "349").build(); + this.dbIdentity.setIdType(IdType.IDENTITY); this.dbIdentity.setSelectLastInsertedIdTemplate("select current_identity_value() from sys.dummy"); this.dbIdentity.setSupportsGetGeneratedKeys(false); @@ -44,24 +57,6 @@ public class HanaPlatform extends DatabasePlatform { this.dbTypeMap.put(DbType.UUID, new DbPlatformType("varchar", 40)); this.dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255)); this.dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255)); - - this.exceptionTranslator = new SqlErrorCodes().addAcquireLock("131", "133", "146") - .addDataIntegrity("130", "429", "461", "462").addDuplicateKey("144", "301", "349").build(); - - this.historySupport = new HanaHistorySupport(); - - this.likeClauseRaw = "like ?"; - - this.maxConstraintNameLength = 127; - this.maxTableNameLength = 127; - - this.persistBatchOnCascade = PersistBatch.NONE; - - this.platform = Platform.HANA; - - this.sqlLimiter = new HanaSqlLimiter(); - - this.supportsResultSetConcurrencyModeUpdatable = false; } @Override @@ -77,14 +72,14 @@ public class HanaPlatform extends DatabasePlatform { @Override protected String withForUpdate(String sql, ForUpdate forUpdateMode) { switch (forUpdateMode) { - case BASE: - return sql + " for update"; - case NOWAIT: - return sql + " for update nowait"; - case SKIPLOCKED: - return sql + " for update ignore locked"; - default: - throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name()); + case BASE: + return sql + " for update"; + case NOWAIT: + return sql + " for update nowait"; + case SKIPLOCKED: + return sql + " for update ignore locked"; + default: + throw new IllegalArgumentException("Unknown update mode: " + forUpdateMode.name()); } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index 19817a924..5ae428a10 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -266,6 +266,7 @@ public class DefaultDbMigration implements DbMigration { * migration.generateMigration(); * * } + * * @return the generated migration or null */ @Override @@ -681,7 +682,7 @@ public class DefaultDbMigration implements DbMigration { case SQLITE: return new SQLitePlatform(); case HANA: - return new HanaPlatform(); + return new HanaPlatform(); case GENERIC: return new DatabasePlatform(); diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java index b898c02a6..cd3b580b3 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/AbstractHanaDdl.java @@ -1,10 +1,5 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; -import java.io.IOException; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import io.ebean.config.ServerConfig; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DbPlatformType; @@ -12,10 +7,14 @@ import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlHandler; import io.ebeaninternal.dbmigration.migration.AlterColumn; +import java.io.IOException; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public abstract class AbstractHanaDdl extends PlatformDdl { - private static final Pattern ARRAY_PATTERN = Pattern.compile("(\\w+)\\s*\\[\\s*\\]\\s*(\\(\\d+\\))?", - Pattern.CASE_INSENSITIVE); + private static final Pattern ARRAY_PATTERN = Pattern.compile("(\\w+)\\s*\\[\\s*\\]\\s*(\\(\\d+\\))?", Pattern.CASE_INSENSITIVE); public AbstractHanaDdl(DatabasePlatform platform) { super(platform); @@ -50,7 +49,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl { boolean notnull = (alter.isNotnull() != null) ? alter.isNotnull() : Boolean.TRUE.equals(alter.isCurrentNotnull()); String notnullClause = notnull ? " not null" : ""; String defaultValue = DdlHelp.isDropDefault(alter.getDefaultValue()) ? "null" - : (alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue()); + : (alter.getDefaultValue() != null ? alter.getDefaultValue() : alter.getCurrentDefaultValue()); String defaultValueClause = (defaultValue == null || defaultValue.isEmpty()) ? "" : " default " + defaultValue; try { @@ -60,18 +59,19 @@ public abstract class AbstractHanaDdl extends PlatformDdl { if (isNumberType(currentType)) { // numbers can always be converted to decimal buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) - .append(" decimal ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) - .endOfStatement(); + .append(" decimal ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) + .endOfStatement(); + } else if (isStringType(currentType)) { // strings can always be converted to nclob buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) - .append(" nclob ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) - .endOfStatement(); + .append(" nclob ").append(defaultValueClause).append(notnullClause).append(alterColumnSuffix) + .endOfStatement(); } } buffer.append("alter table ").append(tableName).append(" ").append(alterColumn).append(" ").append(columnName) - .append(" ").append(type).append(defaultValueClause).append(notnullClause).append(alterColumnSuffix); + .append(" ").append(type).append(defaultValueClause).append(notnullClause).append(alterColumnSuffix); return buffer.getBuffer(); } catch (IOException e) { @@ -110,8 +110,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl { } @Override - public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, - String[] nullableColumns) { + public String alterTableAddUniqueConstraint(String tableName, String uqName, String[] columns, String[] nullableColumns) { if (nullableColumns == null || nullableColumns.length == 0) { return super.alterTableAddUniqueConstraint(tableName, uqName, columns, nullableColumns); } else { @@ -128,7 +127,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl { buffer.append("begin").newLine(); buffer.append("declare exit handler for sql_error_code 397 begin end").endOfStatement(); buffer.append("exec 'alter table ").append(tableName).append(" ").append(dropUniqueConstraint).append(" ") - .append(maxConstraintName(uniqueConstraintName)).append("'").endOfStatement(); + .append(maxConstraintName(uniqueConstraintName)).append("'").endOfStatement(); buffer.append("end").endOfStatement(); buffer.append("$$"); return buffer.getBuffer(); @@ -136,7 +135,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl { throw new RuntimeException(e); } } - + @Override public String alterTableDropConstraint(String tableName, String constraintName) { return alterTableDropUniqueConstraint(tableName, constraintName); @@ -149,13 +148,13 @@ public abstract class AbstractHanaDdl extends PlatformDdl { @Override public void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException { buffer.append("CALL usp_ebean_drop_column('").append(tableName).append("', '").append(columnName).append("')") - .endOfStatement(); + .endOfStatement(); } /** * Check if a data type can be converted to another data type. Data types can't * be converted if the target type has a lower precision than the source type. - * + * * @param sourceType The source data type * @param targetType the target data type * @return {@code true} if the type can be converted, {@code false} otherwise @@ -204,7 +203,7 @@ public abstract class AbstractHanaDdl extends PlatformDdl { DbPlatformType dbPlatformTargetType = DbPlatformType.parse(targetType); if ("decimal".equals(dbPlatformTargetType.getName())) { if (dbPlatformSourceType.getDefaultLength() > dbPlatformTargetType.getDefaultLength() - || dbPlatformSourceType.getDefaultScale() > dbPlatformTargetType.getDefaultScale()) { + || dbPlatformSourceType.getDefaultScale() > dbPlatformTargetType.getDefaultScale()) { return false; } } @@ -215,12 +214,12 @@ public abstract class AbstractHanaDdl extends PlatformDdl { private boolean isNumberType(String type) { return type != null - && ("bigint".equals(type) || "integer".equals(type) || "smallint".equals(type) || "tinyint".equals(type) - || type.startsWith("float") || "real".equals(type) || "double".equals(type) || type.startsWith("decimal")); + && ("bigint".equals(type) || "integer".equals(type) || "smallint".equals(type) || "tinyint".equals(type) + || type.startsWith("float") || "real".equals(type) || "double".equals(type) || type.startsWith("decimal")); } private boolean isStringType(String type) { return type != null - && (type.startsWith("varchar") || type.startsWith("nvarchar") || "clob".equals(type) || "nclob".equals(type)); + && (type.startsWith("varchar") || type.startsWith("nvarchar") || "clob".equals(type) || "nclob".equals(type)); } } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java index 0ea165ba3..9fd37416f 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaHistoryDdl.java @@ -1,11 +1,5 @@ package io.ebeaninternal.dbmigration.ddlgeneration.platform; -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; - import io.ebean.config.ServerConfig; import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; @@ -14,6 +8,12 @@ import io.ebeaninternal.dbmigration.migration.DropHistoryTable; import io.ebeaninternal.dbmigration.model.MColumn; import io.ebeaninternal.dbmigration.model.MTable; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; + public class HanaHistoryDdl implements PlatformHistoryDdl { private String systemPeriodStart; @@ -47,7 +47,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { for (MColumn column : cols) { if (!column.isDraftOnly()) { writeColumnDefinition(apply, column.getName(), column.getType(), column.getDefaultValue(), column.isNotnull(), - column.isIdentity() ? platformDdl.identitySuffix : null); + column.isIdentity() ? platformDdl.identitySuffix : null); apply.append(",").newLine(); } } @@ -58,13 +58,12 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { // enable system versioning apply.append("alter table ").append(tableName).append(" add (").newLine(); - apply.append(" ").append(systemPeriodStart).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, ") - .newLine(); + apply.append(" ").append(systemPeriodStart).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW START, ").newLine(); apply.append(" ").append(systemPeriodEnd).append(" TIMESTAMP NOT NULL GENERATED ALWAYS AS ROW END").newLine(); apply.append(")").endOfStatement(); apply.append("alter table ").append(tableName).append(" add period for system_time(").append(systemPeriodStart) - .append(",").append(systemPeriodEnd).append(")").endOfStatement(); + .append(",").append(systemPeriodEnd).append(")").endOfStatement(); enableSystemVersioning(apply, tableName, historyTableName, true, false); @@ -76,7 +75,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { @Override public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException { dropHistoryTable(writer.applyDropDependencies(), dropHistoryTable.getBaseTable(), - dropHistoryTable.getBaseTable() + historySuffix); + dropHistoryTable.getBaseTable() + historySuffix); } protected void dropHistoryTable(DdlBuffer apply, String baseTable, String historyTable) throws IOException { @@ -87,7 +86,7 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { // drop the period columns apply.append("alter table ").append(baseTable).append(" drop (").append(systemPeriodStart).append(",") - .append(systemPeriodEnd).append(")").endOfStatement(); + .append(systemPeriodEnd).append(")").endOfStatement(); // drop the history table apply.append("drop table ").append(historyTable).append(" cascade").endOfStatement(); @@ -97,19 +96,18 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException { MTable table = writer.getTable(addHistoryTable.getBaseTable()); if (table == null) { - throw new IllegalStateException( - "MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)"); + throw new IllegalStateException("MTable " + addHistoryTable.getBaseTable() + " not found in writer? (required for history DDL)"); } createWithHistory(writer, table); } @Override - public void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) throws IOException { + public void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) { // nothing to do } protected void writeColumnDefinition(DdlBuffer buffer, String columnName, String type, String defaultValue, - boolean isNotNull, String generated) throws IOException { + boolean isNotNull, String generated) throws IOException { String platformType = platformDdl.convert(type, false); buffer.append(" ").append(platformDdl.lowerColumnName(columnName)); @@ -140,9 +138,8 @@ public class HanaHistoryDdl implements PlatformHistoryDdl { } public void enableSystemVersioning(DdlBuffer apply, String tableName, String historyTableName, boolean validated, - boolean uniqueStatement) throws IOException { - apply.append("alter table ").append(tableName).append(" add system versioning history table ") - .append(historyTableName); + boolean uniqueStatement) throws IOException { + apply.append("alter table ").append(tableName).append(" add system versioning history table ").append(historyTableName); if (!validated) { apply.append(" not validated"); } diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java index 1d0b47abc..943dc3ecd 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java +++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/HanaTableDdl.java @@ -21,8 +21,7 @@ public class HanaTableDdl extends BaseTableDdl { super(serverConfig, platformDdl); this.historyDdl = (HanaHistoryDdl) platformDdl.historyDdl; if (serverConfig.getProperties() != null) { - PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "hana", serverConfig.getProperties(), - serverConfig.getClassLoadConfig()); + PropertiesWrapper wrapper = new PropertiesWrapper("ebean", "hana", serverConfig.getProperties(), serverConfig.getClassLoadConfig()); this.generateUniqueDdl = wrapper.getBoolean("generateUniqueDdl", false); } else { this.generateUniqueDdl = false; @@ -86,8 +85,7 @@ public class HanaTableDdl extends BaseTableDdl { if (manageSystemVersioning) { // make same changes to the history table String historyTable = historyTable(tableName); - if (hasValue(alterColumn.getType()) || hasValue(alterColumn.getDefaultValue()) - || alterColumn.isNotnull() != null) { + if (hasValue(alterColumn.getType()) || hasValue(alterColumn.getDefaultValue()) || alterColumn.isNotnull() != null) { AlterColumn alterHistoryColumn = new AlterColumn(); alterHistoryColumn.setTableName(historyTable); alterHistoryColumn.setColumnName(alterColumn.getColumnName()); diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index acf955620..b5a5b6ef5 100644 --- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -160,7 +160,7 @@ public class DatabasePlatformFactory { return new DB2Platform(); } else if (dbProductName.contains("sql anywhere")) { return new SqlAnywherePlatform(); - }else if (dbProductName.contains("hdb")) { + } else if (dbProductName.contains("hdb")) { return new HanaPlatform(); } diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java index 0593bdb84..a6633edfa 100644 --- a/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java +++ b/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java @@ -10,8 +10,7 @@ import io.ebeaninternal.server.expression.Op; public class HanaDbExpression extends BaseDbExpression { @Override - public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, - long match) { + public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { bitwiseFunction(request, propName, operator, compare); } From d185ea5962f3f3da94124af7f5afcdf6fcc69106 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 22:12:42 +1300 Subject: [PATCH 0501/1036] Updated db migration test for mysql --- .../dbmigration/migrationtest/mysql/1.4__dropsFor_1.3.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/dbmigration/migrationtest/mysql/1.4__dropsFor_1.3.sql b/src/test/resources/dbmigration/migrationtest/mysql/1.4__dropsFor_1.3.sql index 7d2ef6bec..efa0bbc8a 100644 --- a/src/test/resources/dbmigration/migrationtest/mysql/1.4__dropsFor_1.3.sql +++ b/src/test/resources/dbmigration/migrationtest/mysql/1.4__dropsFor_1.3.sql @@ -3,8 +3,8 @@ drop trigger migtest_e_history_history_upd; drop trigger migtest_e_history_history_del; drop view migtest_e_history_with_history; -alter table migtest_e_history drop column sys_period_start; -alter table migtest_e_history drop column sys_period_end; +CALL usp_ebean_drop_column('migtest_e_history', 'sys_period_start'); +CALL usp_ebean_drop_column('migtest_e_history', 'sys_period_end'); drop table migtest_e_history_history; drop view if exists migtest_e_history2_with_history; From 1d1d479ddab11485ab30d2b0208beaadfa2545d3 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 22:17:44 +1300 Subject: [PATCH 0502/1036] Fix concat_expectString test with explicit cast to string --- .../java/org/tests/query/aggregation/TestAggregationCount.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java index cbd55510e..fc578780e 100644 --- a/src/test/java/org/tests/query/aggregation/TestAggregationCount.java +++ b/src/test/java/org/tests/query/aggregation/TestAggregationCount.java @@ -406,7 +406,7 @@ public class TestAggregationCount extends BaseTestCase { List names = Ebean.find(Contact.class) - .select(concat("updtime",", ","firstName")) + .select(concat("updtime",", ","firstName")+"::String") .where().isNull("phone") .orderBy().asc("lastName") .findSingleAttributeList(); From 156469ae0fd49d13849473d605189cfa5722e1d7 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 22:59:48 +1300 Subject: [PATCH 0503/1036] Update tests for running MySql --- .../org/tests/model/history/HsdSetting.java | 24 +++++++++--------- .../TestQuotedIdentifierQuery.java | 25 ++++++++++++++----- .../tests/softdelete/TestSoftDeleteBasic.java | 4 +-- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/test/java/org/tests/model/history/HsdSetting.java b/src/test/java/org/tests/model/history/HsdSetting.java index 26cfc30d9..c315110e0 100644 --- a/src/test/java/org/tests/model/history/HsdSetting.java +++ b/src/test/java/org/tests/model/history/HsdSetting.java @@ -11,8 +11,8 @@ import javax.persistence.OneToOne; @Entity public class HsdSetting extends BaseDomain { - String key; - String val; + String code; + String content; @SoftDelete boolean deleted; @@ -21,27 +21,27 @@ public class HsdSetting extends BaseDomain { private HsdUser user; - public HsdSetting(String key) { - this.key = key; + public HsdSetting(String code) { + this.code = code; } public HsdSetting() { } - public String getKey() { - return key; + public String getCode() { + return code; } - public void setKey(String key) { - this.key = key; + public void setCode(String code) { + this.code = code; } - public String getVal() { - return val; + public String getContent() { + return content; } - public void setVal(String val) { - this.val = val; + public void setContent(String content) { + this.content = content; } public boolean isDeleted() { diff --git a/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java b/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java index 90f6b3be8..caf230efc 100644 --- a/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java +++ b/src/test/java/org/tests/quotedidentifier/TestQuotedIdentifierQuery.java @@ -16,11 +16,24 @@ public class TestQuotedIdentifierQuery extends BaseTestCase { Ebean.save(bean); - Ebean.find(BWithQIdent.class) - .where() - .eq("name", "foo") - .raw("t0.\"Name\" = ?", "foo") - .raw("t0.\"CODE\" = ?", "bar") - .findList(); + if (isMySql()) { + + Ebean.find(BWithQIdent.class) + .where() + .eq("name", "foo") + .raw("t0.`Name` = ?", "foo") + .raw("t0.`CODE` = ?", "bar") + .findList(); + + } else if (isH2() || isPostgres()) { + + Ebean.find(BWithQIdent.class) + .where() + .eq("name", "foo") + .raw("t0.\"Name\" = ?", "foo") + .raw("t0.\"CODE\" = ?", "bar") + .findList(); + + } } } diff --git a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java index 6240c49cd..9058195dc 100644 --- a/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java +++ b/src/test/java/org/tests/softdelete/TestSoftDeleteBasic.java @@ -79,8 +79,8 @@ public class TestSoftDeleteBasic extends BaseTestCase { List sql = LoggedSqlCollector.stop(); assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = false"); - assertThat(sql.get(1)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = false"); + assertThat(sql.get(0)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = "); + assertThat(sql.get(1)).contains("from ebasic_sdchild t0 where t0.owner_id = ? and t0.deleted = "); } @Test From e06967ff4a60fef40149753ddc0e2595dcb12318 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 23:25:48 +1300 Subject: [PATCH 0504/1036] #1512 - Invalid SQL with Postgres + order by nulls first/last + where() expression on ManyToMany --- src/main/java/io/ebeaninternal/server/query/DbOrderByTrim.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/ebeaninternal/server/query/DbOrderByTrim.java b/src/main/java/io/ebeaninternal/server/query/DbOrderByTrim.java index 2edfe488b..5865da349 100644 --- a/src/main/java/io/ebeaninternal/server/query/DbOrderByTrim.java +++ b/src/main/java/io/ebeaninternal/server/query/DbOrderByTrim.java @@ -4,7 +4,7 @@ import java.util.regex.Pattern; class DbOrderByTrim { - private static final Pattern orderByTrim = Pattern.compile("(?i)\\b asc\\b|\\b desc\\b"); + private static final Pattern orderByTrim = Pattern.compile("(?i)\\b asc\\b|\\b desc\\b|\\b nulls first\\b|\\b nulls last\\b"); /** * Convert the dbOrderBy clause to be safe for adding to select or distinct on. From c1a479e1f467fa1a38434d7e16a1df78b7d5a6af Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 23:26:19 +1300 Subject: [PATCH 0505/1036] #1512 - Invalid SQL with Postgres + order by nulls first/last + where() expression on ManyToMany --- .../server/query/SqlTreeBuilderTest.java | 37 ++++++++++--------- .../orderby/TestOrderByWithDistinct.java | 21 +++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/test/java/io/ebeaninternal/server/query/SqlTreeBuilderTest.java b/src/test/java/io/ebeaninternal/server/query/SqlTreeBuilderTest.java index 7b8232ba6..2c5beb403 100644 --- a/src/test/java/io/ebeaninternal/server/query/SqlTreeBuilderTest.java +++ b/src/test/java/io/ebeaninternal/server/query/SqlTreeBuilderTest.java @@ -7,57 +7,58 @@ import static org.junit.Assert.*; public class SqlTreeBuilderTest { @Test - public void mergeOnDistinct_equal() throws Exception { - + public void mergeOnDistinct_equal() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.id"), "t0.id"); } @Test - public void mergeOnDistinct_add() throws Exception { - + public void mergeOnDistinct_add() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre"), "t0.cre, t0.id"); } @Test - public void mergeOnDistinct_contained() throws Exception { - + public void mergeOnDistinct_contained() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre, t0.id"), "t0.cre, t0.id"); } @Test - public void mergeOnDistinct_overlap() throws Exception { - + public void mergeOnDistinct_overlap() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id, t1.id", "t0.cre, t0.id"), "t0.cre, t0.id, t1.id"); } @Test - public void mergeOnDistinct_overlapBoth() throws Exception { - + public void mergeOnDistinct_overlapBoth() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id, t1.id", "t0.cre, t1.id, t0.id"), "t0.cre, t1.id, t0.id"); } @Test - public void mergeOnDistinct_inlineAscDesc() throws Exception { - + public void mergeOnDistinct_inlineAscDesc() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre asc, t1.bb desc, t3.b"), "t0.cre, t1.bb, t3.b, t0.id"); } @Test - public void mergeOnDistinct_inlineAscDesc2() throws Exception { - + public void mergeOnDistinct_inlineAscDesc2() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre desc, t1.bb asc, t3.b"), "t0.cre, t1.bb, t3.b, t0.id"); } @Test - public void mergeOnDistinct_trailingAsc() throws Exception { - + public void mergeOnDistinct_trailingAsc() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre asc"), "t0.cre, t0.id"); } @Test - public void mergeOnDistinct_trailingDesc() throws Exception { - + public void mergeOnDistinct_trailingDesc() { assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre desc"), "t0.cre, t0.id"); } + @Test + public void mergeOnDistinct_trailingDescNullsFirst() { + assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre desc nulls first"), "t0.cre, t0.id"); + } + + @Test + public void mergeOnDistinct_trailingDescNullsLast() { + assertEquals(SqlTreeBuilder.mergeOnDistinct("t0.id", "t0.cre desc nulls last"), "t0.cre, t0.id"); + } + } diff --git a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java index 2090a0566..9d2ece465 100644 --- a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java +++ b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java @@ -37,6 +37,27 @@ public class TestOrderByWithDistinct extends BaseTestCase { } + @Test + public void testDistinctOn() { + + MRole role = Ebean.getReference(MRole.class, 1); + + Query query = Ebean.find(MUser.class) + .where() + .eq("roles", role) + .orderBy("userName asc nulls first"); + + query.findList(); + + String sql = sqlOf(query); + if (isPostgres()) { + assertThat(sql).contains("select distinct on (t0.user_name, t0.userid) t0.userid,"); + } else if (isH2()) { + assertThat(sql).contains("select distinct t0.userid, t0.user_name, t0.user_type_id,"); + } + + } + @Test public void testOrderByWithDistinct() { From 6909b20a9e6ce2f96fce374927a321c5242bf00c Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 24 Oct 2018 23:31:07 +1300 Subject: [PATCH 0506/1036] #1510 - Tidy DbMigrationConfig removing the properties that should only be with DbMigration generation (#1513) --- .../io/ebean/config/DbMigrationConfig.java | 125 ------------------ .../dbmigration/DefaultDbMigration.java | 82 +++++++++--- 2 files changed, 64 insertions(+), 143 deletions(-) diff --git a/src/main/java/io/ebean/config/DbMigrationConfig.java b/src/main/java/io/ebean/config/DbMigrationConfig.java index d09f3430a..cdbb3a416 100644 --- a/src/main/java/io/ebean/config/DbMigrationConfig.java +++ b/src/main/java/io/ebean/config/DbMigrationConfig.java @@ -28,34 +28,6 @@ public class DbMigrationConfig { */ protected Platform platform; - /** - * Set to true if the DB migration should be generated on server start. - */ - protected boolean generate; - - /** - * The migration version name (typically FlywayDb compatible). - *

    - * Example: 1.1.1_2 - *

    - * The version is expected to be the combination of the current pom version plus - * a 'feature' id. The combined version must be unique and ordered to work with - * FlywayDb so each developer sets a unique version so that the migration script - * generated is unique (typically just prior to being submitted as a merge request). - */ - protected String version; - - /** - * Description text that can be appended to the version to become the ddl script file name. - *

    - * So if the name is "a foo table" then the ddl script file could be: - * "1.1.1_2__a-foo-table.sql" - *

    - * When the DB migration relates to a git feature (merge request) then this description text - * is a short description of the feature. - */ - protected String name; - /** * Resource path for the migration xml and sql. */ @@ -75,13 +47,6 @@ public class DbMigrationConfig { protected String modelSuffix = ".model.xml"; - protected boolean includeGeneratedFileComment; - - /** - * The version of a pending drop that should be generated as the next migration. - */ - protected String generatePendingDrop; - /** * For running migration the DB table that holds migration execution status. */ @@ -228,52 +193,6 @@ public class DbMigrationConfig { this.applyPrefix = applyPrefix; } - /** - * Return true if the generated file comment should be included. - */ - public boolean isIncludeGeneratedFileComment() { - return includeGeneratedFileComment; - } - - /** - * Set to true if the generated file comment should be included. - */ - public void setIncludeGeneratedFileComment(boolean includeGeneratedFileComment) { - this.includeGeneratedFileComment = includeGeneratedFileComment; - } - - /** - * Return the migration version (or "next") to generate pending drops for. - */ - public String getGeneratePendingDrop() { - return generatePendingDrop; - } - - /** - * Set the migration version (or "next") to generate pending drops for. - */ - public void setGeneratePendingDrop(String generatePendingDrop) { - this.generatePendingDrop = generatePendingDrop; - } - - /** - * Set the migration version. - *

    - * Note that version set via System property or environment variable ddl.migration.version takes precedence. - */ - public void setVersion(String version) { - this.version = version; - } - - /** - * Set the migration name. - *

    - * Note that name set via System property or environment variable ddl.migration.name takes precedence. - */ - public void setName(String name) { - this.name = name; - } - /** * Return the table name that holds the migration run details * (used by DB Migration runner only). @@ -504,14 +423,8 @@ public class DbMigrationConfig { applyPrefix = properties.get("migration.applyPrefix", applyPrefix); applySuffix = properties.get("migration.applySuffix", applySuffix); modelSuffix = properties.get("migration.modelSuffix", modelSuffix); - includeGeneratedFileComment = properties.getBoolean("migration.includeGeneratedFileComment", includeGeneratedFileComment); - generatePendingDrop = properties.get("migration.generatePendingDrop", generatePendingDrop); platform = properties.getEnum(Platform.class, "migration.platform", platform); - - generate = properties.getBoolean("migration.generate", generate); - version = properties.get("migration.version", version); - name = properties.get("migration.name", name); patchInsertOn = properties.get("migration.patchInsertOn", patchInsertOn); patchResetChecksumOn = properties.get("migration.patchResetChecksumOn", patchResetChecksumOn); @@ -532,44 +445,6 @@ public class DbMigrationConfig { ddlHeader = properties.get("ddl.header", ddlHeader); } - /** - * Return the migration version (typically FlywayDb compatible). - *

    - * Example: 1.1.1_2 - *

    - * The version is expected to be the combination of the current pom version plus - * a 'feature' id. The combined version must be unique and ordered to work with - * FlywayDb so each developer sets a unique version so that the migration script - * generated is unique (typically just prior to being submitted as a merge request). - */ - public String getVersion() { - String envVersion = readEnvironment("ddl.migration.version"); - if (!isEmpty(envVersion)) { - return envVersion.trim(); - } - return version; - } - - /** - * Return the migration name which is short description text that can be appended to - * the migration version to become the ddl script file name. - *

    - * So if the name is "a foo table" then the ddl script file could be: - * "1.1.1_2__a-foo-table.sql" - *

    - *

    - * When the DB migration relates to a git feature (merge request) then this description text - * is a short description of the feature. - *

    - */ - public String getName() { - String envName = readEnvironment("ddl.migration.name"); - if (!isEmpty(envName)) { - return envName.trim(); - } - return name; - } - /** * Return the system or environment property. */ diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index 5ae428a10..2eced70a2 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -58,7 +58,7 @@ import java.util.List; * * DbMigration migration = DbMigration.create(); * migration.setPathToResources("src/main/resources"); - * migration.setPlatform(DbPlatformName.ORACLE); + * migration.setPlatform(Platform.POSTGRES); * * migration.generateMigration(); * @@ -513,10 +513,7 @@ public class DefaultDbMigration implements DbMigration { if (nextDrop != null) { return nextDrop; } - if (generatePendingDrop != null) { - return generatePendingDrop; - } - return migrationConfig.getGeneratePendingDrop(); + return generatePendingDrop; } /** @@ -526,14 +523,15 @@ public class DefaultDbMigration implements DbMigration { */ private String getFullVersion(MigrationModel migrationModel, String dropsFor) { - String version = migrationConfig.getVersion(); + String version = getVersion(); if (version == null) { version = migrationModel.getNextVersion(initialVersion); } String fullVersion = migrationConfig.getApplyPrefix() + version; - if (migrationConfig.getName() != null) { - fullVersion += "__" + toUnderScore(migrationConfig.getName()); + String name = getName(); + if (name != null) { + fullVersion += "__" + toUnderScore(name); } else if (dropsFor != null) { fullVersion += "__" + toUnderScore("dropsFor_" + MigrationVersion.trim(dropsFor)); @@ -580,7 +578,7 @@ public class DefaultDbMigration implements DbMigration { if (file.exists()) { return false; } - String comment = migrationConfig.isIncludeGeneratedFileComment() ? GENERATED_COMMENT : null; + String comment = Boolean.TRUE.equals(includeGeneratedFileComment) ? GENERATED_COMMENT : null; MigrationXmlWriter xmlWriter = new MigrationXmlWriter(comment); xmlWriter.write(dbMigration, file); return true; @@ -608,18 +606,66 @@ public class DefaultDbMigration implements DbMigration { if (header != null) { migrationConfig.setDdlHeader(header); } - if (includeGeneratedFileComment != null) { - migrationConfig.setIncludeGeneratedFileComment(includeGeneratedFileComment); - } - if (version != null) { - migrationConfig.setVersion(version); - } - if (name != null) { - migrationConfig.setName(name); - } } } + /** + * Return the migration version (typically FlywayDb compatible). + *

    + * Example: 1.1.1_2 + *

    + * The version is expected to be the combination of the current pom version plus + * a 'feature' id. The combined version must be unique and ordered to work with + * FlywayDb so each developer sets a unique version so that the migration script + * generated is unique (typically just prior to being submitted as a merge request). + */ + private String getVersion() { + String envVersion = readEnvironment("ddl.migration.version"); + if (!isEmpty(envVersion)) { + return envVersion.trim(); + } + return version; + } + + /** + * Return the migration name which is short description text that can be appended to + * the migration version to become the ddl script file name. + *

    + * So if the name is "a foo table" then the ddl script file could be: + * "1.1.1_2__a-foo-table.sql" + *

    + *

    + * When the DB migration relates to a git feature (merge request) then this description text + * is a short description of the feature. + *

    + */ + private String getName() { + String envName = readEnvironment("ddl.migration.name"); + if (!isEmpty(envName)) { + return envName.trim(); + } + return name; + } + + /** + * Return true if the string is null or empty. + */ + private boolean isEmpty(String val) { + return val == null || val.trim().isEmpty(); + } + + /** + * Return the system or environment property. + */ + private String readEnvironment(String key) { + + String val = System.getProperty(key); + if (val == null) { + val = System.getenv(key); + } + return val; + } + /** * Return the file path to write the xml and sql to. */ From fef87323b383b6ef6ba58731cf05903045a266b3 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 23:49:26 +1300 Subject: [PATCH 0507/1036] Bump to 11.23.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c08c66ca6..ac8e674e8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.22.11-SNAPSHOT + 11.23.1-SNAPSHOT jar ebean From afcd6859e067146058ab1377d227b53d78da35f8 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 23:50:44 +1300 Subject: [PATCH 0508/1036] [maven-release-plugin] prepare release ebean-11.23.1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ac8e674e8..8a9d061ec 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.23.1-SNAPSHOT + 11.23.1 jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - HEAD + ebean-11.23.1 From bdc991781119d83cbb1d51d9f4be39d88d6aab3a Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Wed, 24 Oct 2018 23:51:00 +1300 Subject: [PATCH 0509/1036] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8a9d061ec..845fea9ae 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.23.1 + 11.23.2-SNAPSHOT jar ebean @@ -22,7 +22,7 @@ scm:git:git@github.com:ebean-orm/ebean.git - ebean-11.23.1 + HEAD From fecb5fa731552361087a428e399f086cb87eda75 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Wed, 24 Oct 2018 23:35:02 +0200 Subject: [PATCH 0510/1036] There should be only one "Rob" in o_customer (#1515) * FIX: CsvReader-Test * Fixes for tests * reversed changes * tidy TestCsvReaderWithCallback --- src/test/java/org/tests/basic/TestTransient.java | 2 +- src/test/resources/test1.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/tests/basic/TestTransient.java b/src/test/java/org/tests/basic/TestTransient.java index 70e560a1c..0652fd5e2 100644 --- a/src/test/java/org/tests/basic/TestTransient.java +++ b/src/test/java/org/tests/basic/TestTransient.java @@ -54,7 +54,7 @@ public class TestTransient extends BaseTestCase { selected = c.getSelected(); Assert.assertNotNull(selected); - String updateStmt = "update customer set name = 'Rob' where id = :id"; + String updateStmt = "update customer set name = 'testTrans2' where id = :id"; int rows = Ebean.createUpdate(Customer.class, updateStmt).set("id", custId).execute(); Assert.assertTrue("changed name back", 1 == rows); diff --git a/src/test/resources/test1.csv b/src/test/resources/test1.csv index b04efe79a..136964f46 100644 --- a/src/test/resources/test1.csv +++ b/src/test/resources/test1.csv @@ -1,4 +1,4 @@ -10000,NEW,"Rob",01-JAN-2009,"12 someplace",Auckland,NZ +10000,NEW,"Roland",01-JAN-2009,"12 someplace",Auckland,NZ ,ACTIVE,"Greg",14-FEB-2009,"13 someplace",Sydney,AU ,INACTIVE,"Dan",29-SEP-2009,"14 someplace",Auckland,NZ ,NEW,"ARob",01-JAN-2009,"12 someplace",Auckland,NZ From 939397acfce33185b911073cc48af06b475c5dbf Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Thu, 25 Oct 2018 11:11:36 +0200 Subject: [PATCH 0511/1036] Add support for JacksonAnnotations at bean-properties (#1514) --- .../deploy/meta/DeployBeanDescriptor.java | 15 +++ .../deploy/meta/DeployBeanProperty.java | 14 +++ .../server/deploy/parse/DeployUtil.java | 5 +- .../server/type/DefaultTypeManager.java | 37 ++++-- .../type/ScalarTypeJsonObjectMapper.java | 87 ++++++++++---- .../server/type/TypeManager.java | 3 +- .../org/tests/json/TestDbJson_Jackson.java | 113 ++++++++++++++++++ .../org/tests/json/TestDbJson_Jackson2.java | 62 ++++++++++ .../tests/model/json/BasicJacksonType.java | 15 +++ .../tests/model/json/EBasicJsonJackson.java | 101 ++++++++++++++++ .../tests/model/json/EBasicJsonJackson2.java | 98 +++++++++++++++ .../org/tests/model/json/LongJacksonType.java | 22 ++++ .../tests/model/json/StringJacksonType.java | 22 ++++ 13 files changed, 554 insertions(+), 40 deletions(-) create mode 100644 src/test/java/org/tests/json/TestDbJson_Jackson.java create mode 100644 src/test/java/org/tests/json/TestDbJson_Jackson2.java create mode 100644 src/test/java/org/tests/model/json/BasicJacksonType.java create mode 100644 src/test/java/org/tests/model/json/EBasicJsonJackson.java create mode 100644 src/test/java/org/tests/model/json/EBasicJsonJackson2.java create mode 100644 src/test/java/org/tests/model/json/LongJacksonType.java create mode 100644 src/test/java/org/tests/model/json/StringJacksonType.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 76a54220a..9f26a4f34 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -223,6 +223,8 @@ public class DeployBeanDescriptor { private short profileId; + private Object jacksonAnnotatedClass; + /** * Construct the BeanDescriptor. */ @@ -1238,6 +1240,7 @@ public class DeployBeanDescriptor { this.descriptor = descriptor; } + @Override public String getDeployWord(String expression) { return descriptor.getDeployWord(expression); } @@ -1252,4 +1255,16 @@ public class DeployBeanDescriptor { return (property == null) ? null : "${ta}." + property.getDbColumn(); } + /** + * Returns the jackson annotated class, if jackson is present. + */ + public Object /*AnnotatedClass*/ getJacksonAnnotatedClass() { + if (jacksonAnnotatedClass == null) { + com.fasterxml.jackson.databind.ObjectMapper objectMapper = (com.fasterxml.jackson.databind.ObjectMapper) serverConfig.getObjectMapper(); + com.fasterxml.jackson.databind.JavaType javaType = objectMapper.getTypeFactory().constructType(beanType); + jacksonAnnotatedClass = com.fasterxml.jackson.databind.introspect.AnnotatedClassResolver + .resolve(objectMapper.getDeserializationConfig(), javaType, objectMapper.getDeserializationConfig()); + } + return jacksonAnnotatedClass; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 0bfa5b328..4b38812d5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -1124,4 +1124,18 @@ public class DeployBeanProperty { public void setElementProperty() { this.elementProperty = true; } + + /** + * Returns the jackson annotated field, if jackson is present. + */ + public Object /*AnnotatedField*/ getJacksonField() { + com.fasterxml.jackson.databind.introspect.AnnotatedClass jac = + (com.fasterxml.jackson.databind.introspect.AnnotatedClass) getDesc().getJacksonAnnotatedClass(); + for (com.fasterxml.jackson.databind.introspect.AnnotatedField candidate : jac.fields()) { + if (candidate.getName().equals(getName())) { + return candidate; + } + } + return null; + } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java index 83ed5eb21..303135e91 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/DeployUtil.java @@ -239,10 +239,9 @@ public class DeployUtil { private void setDbJsonType(DeployBeanProperty prop, int dbType, int dbLength) { - Class type = prop.getPropertyType(); - ScalarType scalarType = typeManager.getJsonScalarType(type, dbType, dbLength, prop.getGenericType()); + ScalarType scalarType = typeManager.getJsonScalarType(prop, dbType, dbLength); if (scalarType == null) { - throw new RuntimeException("No ScalarType for JSON type [" + type + "] [" + dbType + "]"); + throw new RuntimeException("No ScalarType for JSON property [" + prop + "] [" + dbType + "]"); } prop.setDbType(dbType); prop.setScalarType(scalarType); diff --git a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java index d6fb20e33..896391ff5 100644 --- a/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/DefaultTypeManager.java @@ -2,6 +2,8 @@ package io.ebeaninternal.server.type; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.AnnotatedField; + import io.ebean.annotation.DbArray; import io.ebean.annotation.DbEnumType; import io.ebean.annotation.DbEnumValue; @@ -17,6 +19,7 @@ import io.ebean.util.AnnotationUtil; import io.ebeaninternal.api.ExtraTypeFactory; import io.ebeaninternal.dbmigration.DbOffline; import io.ebeaninternal.server.core.bootup.BootupClasses; +import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import io.ebeanservice.docstore.api.mapping.DocPropertyType; import org.joda.time.DateTime; import org.joda.time.LocalDate; @@ -379,31 +382,36 @@ public final class DefaultTypeManager implements TypeManager { } @Override - public ScalarType getJsonScalarType(Class type, int dbType, int dbLength, Type genericType) { + public ScalarType getJsonScalarType(DeployBeanProperty prop, int dbType, int dbLength) { + + Class type = prop.getPropertyType(); + Type genericType = prop.getGenericType(); + + boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop); if (type.equals(List.class)) { DocPropertyType docType = getDocType(genericType); - if (isValueTypeSimple(genericType)) { + if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) { return ScalarTypeJsonList.typeFor(postgres, dbType, docType); } else { - return createJsonObjectMapperType(type, genericType, dbType, docType); + return createJsonObjectMapperType(prop, dbType, docType); } } if (type.equals(Set.class)) { DocPropertyType docType = getDocType(genericType); - if (isValueTypeSimple(genericType)) { + if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) { return ScalarTypeJsonSet.typeFor(postgres, dbType, docType); } else { - return createJsonObjectMapperType(type, genericType, dbType, docType); + return createJsonObjectMapperType(prop, dbType, docType); } } if (type.equals(Map.class)) { - if (isMapValueTypeObject(genericType)) { + if (!hasJacksonAnnotations && isMapValueTypeObject(genericType)) { return ScalarTypeJsonMap.typeFor(postgres, dbType); } else { - return createJsonObjectMapperType(type, genericType, dbType, DocPropertyType.OBJECT); + return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT); } } @@ -426,7 +434,15 @@ public final class DefaultTypeManager implements TypeManager { } } - return createJsonObjectMapperType(type, type, dbType, DocPropertyType.OBJECT); + return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT); + } + + /** + * Returns TRUE, if there is any jackson annotation on that property. All jackson annotations + * are annotated with the @JacksonAnnotation meta annotation. So detection is easy. + */ + private boolean checkJacksonAnnotations(DeployBeanProperty prop) { + return AnnotationUtil.findAnnotation(prop.getField(), com.fasterxml.jackson.annotation.JacksonAnnotation.class) != null; } private DocPropertyType getDocType(Type genericType) { @@ -459,11 +475,12 @@ public final class DefaultTypeManager implements TypeManager { return Object.class.equals(typeArgs[1]) || "?".equals(typeArgs[1].toString()); } - private ScalarType createJsonObjectMapperType(Class type, Type genericType, int dbType, DocPropertyType docType) { + private ScalarType createJsonObjectMapperType(DeployBeanProperty prop, int dbType, DocPropertyType docType) { + Class type = prop.getPropertyType(); if (objectMapper == null) { throw new IllegalArgumentException("Type [" + type + "] unsupported for @DbJson mapping - Jackson ObjectMapper not present"); } - return ScalarTypeJsonObjectMapper.createTypeFor(postgres, type, (ObjectMapper) objectMapper, genericType, dbType, docType); + return ScalarTypeJsonObjectMapper.createTypeFor(postgres, (AnnotatedField) prop.getJacksonField(), (ObjectMapper) objectMapper, dbType, docType); } /** diff --git a/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java b/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java index eda46122a..91c1e1c9b 100644 --- a/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java +++ b/src/main/java/io/ebeaninternal/server/type/ScalarTypeJsonObjectMapper.java @@ -9,14 +9,19 @@ import io.ebeanservice.docstore.api.mapping.DocPropertyType; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.introspect.AnnotatedField; import javax.persistence.PersistenceException; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import java.lang.reflect.Type; import java.sql.SQLException; import java.sql.Types; import java.util.List; @@ -31,20 +36,21 @@ public class ScalarTypeJsonObjectMapper { /** * Create and return the appropriate ScalarType. */ - public static ScalarType createTypeFor(boolean postgres, Class type, ObjectMapper objectMapper, - Type genericType, int dbType, DocPropertyType docType) { + public static ScalarType createTypeFor(boolean postgres, AnnotatedField field, ObjectMapper objectMapper, + int dbType, DocPropertyType docType) { + Class type = field.getRawType(); String pgType = getPostgresType(postgres, dbType); if (Set.class.equals(type)) { - return new OmSet(objectMapper, genericType, dbType, pgType, docType); + return new OmSet(objectMapper, field, dbType, pgType, docType); } if (List.class.equals(type)) { - return new OmList(objectMapper, genericType, dbType, pgType, docType); + return new OmList(objectMapper, field, dbType, pgType, docType); } if (Map.class.equals(type)) { - return new OmMap(objectMapper, genericType, dbType, pgType); + return new OmMap(objectMapper, field, dbType, pgType); } - return new GenericObject(objectMapper, genericType, dbType, pgType); + return new GenericObject(objectMapper, field, dbType, pgType); } private static String getPostgresType(boolean postgres, int dbType) { @@ -64,8 +70,8 @@ public class ScalarTypeJsonObjectMapper { */ private static class GenericObject extends Base { - public GenericObject(ObjectMapper objectMapper, Type type, int dbType, String pgType) { - super(Object.class, objectMapper, type, dbType, pgType, DocPropertyType.OBJECT); + public GenericObject(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType) { + super(Object.class, objectMapper, field, dbType, pgType, DocPropertyType.OBJECT); } } @@ -75,8 +81,8 @@ public class ScalarTypeJsonObjectMapper { @SuppressWarnings("rawtypes") private static class OmSet extends Base { - public OmSet(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) { - super(Set.class, objectMapper, type, dbType, pgType, docType); + public OmSet(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) { + super(Set.class, objectMapper, field, dbType, pgType, docType); } @Override @@ -93,8 +99,8 @@ public class ScalarTypeJsonObjectMapper { @SuppressWarnings("rawtypes") private static class OmList extends Base { - public OmList(ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) { - super(List.class, objectMapper, type, dbType, pgType, docType); + public OmList(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) { + super(List.class, objectMapper, field, dbType, pgType, docType); } @Override @@ -111,8 +117,8 @@ public class ScalarTypeJsonObjectMapper { @SuppressWarnings("rawtypes") private static class OmMap extends Base { - public OmMap(ObjectMapper objectMapper, Type type, int dbType, String pgType) { - super(Map.class, objectMapper, type, dbType, pgType, DocPropertyType.OBJECT); + public OmMap(ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType) { + super(Map.class, objectMapper, field, dbType, pgType, DocPropertyType.OBJECT); } @Override @@ -129,9 +135,11 @@ public class ScalarTypeJsonObjectMapper { */ private static abstract class Base extends ScalarTypeBase { - private final ObjectMapper objectMapper; + private final ObjectWriter objectWriter; - private final JavaType javaType; + private final ObjectMapper objectReader; + + private JavaType deserType; private final String pgType; @@ -140,12 +148,39 @@ public class ScalarTypeJsonObjectMapper { /** * Construct given the object mapper, property type and DB type for storage. */ - public Base(Class cls, ObjectMapper objectMapper, Type type, int dbType, String pgType, DocPropertyType docType) { + public Base(Class cls, ObjectMapper objectMapper, AnnotatedField field, int dbType, String pgType, DocPropertyType docType) { super(cls, false, dbType); this.pgType = pgType; this.docType = docType; - this.objectMapper = objectMapper; - this.javaType = objectMapper.getTypeFactory().constructType(type); + this.objectReader = objectMapper; + + JavaType javaType = field.getType(); + DeserializationConfig deserConfig = objectMapper.getDeserializationConfig(); + AnnotationIntrospector ai = deserConfig.getAnnotationIntrospector(); + + if (ai != null && javaType != null && !javaType.hasRawClass(Object.class)) { + try { + this.deserType = ai.refineDeserializationType(deserConfig, field, javaType); + } catch (JsonMappingException e) { + throw new RuntimeException(e); + } + } else { + this.deserType = javaType; + } + + SerializationConfig serConfig = objectMapper.getSerializationConfig(); + ai = deserConfig.getAnnotationIntrospector(); + + if (ai != null && javaType != null && !javaType.hasRawClass(Object.class)) { + try { + JavaType serType = ai.refineSerializationType(serConfig, field, javaType); + this.objectWriter = objectMapper.writerFor(serType); + } catch (JsonMappingException e) { + throw new RuntimeException(e); + } + } else { + this.objectWriter = objectMapper.writerFor(javaType); + } } /** @@ -171,7 +206,7 @@ public class ScalarTypeJsonObjectMapper { return null; } try { - return objectMapper.readValue(json, javaType); + return objectReader.readValue(json, deserType); } catch (IOException e) { throw new SQLException("Unable to convert JSON", e); } @@ -187,7 +222,7 @@ public class ScalarTypeJsonObjectMapper { bind.setNull(Types.VARCHAR); // use varchar, otherwise SqlServer/db2 will fail with 'Invalid JDBC data type 5.001.' } else { try { - String json = objectMapper.writeValueAsString(value); + String json = objectWriter.writeValueAsString(value); bind.setString(json); } catch (JsonProcessingException e) { throw new SQLException("Unable to create JSON", e); @@ -212,7 +247,7 @@ public class ScalarTypeJsonObjectMapper { @Override public String formatValue(T value) { try { - return objectMapper.writeValueAsString(value); + return objectWriter.writeValueAsString(value); } catch (JsonProcessingException e) { throw new PersistenceException("Unable to create JSON", e); } @@ -221,7 +256,7 @@ public class ScalarTypeJsonObjectMapper { @Override public T parse(String value) { try { - return objectMapper.readValue(value, javaType); + return objectReader.readValue(value, deserType); } catch (IOException e) { throw new PersistenceException("Unable to convert JSON", e); } @@ -244,12 +279,12 @@ public class ScalarTypeJsonObjectMapper { @Override public T jsonRead(JsonParser parser) throws IOException { - return objectMapper.readValue(parser, javaType); + return objectReader.readValue(parser, deserType); } @Override public void jsonWrite(JsonGenerator writer, T value) throws IOException { - objectMapper.writeValue(writer, value); + objectWriter.writeValue(writer, value); } @Override diff --git a/src/main/java/io/ebeaninternal/server/type/TypeManager.java b/src/main/java/io/ebeaninternal/server/type/TypeManager.java index ebfebc955..9e6ca0d7b 100644 --- a/src/main/java/io/ebeaninternal/server/type/TypeManager.java +++ b/src/main/java/io/ebeaninternal/server/type/TypeManager.java @@ -1,6 +1,7 @@ package io.ebeaninternal.server.type; import io.ebean.annotation.DbArray; +import io.ebeaninternal.server.deploy.meta.DeployBeanProperty; import javax.persistence.EnumType; import java.lang.reflect.Type; @@ -57,7 +58,7 @@ public interface TypeManager { * Note that type expected to be JsonNode or Map. *

    */ - ScalarType getJsonScalarType(Class type, int dbType, int dbLength, Type genericType); + ScalarType getJsonScalarType(DeployBeanProperty prop, int dbType, int dbLength); /** * Return the ScalarType used to handle DB ARRAY. diff --git a/src/test/java/org/tests/json/TestDbJson_Jackson.java b/src/test/java/org/tests/json/TestDbJson_Jackson.java new file mode 100644 index 000000000..c281444a7 --- /dev/null +++ b/src/test/java/org/tests/json/TestDbJson_Jackson.java @@ -0,0 +1,113 @@ +package org.tests.json; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.StrictAssertions.assertThat; + +import java.io.IOException; + +import org.junit.Test; +import org.tests.model.json.EBasicJsonJackson; +import org.tests.model.json.EBasicJsonJackson2; +import org.tests.model.json.LongJacksonType; +import org.tests.model.json.StringJacksonType; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; + +public class TestDbJson_Jackson extends BaseTestCase { + + + /** + * This testcase verifies if the @JsonDeserialize Annotation will work properly in ebean. + */ + @Test + public void testJsonDeserializeAnnotation() throws IOException { + + EBasicJsonJackson bean = new EBasicJsonJackson(); + + bean.setName("stuff"); + + bean.setPlainValue("plain"); + + bean.getValueSet().add("A"); + bean.getValueSet().add("B"); + + bean.getValueList().add("A"); + bean.getValueList().add("B"); + + bean.getValueMap().put(1, "one"); + bean.getValueMap().put(2, "two"); + + ObjectMapper mapper = (ObjectMapper) Ebean.getDefaultServer().getPluginApi().getServerConfig().getObjectMapper(); + + String json = mapper.writeValueAsString(bean); + EBasicJsonJackson found = mapper.readValue(json, EBasicJsonJackson.class); + + // here we assert, that we can serialize/deserialize that bean with jackson + assertThat(found.getPlainValue()).isEqualTo("plain"); + assertThat(found.getValueList()).containsExactly("A", "B"); + assertThat(found.getValueSet()).containsExactly("A", "B"); + assertThat(found.getValueMap()).containsEntry(1L, "one").containsEntry(2L, "two"); + + Ebean.save(bean); + + // here we do the same and expect, that we can deserialize the bean also + found = Ebean.find(EBasicJsonJackson.class, bean.getId()); + + assertThat(found.getPlainValue()).isEqualTo("plain"); + assertThat(found.getValueList()).containsExactly("A", "B"); + assertThat(found.getValueSet()).containsExactly("A", "B"); + assertThat(found.getValueMap()).containsEntry(1L, "one").containsEntry(2L, "two"); + } + + /** + * This testcase verifies if polymorph objects will work in ebean. + * + * for BasicJacksonType there exists two types and has a @JsonTypeInfo + * annotation. It is expected that this information is also honored by ebean. + */ + @Test + public void testPolymorph() throws IOException { + + EBasicJsonJackson2 bean = new EBasicJsonJackson2(); + + bean.setName("stuff"); + + bean.setPlainValue(new LongJacksonType(42L)); + + bean.getValueSet().add(new StringJacksonType("A")); + bean.getValueSet().add(new LongJacksonType(7l)); + + bean.getValueList().add(new StringJacksonType("A")); + bean.getValueList().add(new LongJacksonType(7l)); + + bean.getValueMap().put(1, new StringJacksonType("A")); + bean.getValueMap().put(2, new LongJacksonType(7l)); + + ObjectMapper mapper = (ObjectMapper) Ebean.getDefaultServer().getPluginApi().getServerConfig().getObjectMapper(); + + String json = mapper.writeValueAsString(bean); + assertThat(json) + .contains("\"type\":\"string\"") + .contains("\"type\":\"long\""); + EBasicJsonJackson2 found = mapper.readValue(json, EBasicJsonJackson2.class); + + assertThat(found.getPlainValue()).isInstanceOf(LongJacksonType.class); + assertThat(found.getValueList()).hasSize(2); + assertThat(found.getValueSet()).hasSize(2); + assertThat(found.getValueMap()).hasSize(2);; + + Ebean.save(bean); + + found = Ebean.find(EBasicJsonJackson2.class, bean.getId()); + + assertThat(found.getPlainValue()).isInstanceOf(LongJacksonType.class); + assertThat(found.getValueList()).hasSize(2); + assertThat(found.getValueSet()).hasSize(2); + assertThat(found.getValueMap()).hasSize(2);; + + } + +} diff --git a/src/test/java/org/tests/json/TestDbJson_Jackson2.java b/src/test/java/org/tests/json/TestDbJson_Jackson2.java new file mode 100644 index 000000000..866161cf0 --- /dev/null +++ b/src/test/java/org/tests/json/TestDbJson_Jackson2.java @@ -0,0 +1,62 @@ +package org.tests.json; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.StrictAssertions.assertThat; + +import java.io.IOException; + +import org.junit.Test; +import org.tests.model.json.EBasicJsonJackson2; +import org.tests.model.json.LongJacksonType; +import org.tests.model.json.StringJacksonType; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.ebean.BaseTestCase; +import io.ebean.Ebean; + +public class TestDbJson_Jackson2 extends BaseTestCase { + + private EBasicJsonJackson2 bean = new EBasicJsonJackson2(); + + private EBasicJsonJackson2 found; + + @Test + public void insert() throws IOException { + + bean.setName("stuff"); + + bean.setPlainValue(new LongJacksonType(42L)); + + bean.getValueSet().add(new StringJacksonType("A")); + bean.getValueSet().add(new LongJacksonType(7l)); + + bean.getValueList().add(new StringJacksonType("A")); + bean.getValueList().add(new LongJacksonType(7l)); + + bean.getValueMap().put(1, new StringJacksonType("A")); + bean.getValueMap().put(2, new LongJacksonType(7l)); + + ObjectMapper mapper = (ObjectMapper) Ebean.getDefaultServer().getPluginApi().getServerConfig().getObjectMapper(); + + String json = mapper.writeValueAsString(bean); + found = mapper.readValue(json, EBasicJsonJackson2.class); + + assertThat(found.getPlainValue()).isInstanceOf(LongJacksonType.class); + assertThat(found.getValueList()).hasSize(2); + assertThat(found.getValueSet()).hasSize(2); + assertThat(found.getValueMap()).hasSize(2);; + + Ebean.save(bean); + + found = Ebean.find(EBasicJsonJackson2.class, bean.getId()); + + assertThat(found.getPlainValue()).isInstanceOf(LongJacksonType.class); + assertThat(found.getValueList()).hasSize(2); + assertThat(found.getValueSet()).hasSize(2); + assertThat(found.getValueMap()).hasSize(2);; + + } + + +} diff --git a/src/test/java/org/tests/model/json/BasicJacksonType.java b/src/test/java/org/tests/model/json/BasicJacksonType.java new file mode 100644 index 000000000..fee853259 --- /dev/null +++ b/src/test/java/org/tests/model/json/BasicJacksonType.java @@ -0,0 +1,15 @@ +package org.tests.model.json; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonTypeInfo.As; + + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type") +@JsonSubTypes({ + @JsonSubTypes.Type(value = LongJacksonType.class, name = "long"), + @JsonSubTypes.Type(value = StringJacksonType.class, name = "string") +}) +public interface BasicJacksonType { + T getValue(); +} diff --git a/src/test/java/org/tests/model/json/EBasicJsonJackson.java b/src/test/java/org/tests/model/json/EBasicJsonJackson.java new file mode 100644 index 000000000..9faa35eee --- /dev/null +++ b/src/test/java/org/tests/model/json/EBasicJsonJackson.java @@ -0,0 +1,101 @@ +package org.tests.model.json; + +import io.ebean.annotation.DbJson; +import io.ebean.annotation.DbJsonB; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Entity +public class EBasicJsonJackson { + + @Id + Long id; + + String name; + + @DbJson(length = 700) + @JsonDeserialize(contentAs = String.class) + Set valueSet = new LinkedHashSet<>(); + + @DbJsonB + @JsonDeserialize(contentAs = String.class) + List valueList = new ArrayList<>(); + + @DbJson(length = 700) + @JsonDeserialize(keyAs = Long.class, contentAs = String.class) + Map valueMap = new LinkedHashMap<>(); + + @DbJson(length = 500) + @JsonDeserialize(as = String.class) + Object plainValue; + + @Version + Long version; + + 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 Set getValueSet() { + return valueSet; + } + + public void setValueSet(Set valueSet) { + this.valueSet = valueSet; + } + + public List getValueList() { + return valueList; + } + + public void setValueList(List valueList) { + this.valueList = valueList; + } + + public Object getPlainValue() { + return plainValue; + } + + public void setPlainValue(Object plainValue) { + this.plainValue = plainValue; + } + + public Map getValueMap() { + return valueMap; + } + + public void setValueMap(Map valueMap) { + this.valueMap = valueMap; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/json/EBasicJsonJackson2.java b/src/test/java/org/tests/model/json/EBasicJsonJackson2.java new file mode 100644 index 000000000..dc8269682 --- /dev/null +++ b/src/test/java/org/tests/model/json/EBasicJsonJackson2.java @@ -0,0 +1,98 @@ +package org.tests.model.json; + +import io.ebean.annotation.DbJson; +import io.ebean.annotation.DbJsonB; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Entity +public class EBasicJsonJackson2 { + + @Id + Long id; + + String name; + + @DbJson(length = 700) + Set> valueSet = new LinkedHashSet<>(); + + @DbJsonB + List> valueList = new ArrayList<>(); + + @DbJson(length = 700) + @JsonDeserialize(keyAs = Long.class) + Map> valueMap = new LinkedHashMap<>(); + + @DbJson(length = 500) + BasicJacksonType plainValue; + + @Version + Long version; + + 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 Set> getValueSet() { + return valueSet; + } + + public void setValueSet(Set> valueSet) { + this.valueSet = valueSet; + } + + public List> getValueList() { + return valueList; + } + + public void setValueList(List> valueList) { + this.valueList = valueList; + } + + public BasicJacksonType getPlainValue() { + return plainValue; + } + + public void setPlainValue(BasicJacksonType plainValue) { + this.plainValue = plainValue; + } + + public Map> getValueMap() { + return valueMap; + } + + public void setValueMap(Map> valueMap) { + this.valueMap = valueMap; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } +} diff --git a/src/test/java/org/tests/model/json/LongJacksonType.java b/src/test/java/org/tests/model/json/LongJacksonType.java new file mode 100644 index 000000000..c1800bf04 --- /dev/null +++ b/src/test/java/org/tests/model/json/LongJacksonType.java @@ -0,0 +1,22 @@ +package org.tests.model.json; + +public class LongJacksonType implements BasicJacksonType { + + private Long value; + + public LongJacksonType() {} + + public LongJacksonType(Long value) { + this.value = value; + } + + @Override + public Long getValue() { + return value; + } + + public void setValue(Long value) { + this.value = value; + } + +} diff --git a/src/test/java/org/tests/model/json/StringJacksonType.java b/src/test/java/org/tests/model/json/StringJacksonType.java new file mode 100644 index 000000000..e562495d6 --- /dev/null +++ b/src/test/java/org/tests/model/json/StringJacksonType.java @@ -0,0 +1,22 @@ +package org.tests.model.json; + +public class StringJacksonType implements BasicJacksonType { + + private String value; + + public StringJacksonType() {} + + public StringJacksonType(String value) { + this.value = value; + } + + @Override + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + +} From d395c666fc2157b565d869149834bdff740838b1 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Oct 2018 01:32:22 +1300 Subject: [PATCH 0512/1036] #1516 - More user friendly exceptions - BeanNotEnhancedException, BeanNotRegisteredException --- src/main/java/io/ebean/Ebean.java | 11 +++++++++ .../config/BeanNotEnhancedException.java | 13 +++++++++++ .../config/BeanNotRegisteredException.java | 13 +++++++++++ .../server/deploy/BeanDescriptorManager.java | 23 +++++++++++++------ .../deploy/BeanEmbeddedMetaFactory.java | 5 ++-- 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/main/java/io/ebean/config/BeanNotEnhancedException.java create mode 100644 src/main/java/io/ebean/config/BeanNotRegisteredException.java diff --git a/src/main/java/io/ebean/Ebean.java b/src/main/java/io/ebean/Ebean.java index 09d2d738b..cd27c7109 100644 --- a/src/main/java/io/ebean/Ebean.java +++ b/src/main/java/io/ebean/Ebean.java @@ -2,10 +2,12 @@ package io.ebean; import io.ebean.annotation.TxIsolation; import io.ebean.cache.ServerCacheManager; +import io.ebean.config.BeanNotEnhancedException; import io.ebean.config.ServerConfig; import io.ebean.plugin.Property; import io.ebean.text.csv.CsvReader; import io.ebean.text.json.JsonContext; +import io.ebean.datasource.DataSourceConfigurationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -160,6 +162,15 @@ public final class Ebean { defaultServer = getWithCreate(defaultName.trim()); } } + } catch (BeanNotEnhancedException e) { + throw e; + + } catch (DataSourceConfigurationException e) { + String msg = "Configuration error creating DataSource for the default EbeanServer." + + " This typically means a missing application-test.yml or missing ebean-test-config dependency." + + " See https://ebean-orm.github.io/docs/trouble-shooting#datasource"; + throw new DataSourceConfigurationException(msg, e); + } catch (Throwable e) { logger.error("Error trying to create the default EbeanServer", e); throw new RuntimeException(e); diff --git a/src/main/java/io/ebean/config/BeanNotEnhancedException.java b/src/main/java/io/ebean/config/BeanNotEnhancedException.java new file mode 100644 index 000000000..67ff285da --- /dev/null +++ b/src/main/java/io/ebean/config/BeanNotEnhancedException.java @@ -0,0 +1,13 @@ +package io.ebean.config; + +/** + * Throw when an processing an entity bean that is not bytecode enhanced. + * + * Refer: https://ebean-orm.github.io/docs/trouble-shooting#not-enhanced + */ +public class BeanNotEnhancedException extends IllegalStateException { + + public BeanNotEnhancedException(String msg) { + super(msg); + } +} diff --git a/src/main/java/io/ebean/config/BeanNotRegisteredException.java b/src/main/java/io/ebean/config/BeanNotRegisteredException.java new file mode 100644 index 000000000..29212c24b --- /dev/null +++ b/src/main/java/io/ebean/config/BeanNotRegisteredException.java @@ -0,0 +1,13 @@ +package io.ebean.config; + +/** + * Throw when an processing thinks a bean is not registered. + * + * Refer: https://ebean-orm.github.io/docs/trouble-shooting#not-registered + */ +public class BeanNotRegisteredException extends IllegalStateException { + + public BeanNotRegisteredException(String msg) { + super(msg); + } +} diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java index 1083235cc..b836faeba 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -6,6 +6,7 @@ import io.ebean.RawSqlBuilder; import io.ebean.annotation.ConstraintMode; import io.ebean.bean.BeanCollection; import io.ebean.bean.EntityBean; +import io.ebean.config.BeanNotEnhancedException; import io.ebean.config.EncryptKey; import io.ebean.config.EncryptKeyManager; import io.ebean.config.NamingConvention; @@ -388,6 +389,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return asOfTableMap; + } catch (BeanNotEnhancedException e) { + throw e; + } catch (RuntimeException e) { logger.error("Error in deployment", e); throw e; @@ -1471,7 +1475,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { if (isPersistentField(prop)) { throw new IllegalStateException( "If you are running in an IDE with enhancement plugin try a Build -> Rebuild Project to recompile and enhance all entity beans. " + - "Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType()); + "Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType()); } } else { @@ -1554,7 +1558,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap { Class beanClass = desc.getBeanType(); if (!hasEntityBeanInterface(beanClass)) { - throw new IllegalStateException("Bean " + beanClass + " is not enhanced?"); + String msg = "Bean " + beanClass + " is not enhanced? If you are running in IDEA or Eclipse check" + + " that the enhancement plugin is installed. See https://ebean-orm.github.io/docs/trouble-shooting#not-enhanced"; + throw new BeanNotEnhancedException(msg); } // the bean already implements EntityBean @@ -1583,7 +1589,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { // ok to stop and treat just the same as Object.class return; } - throw new IllegalStateException("Super type " + superclass + " is not enhanced?"); + throw new BeanNotEnhancedException("Super type " + superclass + " is not enhanced? See https://ebean-orm.github.io/docs/trouble-shooting#not-enhanced"); } // recursively continue up the inheritance hierarchy @@ -1666,11 +1672,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap { private ElementHelp elementHelper(ManyType manyType) { switch (manyType) { - case LIST: return new ElementHelpList(); - case SET: return new ElementHelpSet(); - case MAP: return new ElementHelpMap(); + case LIST: + return new ElementHelpList(); + case SET: + return new ElementHelpSet(); + case MAP: + return new ElementHelpMap(); default: - throw new IllegalStateException("manyType unexpected "+manyType); + throw new IllegalStateException("manyType unexpected " + manyType); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanEmbeddedMetaFactory.java b/src/main/java/io/ebeaninternal/server/deploy/BeanEmbeddedMetaFactory.java index cbe297901..016a760e4 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanEmbeddedMetaFactory.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanEmbeddedMetaFactory.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.deploy; +import io.ebean.config.BeanNotRegisteredException; import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne; import javax.persistence.PersistenceException; @@ -22,8 +23,8 @@ public class BeanEmbeddedMetaFactory { BeanDescriptor targetDesc = owner.getBeanDescriptor(prop.getTargetType()); if (targetDesc == null) { String msg = "Could not find BeanDescriptor for " + prop.getTargetType() - + ". Perhaps the EmbeddedId class is not registered?"; - throw new PersistenceException(msg); + + ". Perhaps the EmbeddedId class is not registered? See https://ebean-orm.github.io/docs/trouble-shooting#not-registered"; + throw new BeanNotRegisteredException(msg); } // deployment override information (column names) From d627bb47e228f28784902c918bef9378392ead7d Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Oct 2018 01:33:24 +1300 Subject: [PATCH 0513/1036] #1516 - More user friendly exceptions - BeanNotEnhancedException, BeanNotRegisteredException --- .../server/deploy/parse/AnnotationAssocManys.java | 9 ++++----- .../server/deploy/parse/AnnotationAssocOnes.java | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java index e4b6d52d0..7ed87e639 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocManys.java @@ -6,6 +6,7 @@ import io.ebean.annotation.HistoryExclude; import io.ebean.annotation.PrivateOwned; import io.ebean.annotation.Where; import io.ebean.bean.BeanCollection.ModifyListenMode; +import io.ebean.config.BeanNotRegisteredException; import io.ebean.config.NamingConvention; import io.ebean.config.TableName; import io.ebean.util.CamelCaseHelper; @@ -430,7 +431,7 @@ class AnnotationAssocManys extends AnnotationParser { private String errorMsgMissingBeanTable(Class type, String from) { - return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered?"; + return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? See https://ebean-orm.github.io/docs/trouble-shooting#not-registered"; } private void readToMany(ManyToMany propAnn, DeployBeanPropertyAssocMany manyProp) { @@ -451,8 +452,7 @@ class AnnotationAssocManys extends AnnotationParser { // find the other many table (not intersection) BeanTable assoc = factory.getBeanTable(targetType); if (assoc == null) { - String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName()); - throw new RuntimeException(msg); + throw new BeanNotRegisteredException(errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName())); } manyProp.setManyToMany(); @@ -478,8 +478,7 @@ class AnnotationAssocManys extends AnnotationParser { BeanTable assoc = factory.getBeanTable(targetType); if (assoc == null) { - String msg = errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName()); - throw new RuntimeException(msg); + throw new BeanNotRegisteredException(errorMsgMissingBeanTable(targetType, manyProp.getFullBeanName())); } manyProp.setBeanTable(assoc); diff --git a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java index add0870e8..c17b5e708 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java +++ b/src/main/java/io/ebeaninternal/server/deploy/parse/AnnotationAssocOnes.java @@ -4,6 +4,7 @@ import io.ebean.annotation.DbForeignKey; import io.ebean.annotation.FetchPreference; import io.ebean.annotation.TenantId; import io.ebean.annotation.Where; +import io.ebean.config.BeanNotRegisteredException; import io.ebean.config.NamingConvention; import io.ebeaninternal.server.deploy.BeanDescriptorManager; import io.ebeaninternal.server.deploy.BeanTable; @@ -194,13 +195,13 @@ public class AnnotationAssocOnes extends AnnotationParser { } private String errorMsgMissingBeanTable(Class type, String from) { - return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? Does it have the @Entity annotation?"; + return "Error with association to [" + type + "] from [" + from + "]. Is " + type + " registered? Does it have the @Entity annotation? See https://ebean-orm.github.io/docs/trouble-shooting#not-registered"; } private BeanTable beanTable(DeployBeanPropertyAssoc prop) { BeanTable assoc = factory.getBeanTable(prop.getPropertyType()); if (assoc == null) { - throw new RuntimeException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName())); + throw new BeanNotRegisteredException(errorMsgMissingBeanTable(prop.getPropertyType(), prop.getFullBeanName())); } return assoc; } From b9ca8be95ae5dee1c30bc98d480a0395c66cc42d Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Oct 2018 01:34:16 +1300 Subject: [PATCH 0514/1036] #1517 - Update for ebean-datasource maven groupId change to io.ebean --- pom.xml | 10 +++++----- src/main/java/io/ebean/config/ServerConfig.java | 2 +- .../io/ebeaninternal/server/core/DefaultContainer.java | 8 ++++---- .../server/core/InternalConfiguration.java | 2 +- .../server/core/MultiTenantDbCatalogSupplier.java | 2 +- .../server/core/MultiTenantDbSchemaSupplier.java | 2 +- .../server/core/SimpleDataSourceProvider.java | 2 +- src/test/java/io/ebean/config/ServerConfigTest.java | 2 +- src/test/java/org/tests/basic/MainDbBoolean.java | 2 +- .../org/tests/basic/MyTestDataSourcePoolListener.java | 2 +- .../java/org/tests/query/TestQueryFindIterate.java | 2 +- .../tests/transaction/TestAutoCommitDataSource.java | 6 +++--- .../tests/transaction/TestExplicitTransactionMode.java | 6 +++--- src/test/java/org/tests/unitinternal/HelloMain.java | 2 +- 14 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pom.xml b/pom.xml index 845fea9ae..db4f48f77 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ io.ebean ebean - 11.23.2-SNAPSHOT + 11.24.1-SNAPSHOT jar ebean @@ -121,9 +121,9 @@ - org.avaje - avaje-datasource - 3.2.2 + io.ebean + ebean-datasource + 4.2.1 @@ -270,7 +270,7 @@ 5.1.43 test - + com.sap.cloud.db.jdbc ngdbc diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index 853c05858..a1f622568 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -30,7 +30,7 @@ import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebean.meta.MetaInfoManager; import io.ebean.migration.MigrationRunner; import io.ebean.util.StringHelper; -import org.avaje.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourceConfig; import javax.sql.DataSource; import java.time.Clock; diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java index 5b9f111d7..9c547e8ae 100644 --- a/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java +++ b/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java @@ -15,10 +15,10 @@ import io.ebeaninternal.server.cluster.ClusterManager; import io.ebeaninternal.server.core.bootup.BootupClassPathSearch; import io.ebeaninternal.server.core.bootup.BootupClasses; import io.ebeaninternal.server.lib.ShutdownManager; -import org.avaje.datasource.DataSourceAlertFactory; -import org.avaje.datasource.DataSourceConfig; -import org.avaje.datasource.DataSourceFactory; -import org.avaje.datasource.DataSourcePoolListener; +import io.ebean.datasource.DataSourceAlertFactory; +import io.ebean.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourceFactory; +import io.ebean.datasource.DataSourcePoolListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java index a2090e2e0..c27c530d1 100644 --- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java +++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java @@ -87,7 +87,7 @@ import io.ebeanservice.docstore.api.DocStoreFactory; import io.ebeanservice.docstore.api.DocStoreIntegration; import io.ebeanservice.docstore.api.DocStoreUpdateProcessor; import io.ebeanservice.docstore.none.NoneDocStoreFactory; -import org.avaje.datasource.DataSourcePool; +import io.ebean.datasource.DataSourcePool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/io/ebeaninternal/server/core/MultiTenantDbCatalogSupplier.java b/src/main/java/io/ebeaninternal/server/core/MultiTenantDbCatalogSupplier.java index 11ede3e96..f1dfc07e1 100644 --- a/src/main/java/io/ebeaninternal/server/core/MultiTenantDbCatalogSupplier.java +++ b/src/main/java/io/ebeaninternal/server/core/MultiTenantDbCatalogSupplier.java @@ -3,7 +3,7 @@ package io.ebeaninternal.server.core; import io.ebean.config.CurrentTenantProvider; import io.ebean.config.TenantCatalogProvider; import io.ebeaninternal.server.transaction.DataSourceSupplier; -import org.avaje.datasource.DataSourcePool; +import io.ebean.datasource.DataSourcePool; import javax.sql.DataSource; import java.io.PrintWriter; diff --git a/src/main/java/io/ebeaninternal/server/core/MultiTenantDbSchemaSupplier.java b/src/main/java/io/ebeaninternal/server/core/MultiTenantDbSchemaSupplier.java index 33f4de3ff..a309f4f2f 100644 --- a/src/main/java/io/ebeaninternal/server/core/MultiTenantDbSchemaSupplier.java +++ b/src/main/java/io/ebeaninternal/server/core/MultiTenantDbSchemaSupplier.java @@ -3,7 +3,7 @@ package io.ebeaninternal.server.core; import io.ebean.config.CurrentTenantProvider; import io.ebean.config.TenantSchemaProvider; import io.ebeaninternal.server.transaction.DataSourceSupplier; -import org.avaje.datasource.DataSourcePool; +import io.ebean.datasource.DataSourcePool; import javax.sql.DataSource; import java.io.PrintWriter; diff --git a/src/main/java/io/ebeaninternal/server/core/SimpleDataSourceProvider.java b/src/main/java/io/ebeaninternal/server/core/SimpleDataSourceProvider.java index 532f2f720..6d83da262 100644 --- a/src/main/java/io/ebeaninternal/server/core/SimpleDataSourceProvider.java +++ b/src/main/java/io/ebeaninternal/server/core/SimpleDataSourceProvider.java @@ -1,7 +1,7 @@ package io.ebeaninternal.server.core; import io.ebeaninternal.server.transaction.DataSourceSupplier; -import org.avaje.datasource.DataSourcePool; +import io.ebean.datasource.DataSourcePool; import javax.sql.DataSource; import java.sql.Connection; diff --git a/src/test/java/io/ebean/config/ServerConfigTest.java b/src/test/java/io/ebean/config/ServerConfigTest.java index b0ff31457..5ac810e8b 100644 --- a/src/test/java/io/ebean/config/ServerConfigTest.java +++ b/src/test/java/io/ebean/config/ServerConfigTest.java @@ -2,7 +2,7 @@ package io.ebean.config; import io.ebean.annotation.PersistBatch; import io.ebean.config.dbplatform.IdType; -import org.avaje.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourceConfig; import org.junit.Test; import java.util.Properties; diff --git a/src/test/java/org/tests/basic/MainDbBoolean.java b/src/test/java/org/tests/basic/MainDbBoolean.java index 3715760c5..47feddb82 100644 --- a/src/test/java/org/tests/basic/MainDbBoolean.java +++ b/src/test/java/org/tests/basic/MainDbBoolean.java @@ -9,7 +9,7 @@ import io.ebean.config.dbplatform.postgres.PostgresPlatform; import org.tests.model.basic.TOne; import org.tests.model.basic.TSDetail; import org.tests.model.basic.TSMaster; -import org.avaje.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourceConfig; import org.junit.Assert; import java.util.List; diff --git a/src/test/java/org/tests/basic/MyTestDataSourcePoolListener.java b/src/test/java/org/tests/basic/MyTestDataSourcePoolListener.java index f73cb92ee..e94299d52 100644 --- a/src/test/java/org/tests/basic/MyTestDataSourcePoolListener.java +++ b/src/test/java/org/tests/basic/MyTestDataSourcePoolListener.java @@ -1,6 +1,6 @@ package org.tests.basic; -import org.avaje.datasource.DataSourcePoolListener; +import io.ebean.datasource.DataSourcePoolListener; import java.sql.Connection; diff --git a/src/test/java/org/tests/query/TestQueryFindIterate.java b/src/test/java/org/tests/query/TestQueryFindIterate.java index de2c9f16b..47c20eb73 100644 --- a/src/test/java/org/tests/query/TestQueryFindIterate.java +++ b/src/test/java/org/tests/query/TestQueryFindIterate.java @@ -6,7 +6,7 @@ import io.ebean.EbeanServer; import io.ebean.Query; import io.ebean.QueryIterator; import io.ebean.plugin.SpiServer; -import org.avaje.datasource.DataSourcePool; +import io.ebean.datasource.DataSourcePool; import org.ebeantest.LoggedSqlCollector; import org.junit.Test; import org.tests.model.basic.Customer; diff --git a/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java b/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java index 554b2efd7..577dbc74c 100644 --- a/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java +++ b/src/test/java/org/tests/transaction/TestAutoCommitDataSource.java @@ -9,9 +9,9 @@ import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import io.ebean.config.properties.PropertiesLoader; -import org.avaje.datasource.DataSourceConfig; -import org.avaje.datasource.DataSourcePool; -import org.avaje.datasource.pool.ConnectionPool; +import io.ebean.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourcePool; +import io.ebean.datasource.pool.ConnectionPool; import org.junit.Test; import org.tests.model.basic.UTDetail; import org.tests.model.basic.UTMaster; diff --git a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java index 0809baa9c..b125ce66f 100644 --- a/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java +++ b/src/test/java/org/tests/transaction/TestExplicitTransactionMode.java @@ -9,9 +9,9 @@ import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; import io.ebean.config.ServerConfig; import io.ebean.config.properties.PropertiesLoader; -import org.avaje.datasource.DataSourceConfig; -import org.avaje.datasource.DataSourcePool; -import org.avaje.datasource.pool.ConnectionPool; +import io.ebean.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourcePool; +import io.ebean.datasource.pool.ConnectionPool; import org.junit.Test; import org.tests.model.basic.UTDetail; import org.tests.model.basic.UTMaster; diff --git a/src/test/java/org/tests/unitinternal/HelloMain.java b/src/test/java/org/tests/unitinternal/HelloMain.java index 1d80fcdbe..5efeba5ea 100644 --- a/src/test/java/org/tests/unitinternal/HelloMain.java +++ b/src/test/java/org/tests/unitinternal/HelloMain.java @@ -5,7 +5,7 @@ import io.ebean.EbeanServerFactory; import io.ebean.config.ServerConfig; import org.tests.model.basic.TOne; import org.avaje.agentloader.AgentLoader; -import org.avaje.datasource.DataSourceConfig; +import io.ebean.datasource.DataSourceConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 19d29cd8367ecaad773d02a6db0fe79794a325bf Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Fri, 26 Oct 2018 14:50:17 +1300 Subject: [PATCH 0515/1036] #1514 - Add support for JacksonAnnotations at bean-properties Fix where Jackson is not present on the classpath --- .../deploy/meta/DeployBeanDescriptor.java | 6 +--- .../deploy/meta/DeployBeanObtainJackson.java | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanObtainJackson.java diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index 9f26a4f34..18873232a 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -3,7 +3,6 @@ package io.ebeaninternal.server.deploy.meta; import io.ebean.annotation.Cache; import io.ebean.annotation.DocStore; import io.ebean.annotation.DocStoreMode; -import io.ebean.annotation.PartitionMode; import io.ebean.config.ServerConfig; import io.ebean.config.TableName; import io.ebean.config.dbplatform.IdType; @@ -1260,10 +1259,7 @@ public class DeployBeanDescriptor { */ public Object /*AnnotatedClass*/ getJacksonAnnotatedClass() { if (jacksonAnnotatedClass == null) { - com.fasterxml.jackson.databind.ObjectMapper objectMapper = (com.fasterxml.jackson.databind.ObjectMapper) serverConfig.getObjectMapper(); - com.fasterxml.jackson.databind.JavaType javaType = objectMapper.getTypeFactory().constructType(beanType); - jacksonAnnotatedClass = com.fasterxml.jackson.databind.introspect.AnnotatedClassResolver - .resolve(objectMapper.getDeserializationConfig(), javaType, objectMapper.getDeserializationConfig()); + jacksonAnnotatedClass = new DeployBeanObtainJackson(serverConfig, beanType).obtain(); } return jacksonAnnotatedClass; } diff --git a/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanObtainJackson.java b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanObtainJackson.java new file mode 100644 index 000000000..9526c2aa2 --- /dev/null +++ b/src/main/java/io/ebeaninternal/server/deploy/meta/DeployBeanObtainJackson.java @@ -0,0 +1,30 @@ +package io.ebeaninternal.server.deploy.meta; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.AnnotatedClassResolver; +import io.ebean.config.ServerConfig; + +/** + * Used to obtain the Jackson AnnotatedClass for a given bean type utlimately to obtain field level Jackson annotations. + */ +class DeployBeanObtainJackson { + + private final ServerConfig serverConfig; + private final Class beanType; + + DeployBeanObtainJackson(ServerConfig serverConfig, Class beanType) { + this.serverConfig = serverConfig; + this.beanType = beanType; + } + + /** + * Return the Jackson AnnotatedClass for the given bean type. + */ + Object obtain() { + + ObjectMapper objectMapper = (ObjectMapper) serverConfig.getObjectMapper(); + JavaType javaType = objectMapper.getTypeFactory().constructType(beanType); + return AnnotatedClassResolver.resolve(objectMapper.getDeserializationConfig(), javaType, objectMapper.getDeserializationConfig()); + } +} From 23d2c64046044cb49a158ee89372f4da61f604de Mon Sep 17 00:00:00 2001 From: Michael Benz Date: Tue, 30 Oct 2018 00:55:58 +0100 Subject: [PATCH 0516/1036] JavaDoc Fix closing h3 tag in Transaction. no code change! (#1520) --- src/main/java/io/ebean/Transaction.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/ebean/Transaction.java b/src/main/java/io/ebean/Transaction.java index df79941e7..961d1f5a8 100644 --- a/src/main/java/io/ebean/Transaction.java +++ b/src/main/java/io/ebean/Transaction.java @@ -84,7 +84,7 @@ public interface Transaction extends AutoCloseable { *

    * This is similar to commit() but leaves the transaction "Active". *

    - *

    Functions/h3> + *

    Functions

    *