From 7ba6e5f67d5d3b420d75d9647cb0c9e96e43656d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Sun, 3 Mar 2024 22:08:47 +1300 Subject: [PATCH 01/12] Add howto-deploy-to-central.md --- howto-deploy-to-central.md | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 howto-deploy-to-central.md diff --git a/howto-deploy-to-central.md b/howto-deploy-to-central.md new file mode 100644 index 000000000..6aad49903 --- /dev/null +++ b/howto-deploy-to-central.md @@ -0,0 +1,49 @@ +# Deploy to Central + +```shell +## confirm on master and building +git checkout master +mvn clean verify + +## set the appropriate version +mvs + +## run tests and package +mvn -T 4 clean package + +## deploy +mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests -DskipStagingRepositoryClose=true -DstagingProgressTimeoutMinutes=9 + +## git commit, git tag, git push --tags + +## convert to javax +./jakarta-to-javax.sh + +## set javax version +mvs + +## deploy javax +mvn -T 4 clean package +mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests -DskipStagingRepositoryClose=true -DstagingProgressTimeoutMinutes=9 + +## checkout / cleanup +git checkout . + +## goto ebean-15x branch +git checkout ebean-15x + +## update ebean-15x branch from master and resolve conflicts +git merge master +## resolve conflicts +## git commit, git push + +## set 15.x version +mvs + +## build and deploy 15.x +mvn -T 4 clean package +mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests -DskipStagingRepositoryClose=true -DstagingProgressTimeoutMinutes=9 + +``` + + From a48e96c7e976cd2d3d49237fa14f6496f67c5172 Mon Sep 17 00:00:00 2001 From: Roland Praml Date: Mon, 4 Mar 2024 10:02:05 +0100 Subject: [PATCH 02/12] FIX broken test for DB2 --- .../java/io/ebeaninternal/server/deploy/BeanProperty.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index 5f592a540..a7dd9c813 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -41,8 +41,8 @@ import io.ebeanservice.docstore.api.mapping.DocMappingBuilder; import io.ebeanservice.docstore.api.mapping.DocPropertyMapping; import io.ebeanservice.docstore.api.mapping.DocPropertyOptions; import io.ebeanservice.docstore.api.support.DocStructure; - import jakarta.persistence.PersistenceException; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -1189,7 +1189,7 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { switch (dbType) { case DbPlatformType.JSON: case DbPlatformType.JSONB: - return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup + return dbLength == 0 || dbLength > 255; // must be analog to DbPlatformTypeMapping.lookup case DbPlatformType.JSONBlob: case DbPlatformType.JSONClob: return true; From fd199f406ba34bf7896461903ac25c236dc35fa9 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Tue, 5 Mar 2024 21:18:27 +1300 Subject: [PATCH 03/12] Modify ContainerConfig to remove the avaje-config dependency This actually reverts a change that was made in commit: https://github.com/ebean-orm/ebean/commit/803f1d86428ce3b653276d72207e5a0009b57d16 --- .../java/io/ebean/config/ContainerConfig.java | 36 +++++++++++-------- .../xtest/config/ContainerConfigTest.java | 20 +++++++---- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/config/ContainerConfig.java b/ebean-api/src/main/java/io/ebean/config/ContainerConfig.java index 20c05c27d..78ef262db 100644 --- a/ebean-api/src/main/java/io/ebean/config/ContainerConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/ContainerConfig.java @@ -1,8 +1,5 @@ package io.ebean.config; -import io.avaje.config.Config; -import io.avaje.config.Configuration; - import java.util.Properties; /** @@ -19,16 +16,6 @@ public class ContainerConfig { private String podName; private int port; private Properties properties; - private Configuration configuration; - - public ContainerConfig() { - this.configuration = Config.asConfiguration(); - this.active = configuration.getBool("ebean.cluster.active", active); - this.serviceName = configuration.getNullable("ebean.cluster.serviceName", serviceName); - this.namespace = configuration.getNullable("ebean.cluster.namespace", namespace); - this.podName = configuration.getNullable("ebean.cluster.podName", podName); - this.port = configuration.getInt("ebean.cluster.port", 0); - } /** * Return the service name. @@ -104,7 +91,7 @@ public class ContainerConfig { * Return the deployment properties. */ public Properties getProperties() { - return properties != null ? properties : configuration.asProperties(); + return properties; } /** @@ -114,4 +101,25 @@ public class ContainerConfig { this.properties = properties; } + /** + * Load the settings from properties. + */ + public void loadFromProperties(Properties properties) { + this.properties = properties; + this.active = getProperty(properties, "ebean.cluster.active", active); + this.serviceName = properties.getProperty("ebean.cluster.serviceName", serviceName); + this.namespace = properties.getProperty("ebean.cluster.namespace", namespace); + this.podName = properties.getProperty("ebean.cluster.podName", podName); + String portParam = properties.getProperty("ebean.cluster.port"); + if (portParam != null) { + this.port = Integer.parseInt(portParam); + } + } + + /** + * Return the boolean property setting. + */ + protected boolean getProperty(Properties properties, String key, boolean defaultValue) { + return "true".equalsIgnoreCase(properties.getProperty(key, Boolean.toString(defaultValue))); + } } diff --git a/ebean-test/src/test/java/io/ebean/xtest/config/ContainerConfigTest.java b/ebean-test/src/test/java/io/ebean/xtest/config/ContainerConfigTest.java index 6fba07abe..4f2f95e22 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/config/ContainerConfigTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/config/ContainerConfigTest.java @@ -12,12 +12,20 @@ class ContainerConfigTest { @Test void loadFromProperties() { - ContainerConfig containerConfig = new ContainerConfig(); + Properties p = new Properties(); + p.setProperty("ebean.cluster.active", "true"); + p.setProperty("ebean.cluster.serviceName", "a"); + p.setProperty("ebean.cluster.namespace", "b"); + p.setProperty("ebean.cluster.podName", "c"); + p.setProperty("ebean.cluster.port", "42"); - assertThat(containerConfig.isActive()).isFalse(); - assertThat(containerConfig.getServiceName()).isNull(); - assertThat(containerConfig.getNamespace()).isNull(); - assertThat(containerConfig.getPodName()).isNull(); - assertThat(containerConfig.getPort()).isEqualTo(0); + ContainerConfig containerConfig = new ContainerConfig(); + containerConfig.loadFromProperties(p); + + assertThat(containerConfig.isActive()).isTrue(); + assertThat(containerConfig.getServiceName()).isEqualTo("a"); + assertThat(containerConfig.getNamespace()).isEqualTo("b"); + assertThat(containerConfig.getPodName()).isEqualTo("c"); + assertThat(containerConfig.getPort()).isEqualTo(42); } } From a48b2f4ebee8e0f8ba8a57a3a84032fcc3753318 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 7 Mar 2024 20:45:40 +1300 Subject: [PATCH 04/12] #3354 Use 4000 for DB Lob detection with distinct query - Use 4000 to match the DB2 logic for considering a column a lob (for distinct etc) - Rename distinctNoLobs -> platformDistinctNoLobs - Rename isDbLob() -> isLobForPlatform() - Rename unselectLobs() -> unselectLobsForPlatform() --- .../io/ebeaninternal/server/deploy/BeanProperty.java | 4 ++-- .../deploy/DynamicPropertyAggregationFormula.java | 2 +- .../io/ebeaninternal/server/query/STreeProperty.java | 2 +- .../io/ebeaninternal/server/query/SqlTreeBuilder.java | 10 +++++----- .../io/ebeaninternal/server/query/SqlTreeNode.java | 2 +- .../io/ebeaninternal/server/query/SqlTreeNodeBean.java | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java index a7dd9c813..72bd24966 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanProperty.java @@ -1182,14 +1182,14 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { * Returns true if this isLob() or the type will effectively map to a lob. */ @Override - public boolean isDbLob() { + public boolean isLobForPlatform() { if (lob) { return true; } switch (dbType) { case DbPlatformType.JSON: case DbPlatformType.JSONB: - return dbLength == 0 || dbLength > 255; // must be analog to DbPlatformTypeMapping.lookup + return dbLength == 0 || dbLength > 4000; // must be analog to DbPlatformTypeMapping.lookup case DbPlatformType.JSONBlob: case DbPlatformType.JSONClob: return true; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java index 8931819a8..2b9899c56 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/DynamicPropertyAggregationFormula.java @@ -63,7 +63,7 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { } @Override - public boolean isDbLob() { + public boolean isLobForPlatform() { return false; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeProperty.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeProperty.java index df7ee17d1..e83c7a084 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeProperty.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/STreeProperty.java @@ -33,7 +33,7 @@ public interface STreeProperty extends ScalarDataReader { /** * Returns true, if this is a lob property from db-perspective. */ - boolean isDbLob(); + boolean isLobForPlatform(); /** * Return true if the property is an embedded type. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index 8a2465293..25ca77d87 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -48,7 +48,7 @@ public final class SqlTreeBuilder { private final SpiQuery.TemporalMode temporalMode; private SqlTreeNode rootNode; private boolean sqlDistinct; - private final boolean distinctNoLobs; + private final boolean platformDistinctNoLobs; private final SqlTreeCommon common; /** @@ -63,7 +63,7 @@ public final class SqlTreeBuilder { this.query = null; this.subQuery = false; this.distinctOnPlatform = false; - this.distinctNoLobs = false; + this.platformDistinctNoLobs = false; this.queryDetail = queryDetail; this.predicates = predicates; this.temporalMode = SpiQuery.TemporalMode.CURRENT; @@ -98,7 +98,7 @@ public final class SqlTreeBuilder { this.predicates = predicates; this.alias = new SqlTreeAlias(request.baseTableAlias(), temporalMode); this.distinctOnPlatform = builder.isPlatformDistinctOn(); - this.distinctNoLobs = builder.isPlatformDistinctNoLobs(); + this.platformDistinctNoLobs = builder.isPlatformDistinctNoLobs(); String fromForUpdate = builder.fromForUpdate(query); CQueryHistorySupport historySupport = builder.historySupport(query); CQueryDraftSupport draftSupport = builder.draftSupport(query); @@ -269,8 +269,8 @@ public final class SqlTreeBuilder { if (joinList != null) { joinList.add(selectNode); } - if (sqlDistinct && distinctNoLobs) { - selectNode.unselectLobs(); + if (sqlDistinct && platformDistinctNoLobs) { + selectNode.unselectLobsForPlatform(); } return selectNode; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java index 5aff65c43..afab4c5cf 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNode.java @@ -82,6 +82,6 @@ interface SqlTreeNode { /** * Unselect lobs (for distinct queries on DB2 and Oracle). */ - default void unselectLobs() { + default void unselectLobsForPlatform() { } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java index f37715131..e8c11be55 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/SqlTreeNodeBean.java @@ -379,16 +379,16 @@ class SqlTreeNodeBean implements SqlTreeNode { @Override - public void unselectLobs() { + public void unselectLobsForPlatform() { if (children != null) { for (SqlTreeNode child : children) { - child.unselectLobs(); + child.unselectLobsForPlatform(); } } if (hasLob()) { List lst = new ArrayList<>(); for (STreeProperty prop : properties) { - if (!prop.isDbLob()) { + if (!prop.isLobForPlatform()) { lst.add(prop); } } @@ -399,7 +399,7 @@ class SqlTreeNodeBean implements SqlTreeNode { private boolean hasLob() { for (STreeProperty prop : properties) { - if (prop.isDbLob()) { + if (prop.isLobForPlatform()) { return true; } } From 1f6e2ee844bea067790f298773860f3b1df6e564 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 7 Mar 2024 20:59:41 +1300 Subject: [PATCH 05/12] No effective change - update test only ClusterTest, increase wait to 200ms --- .../java/org/integration/ClusterTest.java | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/ebean-redis/src/test/java/org/integration/ClusterTest.java b/ebean-redis/src/test/java/org/integration/ClusterTest.java index 8a8142706..b5d4edb6d 100644 --- a/ebean-redis/src/test/java/org/integration/ClusterTest.java +++ b/ebean-redis/src/test/java/org/integration/ClusterTest.java @@ -1,12 +1,9 @@ package org.integration; -import io.ebean.DatabaseBuilder; -import io.ebean.redis.DuelCache; -import org.domain.Person; import io.ebean.DB; import io.ebean.Database; -import io.ebean.DatabaseFactory; -import io.ebean.config.DatabaseConfig; +import io.ebean.redis.DuelCache; +import org.domain.Person; import org.domain.query.QPerson; import org.junit.jupiter.api.Test; @@ -14,21 +11,21 @@ import javax.sql.DataSource; import static org.assertj.core.api.Assertions.assertThat; -public class ClusterTest { +class ClusterTest { private Database createOther(DataSource dataSource) { - DatabaseBuilder config = new DatabaseConfig(); - config.setDataSource(dataSource); - config.loadFromProperties(); - config.setDefaultServer(false); - config.setName("other"); - config.setDdlGenerate(false); - config.setDdlRun(false); - return DatabaseFactory.create(config); + return Database.builder() + .dataSource(dataSource) + .loadFromProperties() + .defaultDatabase(false) + .name("other") + .ddlGenerate(false) + .ddlRun(false) + .build(); } @Test - public void testBothNear() throws InterruptedException { + void testBothNear() throws InterruptedException { // ensure the default server exists first final Database db = DB.getDefault(); Database other = createOther(db.pluginApi().dataSource()); @@ -61,7 +58,7 @@ public class ClusterTest { } @Test - public void test() throws InterruptedException { + void test() throws InterruptedException { // ensure the default server exists first final Database db = DB.getDefault(); Database other = createOther(db.pluginApi().dataSource()); @@ -116,6 +113,6 @@ public class ClusterTest { } private void allowAsyncMessaging() throws InterruptedException { - Thread.sleep(100); + Thread.sleep(200); } } From 0816810d3b0718bc7df88da3d2b39d155455bbcc Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 7 Mar 2024 22:45:21 +1300 Subject: [PATCH 06/12] Refactor extract DbExpressionRequest interface for db platform specific expressions This provides a simpler DbExpressionRequest interface for db platform specific expression adapters (rather than the SpiExpressionRequest which has more features that we don't wish to expose to those expression adapters. --- .../api/SpiExpressionRequest.java | 6 ++++- .../expression/platform/BaseDbExpression.java | 5 ++--- .../platform/BasicDbExpression.java | 7 +++--- .../platform/DbExpressionHandler.java | 9 ++++---- .../platform/DbExpressionRequest.java | 22 +++++++++++++++++++ .../expression/platform/H2DbExpression.java | 3 +-- .../expression/platform/HanaDbExpression.java | 9 ++++---- .../platform/MariaDbExpression.java | 3 +-- .../platform/MySqlDbExpression.java | 3 +-- .../platform/OracleDbExpression.java | 9 ++++---- .../platform/PostgresDbExpression.java | 7 +++--- .../platform/SqlServerDbExpression.java | 7 +++--- 12 files changed, 53 insertions(+), 37 deletions(-) create mode 100644 ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionRequest.java diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java index 1b90140ee..b96317547 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiExpressionRequest.java @@ -3,13 +3,14 @@ package io.ebeaninternal.api; import io.ebeaninternal.server.core.SpiOrmQueryRequest; import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.expression.platform.DbExpressionHandler; +import io.ebeaninternal.server.expression.platform.DbExpressionRequest; import java.util.List; /** * Request object used for gathering expression sql and bind values. */ -public interface SpiExpressionRequest { +public interface SpiExpressionRequest extends DbExpressionRequest { /** * Return the DB specific handler for JSON and ARRAY expressions. @@ -34,11 +35,13 @@ public interface SpiExpressionRequest { /** * Append to the expression sql without any parsing. */ + @Override SpiExpressionRequest append(String expression); /** * Append to the expression sql without any parsing. */ + @Override SpiExpressionRequest append(char c); /** @@ -47,6 +50,7 @@ public interface SpiExpressionRequest { * This is a fast path case when expression is a bean property path and falls back to using parse() * when that isn't the case. */ + @Override SpiExpressionRequest property(String expression); /** diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java index a91131d53..e2007715d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BaseDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.BitwiseOp; /** @@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.BitwiseOp; abstract class BaseDbExpression implements DbExpressionHandler { @Override - public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { final String bitOp = bitOp(operator); request.append('(').property(propName).append(' ').append(bitOp).append(" ? ").append(compare).append(" ?)"); } @@ -28,7 +27,7 @@ abstract class BaseDbExpression implements DbExpressionHandler { /** * 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) { + protected void bitwiseFunction(DbExpressionRequest request, String propName, BitwiseOp operator, String compare) { final String funcName = functionName(operator); request.append(funcName).append('(').property(propName).append(", ?) ").append(compare).append(" ?"); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java index edecf8230..4f64e58fd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/BasicDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; /** @@ -9,17 +8,17 @@ import io.ebeaninternal.server.expression.Op; class BasicDbExpression extends BaseDbExpression { @Override - public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { throw new RuntimeException("JSON expressions only supported on Postgres and Oracle"); } @Override - public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) { + public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) { throw new RuntimeException("ARRAY expressions only supported on Postgres"); } @Override - public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { + public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) { throw new RuntimeException("ARRAY expressions only supported on Postgres"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java index 93c9dc18a..a376eb4e3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandler.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.BitwiseOp; import io.ebeaninternal.server.expression.Op; @@ -12,22 +11,22 @@ public interface DbExpressionHandler { /** * Write the db platform specific json expression. */ - void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value); + void json(DbExpressionRequest request, String propName, String path, Op operator, Object value); /** * Add SQL for ARRAY CONTAINS expression. */ - void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values); + void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values); /** * Add SQL for ARRAY IS EMPTY expression. */ - void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty); + void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty); /** * Add the bitwise expression. */ - void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match); + void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match); /** * Performs a "CONCAT" operation for that platform. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionRequest.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionRequest.java new file mode 100644 index 000000000..9b14fd33d --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionRequest.java @@ -0,0 +1,22 @@ +package io.ebeaninternal.server.expression.platform; + +/** + * Request building the expression sql. + */ +public interface DbExpressionRequest { + + /** + * Append to the expression sql without any parsing. + */ + DbExpressionRequest append(String expression); + + /** + * Append to the expression sql without any parsing. + */ + DbExpressionRequest append(char c); + + /** + * Append to the expression sql with logical property parsing to db columns with logical path prefix. + */ + DbExpressionRequest property(String expression); +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java index 8791cfa07..c72f89a66 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/H2DbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.BitwiseOp; /** @@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.BitwiseOp; final class H2DbExpression extends BasicDbExpression { @Override - public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + public void bitwise(DbExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { final String funcName = functionName(operator); request.append(funcName).append('(').property(propName).append(", cast(? as long)) ").append(compare).append(" cast(? as long)"); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java index 9c8910fca..282500da6 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/HanaDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.BitwiseOp; import io.ebeaninternal.server.expression.Op; @@ -10,17 +9,17 @@ import io.ebeaninternal.server.expression.Op; final class HanaDbExpression extends BaseDbExpression { @Override - public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + public void bitwise(DbExpressionRequest 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) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override - public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { + public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) { request.append("cardinality(").property(propName).append(')'); if (empty) { request.append(" = 0"); @@ -41,7 +40,7 @@ final class HanaDbExpression extends BaseDbExpression { } @Override - public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) { + public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) { for (int i = 0; i < values.length; i++) { if (i > 0) { request.append(" and "); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java index 6e336e642..2622cc2fe 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; /** @@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.Op; final class MariaDbExpression extends BasicDbExpression { @Override - public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { request.append('(').property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java index 59965abba..0c39856c3 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/MySqlDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; /** @@ -9,7 +8,7 @@ import io.ebeaninternal.server.expression.Op; final class MySqlDbExpression extends BasicDbExpression { @Override - public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { request.append('(').property(propName).append(" ->> '$.").append(path).append("')").append(operator.bind()); } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java index d51fbc23a..229aff32a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/OracleDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.BitwiseOp; import io.ebeaninternal.server.expression.Op; @@ -15,7 +14,7 @@ final class OracleDbExpression extends BaseDbExpression { } @Override - public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { if (operator == Op.EXISTS) { request.append("json_exists(").property(propName).append(", '$.").append(path).append("')"); } else if (operator == Op.NOT_EXISTS) { @@ -26,17 +25,17 @@ final class OracleDbExpression extends BaseDbExpression { } @Override - public void bitwise(SpiExpressionRequest request, String propName, BitwiseOp operator, long flags, String compare, long match) { + public void bitwise(DbExpressionRequest 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) { + public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) { throw new IllegalStateException("ARRAY expressions not supported on Oracle"); } @Override - public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { + public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) { throw new IllegalStateException("ARRAY expressions not supported on Oracle"); } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java index ab036d175..c3c71ae0e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/PostgresDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; /** @@ -14,7 +13,7 @@ final class PostgresDbExpression extends BaseDbExpression { } @Override - public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) { + public void json(DbExpressionRequest request, String propName, String path, Op operator, Object value) { String[] paths = path.split("\\."); if (paths.length == 1) { // (t0.content ->> 'title') = 'Some value' @@ -34,7 +33,7 @@ final class PostgresDbExpression extends BaseDbExpression { } @Override - public void arrayContains(SpiExpressionRequest request, String propName, boolean contains, Object... values) { + public void arrayContains(DbExpressionRequest request, String propName, boolean contains, Object... values) { if (!contains) { request.append("not ("); } @@ -49,7 +48,7 @@ final class PostgresDbExpression extends BaseDbExpression { } @Override - public void arrayIsEmpty(SpiExpressionRequest request, String propName, boolean empty) { + public void arrayIsEmpty(DbExpressionRequest request, String propName, boolean empty) { request.append("coalesce(cardinality(").property(propName).append("),0)"); if (empty) { request.append(" = 0"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java index c84482374..bc1d80e1f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/expression/platform/SqlServerDbExpression.java @@ -1,6 +1,5 @@ package io.ebeaninternal.server.expression.platform; -import io.ebeaninternal.api.SpiExpressionRequest; import io.ebeaninternal.server.expression.Op; /** @@ -9,19 +8,19 @@ import io.ebeaninternal.server.expression.Op; final class SqlServerDbExpression extends BaseDbExpression { @Override - public void json(final SpiExpressionRequest request, final String propName, + public void json(final DbExpressionRequest request, final String propName, final String path, final Op operator, final Object value) { request.append("json_value(").property(propName).append(", '$.").append(path).append("')").append(operator.bind()); } @Override - public void arrayContains(final SpiExpressionRequest request, final String propName, + public void arrayContains(final DbExpressionRequest request, final String propName, final boolean contains, final Object... values) { throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server"); } @Override - public void arrayIsEmpty(final SpiExpressionRequest request, final String propName, final boolean empty) { + public void arrayIsEmpty(final DbExpressionRequest request, final String propName, final boolean empty) { throw new RuntimeException("ARRAY expressions not supported on Microsoft SQL Server"); } } From 8b858a073ac75cf11ef15779855c393085b9f240 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Mon, 18 Mar 2024 07:38:30 +1300 Subject: [PATCH 07/12] feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select (#3362) * feat: Add includeLabelInSql configuration option to include query label as inline comment in generated sql select The generated select queries can look like: select /* MyInnerTest.insert_and_find */ t0.id, ... Using either query.setLabel() or profile location (which all query beans get by default). This means that tooling looking at sql in the database can more easily relate that sql back to application code. * More tests for labels with includeLabelInSql=true * Remove trim when using profileLocation label --- .../main/java/io/ebean/DatabaseBuilder.java | 15 ++++ .../java/io/ebean/config/DatabaseConfig.java | 18 +++++ .../config/dbplatform/DatabasePlatform.java | 7 ++ .../io/ebean/config/DatabaseConfigTest.java | 3 + .../server/query/CQueryBuilder.java | 30 ++++++-- .../server/query/CQueryEngine.java | 2 +- .../server/querydefn/DefaultDtoQuery.java | 3 + .../test/java/org/querytest/MyInnerTest.java | 8 +-- .../org/querytest/QCustomerAndOrTest.java | 5 +- .../java/org/querytest/QCustomerTest.java | 4 +- .../test/java/org/querytest/QOrderTest.java | 70 +++++++++---------- .../java/org/querytest/QueryAlsoIfTest.java | 4 +- .../resources/application-test.properties | 1 + .../ebean/xtest/base/DtoQueryFromOrmTest.java | 11 ++- .../io/ebean/xtest/base/FetchGroupTest.java | 3 +- .../src/test/resources/ebean.properties | 1 + 16 files changed, 129 insertions(+), 56 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java index 5c1c04581..985ba1760 100644 --- a/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java +++ b/ebean-api/src/main/java/io/ebean/DatabaseBuilder.java @@ -2209,6 +2209,15 @@ public interface DatabaseBuilder { @Deprecated DatabaseBuilder setLoadModuleInfo(boolean loadModuleInfo); + /** + * Set if generated SQL SELECT should include the query label as an + * inline SQL comment (to help reference back from the SQL to the code + * that executed the query. + * + * @param includeLabelInSql When true include a SQL inline comment in generated SELECT queries. + */ + DatabaseConfig includeLabelInSql(boolean includeLabelInSql); + /** * Set the naming convention to apply to metrics names. */ @@ -3104,6 +3113,12 @@ public interface DatabaseBuilder { */ boolean isLoadModuleInfo(); + /** + * Return true if generated sql select query should include an inline sql comment with the + * query label or profile location label. + */ + boolean isIncludeLabelInSql(); + /** * Return the naming convention to apply to metrics names. */ diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index 4c69d7aec..3f30b9a38 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -125,6 +125,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { */ private boolean loadModuleInfo = true; + /** + * When true then include a sql comment in generated SELECT queries with the query + * label or profile location label. + */ + private boolean includeLabelInSql; + /** * Interesting classes such as entities, embedded, ScalarTypes, * Listeners, Finders, Controllers, AttributeConverters etc. @@ -2133,6 +2139,7 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { readOnlyDatabase = p.getBoolean("readOnlyDatabase", readOnlyDatabase); autoPersistUpdates = p.getBoolean("autoPersistUpdates", autoPersistUpdates); loadModuleInfo = p.getBoolean("loadModuleInfo", loadModuleInfo); + includeLabelInSql = p.getBoolean("includeLabelInSql", includeLabelInSql); maxCallStack = p.getInt("maxCallStack", maxCallStack); dumpMetricsOnShutdown = p.getBoolean("dumpMetricsOnShutdown", dumpMetricsOnShutdown); dumpMetricsOptions = p.get("dumpMetricsOptions", dumpMetricsOptions); @@ -2547,6 +2554,11 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { return loadModuleInfo; } + @Override + public boolean isIncludeLabelInSql() { + return includeLabelInSql; + } + /** * @deprecated - migrate to {@link #isLoadModuleInfo()}. */ @@ -2563,6 +2575,12 @@ public class DatabaseConfig implements DatabaseBuilder.Settings { return this; } + @Override + public DatabaseConfig includeLabelInSql(boolean includeLabelInSql) { + this.includeLabelInSql = includeLabelInSql; + return this; + } + @Override public Function getMetricNaming() { return metricNaming; diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 5c4f33cc1..67051b51d 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -769,4 +769,11 @@ public class DatabasePlatform { public boolean supportsNativeJavaTime() { return supportsNativeJavaTime; } + + public String inlineSqlComment(String label) { + if (label == null) { + return ""; + } + return "/* " + label + " */ "; + } } diff --git a/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java b/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java index 9b5afb2b0..018b5921f 100644 --- a/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java +++ b/ebean-api/src/test/java/io/ebean/config/DatabaseConfigTest.java @@ -76,6 +76,7 @@ class DatabaseConfigTest { props.setProperty("skipDataSourceCheck", "true"); props.setProperty("readOnlyDatabase", "true"); props.setProperty("lengthCheck", "ON"); + props.setProperty("includeLabelInSql", "true"); props.setProperty("queryPlan.enable", "true"); props.setProperty("queryPlan.thresholdMicros", "10000"); @@ -96,6 +97,7 @@ class DatabaseConfigTest { assertTrue(settings.isLoadModuleInfo()); assertTrue(settings.skipDataSourceCheck()); assertTrue(settings.readOnlyDatabase()); + assertTrue(settings.isIncludeLabelInSql()); assertThat(settings.getLengthCheck()).isEqualTo(LengthCheck.ON); assertTrue(settings.isIdGeneratorAutomatic()); @@ -181,6 +183,7 @@ class DatabaseConfigTest { assertEquals(10000L, config.getQueryPlanCaptureMaxTimeMillis()); assertEquals(10, config.getQueryPlanCaptureMaxCount()); assertThat(config.getLengthCheck()).isEqualTo(LengthCheck.OFF); + assertFalse(config.isIncludeLabelInSql()); config.setLoadModuleInfo(false); assertFalse(config.isAutoLoadModuleInfo()); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 2b6664367..d94dde3a9 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -1,9 +1,6 @@ package io.ebeaninternal.server.query; -import io.ebean.CountDistinctOrder; -import io.ebean.Query; -import io.ebean.RawSql; -import io.ebean.RawSqlBuilder; +import io.ebean.*; import io.ebean.annotation.Platform; import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.SqlLimitRequest; @@ -52,11 +49,13 @@ final class CQueryBuilder { private final CQueryDraftSupport draftSupport; private final DatabasePlatform dbPlatform; private final boolean selectCountWithColumnAlias; + private final boolean includeLabelInSql; /** * Create the SqlGenSelect. */ - CQueryBuilder(DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + CQueryBuilder(DatabaseBuilder.Settings config, DatabasePlatform dbPlatform, Binder binder, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport) { + this.includeLabelInSql = config.isIncludeLabelInSql(); this.dbPlatform = dbPlatform; this.binder = binder; this.draftSupport = draftSupport; @@ -596,7 +595,7 @@ final class CQueryBuilder { } private void appendSelectDistinct() { - sb.append("select "); + sb.append("select ").append(inlineSqlComment()); if (distinct && !countSingleAttribute) { if (request.isInlineCountDistinct()) { sb.append("count("); @@ -609,6 +608,25 @@ final class CQueryBuilder { } } + private String inlineSqlComment() { + if (!includeLabelInSql) { + return ""; + } + SpiQuery.Type type = query.type(); + if (type == SpiQuery.Type.SQ_EX || type == SpiQuery.Type.SQ_EXISTS) { + return ""; + } + final var label = query.label(); + if (label != null) { + return dbPlatform.inlineSqlComment(label); + } + final var profileLocation = query.profileLocation(); + if (profileLocation != null) { + return dbPlatform.inlineSqlComment(profileLocation.label()); + } + return ""; + } + private void appendFrom() { if (selectClause == null || !selectClause.startsWith("update")) { sb.append(" from "); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java index a0dab920a..2a51dd515 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryEngine.java @@ -44,7 +44,7 @@ public final class CQueryEngine { this.defaultFetchSizeFindList = config.getJdbcFetchSizeFindList(); this.forwardOnlyHintOnFindIterate = dbPlatform.forwardOnlyHintOnFindIterate(); this.historySupport = new CQueryHistorySupport(dbPlatform.historySupport(), asOfTableMapping, config.getAsOfSysPeriod()); - this.queryBuilder = new CQueryBuilder(dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap)); + this.queryBuilder = new CQueryBuilder(config, dbPlatform, binder, historySupport, new CQueryDraftSupport(draftTableMap)); } public int forwardOnlyFetchSize() { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java index 7d3b571a1..bbaf19b3e 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultDtoQuery.java @@ -250,6 +250,9 @@ public final class DefaultDtoQuery extends AbstractQuery implements SpiDtoQue @Override public DtoQuery setLabel(String label) { this.label = label; + if (ormQuery != null) { + ormQuery.setLabel(label); + } return this; } diff --git a/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java b/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java index e196cf61b..89c40927c 100644 --- a/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java +++ b/ebean-querybean/src/test/java/org/querytest/MyInnerTest.java @@ -68,9 +68,9 @@ class MyInnerTest { List sql = LoggedSql.stop(); assertThat(sql).hasSize(4); - assertThat(sql.get(0)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.one = ?;"); - assertThat(sql.get(1)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.description = ?;"); - assertThat(sql.get(2)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.description = ?;"); - assertThat(sql.get(3)).contains("select t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.one > ? and t0.one >= ? and t0.one < ? and t0.one <= ? and t0.id > ?;"); + assertThat(sql.get(0)).contains("select /* MyInnerTest.insert_and_find:36 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.one = ?;"); + assertThat(sql.get(1)).contains("select /* MyInnerTest.insert_and_find:43 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.description = ?;"); + assertThat(sql.get(2)).contains("select /* MyInnerTest.insert_and_find:54 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.description = ?;"); + assertThat(sql.get(3)).contains("select /* MyInnerTest.insert_and_find:65 */ t0.id, t0.one, t0.id, t0.one, t0.description from my_inner t0 where t0.id < ? and t0.one > ? and t0.one >= ? and t0.one < ? and t0.one <= ? and t0.id > ?;"); } } diff --git a/ebean-querybean/src/test/java/org/querytest/QCustomerAndOrTest.java b/ebean-querybean/src/test/java/org/querytest/QCustomerAndOrTest.java index 7862e0dcd..338741bea 100644 --- a/ebean-querybean/src/test/java/org/querytest/QCustomerAndOrTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QCustomerAndOrTest.java @@ -62,6 +62,7 @@ public class QCustomerAndOrTest { @Test public void testOrWithExists() { QCustomer query = Customer.find.typed() + .setLabel("hiLabel") .alias("_cust") .or() .name.eq("Superman") @@ -72,12 +73,12 @@ public class QCustomerAndOrTest { .query() ) .endOr() - .select(QCustomer.alias().id); + .select(QCustomer.Alias.id); query.findList(); assertThat(query.getGeneratedSql()).isEqualTo( - "select _cust.id from be_customer _cust where (" + + "select /* hiLabel */ _cust.id from be_customer _cust where (" + "_cust.name = ? or exists (select 1 from be_contact contact where " + "contact.first_name = ? and contact.customer_id = _cust.id))" ); diff --git a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java index 5c25c91e9..c72770c37 100644 --- a/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QCustomerTest.java @@ -284,7 +284,7 @@ public class QCustomerTest { .query(); q.findList(); - assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' and t1.email is not null order by t0.id"); + assertThat(q.getGeneratedSql()).isEqualTo("select /* QCustomerTest.filterMany */ t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' and t1.email is not null order by t0.id"); } @Test @@ -296,7 +296,7 @@ public class QCustomerTest { .query(); q.findList(); - assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' order by t0.id"); + assertThat(q.getGeneratedSql()).isEqualTo("select /* QCustomerTest.filterManySingle */ t0.id, t0.name, t1.id, t1.first_name, t1.last_name from be_customer t0 left join be_contact t1 on t1.customer_id = t0.id where t1.first_name like ? escape'|' order by t0.id"); } @Test diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index 44627581d..77ee35ac4 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -22,7 +22,7 @@ import java.util.List; import static io.ebean.StdOperators.*; import static org.assertj.core.api.Assertions.assertThat; -public class QOrderTest { +class QOrderTest { private static final QCustomer cu = QCustomer.alias(); @@ -89,12 +89,12 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0"); - assertThat(sql.get(1)).contains("select t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from be_contact t0 where"); + assertThat(sql.get(0)).contains("select /* QOrderTest.fetchQueryWithBatch */ t0.id, t0.name, t0.phone_number from be_customer t0"); + assertThat(sql.get(1)).contains("select /* QOrderTest.fetchQueryWithBatch_contacts__query */ t0.customer_id, t0.id, t0.first_name, t0.last_name, t0.email from be_contact t0 where"); } @Test - public void fetchCache() { + void fetchCache() { new QOrder() .status.eq(Order.Status.NEW) @@ -108,7 +108,7 @@ public class QOrderTest { } @Test - public void viaFetchGraph() { + void viaFetchGraph() { DB.getDefault(); LoggedSql.start(); @@ -121,11 +121,11 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where"); + assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph */ t0.id, t0.status, t0.ship_date, t0.customer_id from o_order t0 where"); } @Test - public void viaFetchGraph_withJoin() { + void viaFetchGraph_withJoin() { DB.getDefault(); LoggedSql.start(); @@ -138,11 +138,11 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); + assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withJoin */ t0.id, t0.status, t1.id, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); } @Test - public void viaFetchGraph_withNested() { + void viaFetchGraph_withNested() { DB.getDefault(); LoggedSql.start(); @@ -154,11 +154,11 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); + assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested */ t0.id, t0.status, t0.ship_date, t1.id, t1.name, t1.phone_number from o_order t0 join be_customer t1 on t1.id = t0.customer_id where"); } @Test - public void viaFetchGraph_withNested_fetchQuery() { + void viaFetchGraph_withNested_fetchQuery() { DB.getDefault(); LoggedSql.start(); @@ -172,15 +172,15 @@ public class QOrderTest { // assert fetching customer via fetchQuery assertThat(sql).hasSize(2); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); - assertThat(sql.get(1)).contains("select t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?"); + assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery */ t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); + assertThat(sql.get(1)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery_customer__query */ t0.id, t0.name, t0.phone_number from be_customer t0 where t0.id = ?"); assertThat(found.getCustomer().getPhoneNumber().getMsisdn()).isEqualTo("Ph1"); } @Test - public void viaFetchGraph_withNested_fetchCache() { + void viaFetchGraph_withNested_fetchCache() { DB.getDefault(); @@ -201,11 +201,11 @@ public class QOrderTest { // assert we only hit DB for order assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); + assertThat(sql.get(0)).contains("select /* QOrderTest.viaFetchGraph_withNested_fetchQuery */ t0.id, t0.status, t0.customer_id from o_order t0 where t0.id = ?"); } @Test - public void select_partial() { + void select_partial() { DB.getDefault(); LoggedSql.start(); @@ -218,11 +218,11 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t0.order_date from o_order t0"); + assertThat(sql.get(0)).contains("select /* QOrderTest.select_partial */ t0.id, t0.status, t0.order_date from o_order t0"); } @Test - public void fetch_partial() { + void fetch_partial() { DB.getDefault(); LoggedSql.start(); @@ -237,12 +237,12 @@ public class QOrderTest { final List sql = LoggedSql.stop(); assertThat(sql).hasSize(1); - assertThat(sql.get(0)).contains("select t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id"); + assertThat(sql.get(0)).contains("select /* QOrderTest.fetch_partial */ t0.id, t0.status, t1.id, t1.email, t1.name from o_order t0 join be_customer t1 on t1.id = t0.customer_id"); } @Test - public void updateQuery() { + void updateQuery() { LoggedSql.start(); new QOrder() .status.eq(Order.Status.COMPLETE) @@ -258,7 +258,7 @@ public class QOrderTest { } @Test - public void stdExpression_iLikeConcatCoalesce() { + void stdExpression_iLikeConcatCoalesce() { QOrder o = QOrder.alias(); // LOWER(CONCAT(COALESCE(a.name, ""), ":", a.description)) LIKE LOWER(:param) @@ -273,7 +273,7 @@ public class QOrderTest { } @Test - public void stdExpression_gtCoalesce() { + void stdExpression_gtCoalesce() { QOrder o = QOrder.alias(); Query query = new QOrder() @@ -288,7 +288,7 @@ public class QOrderTest { String sql = query.getGeneratedSql(); assertThat(sql).contains(" where (coalesce(t1.version,0) > ? or t0.id < ?)"); - assertThat(sql).isEqualTo("select t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)"); + assertThat(sql).isEqualTo("select /* QOrderTest.stdExpression_gtCoalesce */ t0.id, t0.status from o_order t0 join be_customer t1 on t1.id = t0.customer_id where (coalesce(t1.version,0) > ? or t0.id < ?)"); } @Test @@ -301,7 +301,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.geSqlSubQuery */ t0.id from be_customer t0 where t0.registered >= (select max(o.order_date) as foo from o_order o)"); } @Test @@ -314,7 +314,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.gtSqlSubQuery */ t0.id from be_customer t0 where t0.registered > (select max(o.order_date) as foo from o_order o)"); } @Test @@ -327,7 +327,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.leSqlSubQuery */ t0.id from be_customer t0 where t0.registered <= (select max(o.order_date) as foo from o_order o)"); } @Test @@ -340,7 +340,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.ltSqlSubQuery */ t0.id from be_customer t0 where t0.registered < (select max(o.order_date) as foo from o_order o)"); } @Test @@ -353,7 +353,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.eqSqlSubQuery */ t0.id from be_customer t0 where t0.registered = (select max(o.order_date) as foo from o_order o)"); } @Test @@ -366,7 +366,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.neSqlSubQuery */ t0.id from be_customer t0 where t0.registered <> (select max(o.order_date) as foo from o_order o)"); } @Test @@ -384,7 +384,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered >= (select max(t0.order_date) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.geSubQuery */ t0.id from be_customer t0 where t0.registered >= (select max(t0.order_date) from o_order t0)"); } @Test @@ -399,7 +399,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.version > (select sum(t0.version) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.gtSubQuery */ t0.id from be_customer t0 where t0.version > (select sum(t0.version) from o_order t0)"); } @Test @@ -414,7 +414,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <= (select max(t0.order_date) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.leSubQuery */ t0.id from be_customer t0 where t0.registered <= (select max(t0.order_date) from o_order t0)"); } @Test @@ -429,7 +429,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered < (select max(t0.order_date) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.ltSubQuery */ t0.id from be_customer t0 where t0.registered < (select max(t0.order_date) from o_order t0)"); } @Test @@ -444,7 +444,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered = (select max(t0.order_date) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.eqSubQuery */ t0.id from be_customer t0 where t0.registered = (select max(t0.order_date) from o_order t0)"); } @Test @@ -459,7 +459,7 @@ public class QOrderTest { .query(); query.findList(); - assertThat(query.getGeneratedSql()).contains("select t0.id from be_customer t0 where t0.registered <> (select max(t0.order_date) from o_order t0)"); + assertThat(query.getGeneratedSql()).contains("select /* QOrderTest.neSubQuery */ t0.id from be_customer t0 where t0.registered <> (select max(t0.order_date) from o_order t0)"); } @Test diff --git a/ebean-querybean/src/test/java/org/querytest/QueryAlsoIfTest.java b/ebean-querybean/src/test/java/org/querytest/QueryAlsoIfTest.java index 3ccc58879..a9a4dbf50 100644 --- a/ebean-querybean/src/test/java/org/querytest/QueryAlsoIfTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QueryAlsoIfTest.java @@ -20,7 +20,7 @@ class QueryAlsoIfTest { .query(); q.findList(); - assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name from be_customer t0 where t0.name is not null and t0.status = ?"); + assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.apply */ t0.id, t0.name from be_customer t0 where t0.name is not null and t0.status = ?"); } @Test @@ -32,6 +32,6 @@ class QueryAlsoIfTest { .query(); q.findList(); - assertThat(q.getGeneratedSql()).isEqualTo("select t0.id, t0.name from be_customer t0 where t0.name is not null"); + assertThat(q.getGeneratedSql()).isEqualTo("select /* QueryAlsoIfTest.notApply */ t0.id, t0.name from be_customer t0 where t0.name is not null"); } } diff --git a/ebean-querybean/src/test/resources/application-test.properties b/ebean-querybean/src/test/resources/application-test.properties index 9c1b1a919..5b5481d45 100644 --- a/ebean-querybean/src/test/resources/application-test.properties +++ b/ebean-querybean/src/test/resources/application-test.properties @@ -3,6 +3,7 @@ ebean.ddl.run=true ebean.ddl.initSql=init-db.sql ebean.dumpMetricsOnShutdown=true ebean.dumpMetricsOptions=sql,hash,loc +ebean.includeLabelInSql=true datasource.default=h2 diff --git a/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java b/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java index 6505e120d..83982fbc1 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java @@ -164,8 +164,13 @@ public class DtoQueryFromOrmTest extends BaseTestCase { DtoQuery query = DB.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").order().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(); @@ -178,7 +183,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSql.stop(); - assertSql(sql.get(0)).contains("select t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + assertSql(sql.get(0)).contains("select /* explicitId */ 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"); } diff --git a/ebean-test/src/test/java/io/ebean/xtest/base/FetchGroupTest.java b/ebean-test/src/test/java/io/ebean/xtest/base/FetchGroupTest.java index 010d6460c..24708348c 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/base/FetchGroupTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/base/FetchGroupTest.java @@ -26,11 +26,12 @@ public class FetchGroupTest extends BaseTestCase { .query() .where() .ilike("name", "rob") + .setLabel("hello") .select(fetch); query.findList(); - assertThat(sqlOf(query)).contains("select t0.id, t0.name, t0.status from"); + assertThat(sqlOf(query)).contains("select /* hello */ t0.id, t0.name, t0.status from"); } diff --git a/ebean-test/src/test/resources/ebean.properties b/ebean-test/src/test/resources/ebean.properties index 6bd984585..739bc554c 100644 --- a/ebean-test/src/test/resources/ebean.properties +++ b/ebean-test/src/test/resources/ebean.properties @@ -17,6 +17,7 @@ ebean.encryptKeyManager=org.tests.basic.encrypt.BasicEncyptKeyManager #ebean.autoTune.mode=DEFAULT_ON #ebean.autoTune.profiling=true #ebean.autoTune.profilingUpdateFrequency=5 +ebean.includeLabelInSql=true ebean.ddl.generate=true ebean.ddl.run=true From 540ceab96f218e2877c75ca53064f5a99986c08d Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 20 Mar 2024 21:48:43 +1300 Subject: [PATCH 08/12] feat: Add query.setHint() to support sql hint as inline comment in select queries (#3365) * feat: Add query.setHint() to support sql hint as inline comment in select queries This is for ORM queries only. An ORM query like: new QCustomer() .setHint("FirstRows") .select(QCustomer.Alias.id, QCustomer.Alias.name) .findList(); Produces SQL that includes the hint as an inline comment like: select /*+ FirstRows */ t0.id, t0.name from customer t0 * Fix test QOrderTest --- ebean-api/src/main/java/io/ebean/Query.java | 8 +++++++ .../config/dbplatform/DatabasePlatform.java | 4 ++++ .../java/io/ebeaninternal/api/SpiQuery.java | 5 +++++ .../server/persist/BatchControl.java | 2 +- .../server/query/CQueryBuilder.java | 7 ++++++- .../server/query/DefaultFetchGroupQuery.java | 5 +++++ .../server/querydefn/DefaultOrmQuery.java | 16 ++++++++++++++ .../server/querydefn/OrmQueryPlanKeyTest.java | 21 +++++++++++++++++++ .../java/io/ebean/typequery/TQRootBean.java | 11 ++++++++++ .../test/java/org/querytest/QOrderTest.java | 19 +++++++++++++---- .../ebean/xtest/base/DtoQueryFromOrmTest.java | 3 ++- 11 files changed, 94 insertions(+), 7 deletions(-) diff --git a/ebean-api/src/main/java/io/ebean/Query.java b/ebean-api/src/main/java/io/ebean/Query.java index ef941aa1f..c48474ac7 100644 --- a/ebean-api/src/main/java/io/ebean/Query.java +++ b/ebean-api/src/main/java/io/ebean/Query.java @@ -1601,6 +1601,14 @@ public interface Query extends CancelableQuery { */ Query setLabel(String label); + /** + * Set a SQL query hint. + *

+ * This results in an inline comment that immediately follows + * after the select keyword in the form: {@code /*+ hint *\/ } + */ + Query setHint(String hint); + /** * Set to true if this query should execute against the doc store. *

diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 67051b51d..29b554c48 100644 --- a/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -776,4 +776,8 @@ public class DatabasePlatform { } return "/* " + label + " */ "; } + + public String inlineSqlHint(String hint) { + return "/*+ " + hint + " */ "; + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java index 5669dcf57..a4696508d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/api/SpiQuery.java @@ -226,6 +226,11 @@ public interface SpiQuery extends Query, SpiQueryFetch, TxnProfileEventCod */ ProfileLocation profileLocation(); + /** + * Return the SQL hint to include in the query. + */ + String hint(); + /** * Return the label set on the query. */ diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java index 08e6bc6ab..24ed757e4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/BatchControl.java @@ -226,7 +226,7 @@ public final class BatchControl { void executeNow(ArrayList list) throws BatchedSqlException { boolean old = transaction.isFlushOnQuery(); transaction.setFlushOnQuery(false); - // disable flush on query due transsaction callbacks + // disable flush on query due transaction callbacks try { for (int i = 0; i < list.size(); i++) { if (i % batchSize == 0) { diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index d94dde3a9..9147eefe0 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -595,7 +595,7 @@ final class CQueryBuilder { } private void appendSelectDistinct() { - sb.append("select ").append(inlineSqlComment()); + sb.append("select ").append(hint()).append(inlineSqlComment()); if (distinct && !countSingleAttribute) { if (request.isInlineCountDistinct()) { sb.append("count("); @@ -608,6 +608,11 @@ final class CQueryBuilder { } } + private String hint() { + String hint = query.hint(); + return hint == null ? "" : dbPlatform.inlineSqlHint(hint); + } + private String inlineSqlComment() { if (!includeLabelInSql) { return ""; diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java index c4a3b965b..aca22b8bc 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/DefaultFetchGroupQuery.java @@ -133,6 +133,11 @@ final class DefaultFetchGroupQuery implements SpiFetchGroupQuery, SpiQuery return this; } + @Override + public Query setHint(String hint) { + throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup"); + } + // Everything else deemed invalid @Override diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java index f877be126..abe89c40a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -57,6 +57,7 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { private ProfilingListener profilingListener; private Type type; private String label; + private String hint; private Mode mode = Mode.NORMAL; private boolean usingFuture; private Object tenantId; @@ -235,6 +236,11 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { return label; } + @Override + public final String hint() { + return hint; + } + @Override public final String planLabel() { if (label != null) { @@ -258,6 +264,12 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { return this; } + @Override + public final Query setHint(String hint) { + this.hint = hint; + return this; + } + @Override public final boolean isAutoTunable() { return nativeSql == null && beanDescriptor.isAutoTunable(); @@ -732,6 +744,7 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { copy.timeout = timeout; copy.mapKey = mapKey; copy.id = id; + copy.hint = hint; copy.label = label; copy.nativeSql = nativeSql; copy.useBeanCache = useBeanCache; @@ -1069,6 +1082,9 @@ public class DefaultOrmQuery extends AbstractQuery implements SpiQuery { if (manualId) { sb.append("/md"); } + if (hint != null) { + sb.append("/h:").append(hint); + } if (distinct) { sb.append("/dt"); } diff --git a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java index 6e181573b..fbe02353d 100644 --- a/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java +++ b/ebean-core/src/test/java/io/ebeaninternal/server/querydefn/OrmQueryPlanKeyTest.java @@ -29,6 +29,27 @@ public class OrmQueryPlanKeyTest extends BaseTest { assertSame(query().createQueryPlanKey(), query().createQueryPlanKey()); } + @Test + public void equals_when_hintIsDifferent_expect_different() { + DefaultOrmQuery q1 = query(); + q1.setHint("a"); + assertDifferent(q1, query()); + + DefaultOrmQuery q2 = query(); + q2.setHint("b"); + assertDifferent(q1, q2); + } + + @Test + public void equals_when_hintIsSame() { + DefaultOrmQuery q1 = query(); + q1.setHint("b"); + DefaultOrmQuery q2 = query(); + q2.setHint("b"); + + assertSame(q1, q2); + } + @Test public void equals_when_diffTableJoinNull() { diff --git a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java index 48125150e..4584bea31 100644 --- a/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java +++ b/ebean-querybean/src/main/java/io/ebean/typequery/TQRootBean.java @@ -912,6 +912,17 @@ public abstract class TQRootBean { return root; } + /** + * Set a SQL query hint. + *

+ * This results in an inline comment that immediately follows + * after the select keyword in the form: {@code /*+ hint *\/ } + */ + public R setHint(String hint) { + query.setHint(hint); + return root; + } + /** * Set the profile location. *

diff --git a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java index 77ee35ac4..9fd331291 100644 --- a/ebean-querybean/src/test/java/org/querytest/QOrderTest.java +++ b/ebean-querybean/src/test/java/org/querytest/QOrderTest.java @@ -79,6 +79,19 @@ class QOrderTest { DB.delete(customer); } + @Test + void hint() { + LoggedSql.start(); + new QCustomer() + .setHint("FirstRows") + .select(QCustomer.Alias.id, QCustomer.Alias.name) + .findList(); + + List sql = LoggedSql.stop(); + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("select /*+ FirstRows */ /* QOrderTest.hint */ t0.id, t0.name from be_customer t0"); + } + @Test void fetchQueryWithBatch() { LoggedSql.start(); @@ -159,8 +172,7 @@ class QOrderTest { @Test void viaFetchGraph_withNested_fetchQuery() { - - DB.getDefault(); + DB.cacheManager().clearAll(); LoggedSql.start(); final Order found = new QOrder() @@ -181,8 +193,7 @@ class QOrderTest { @Test void viaFetchGraph_withNested_fetchCache() { - - DB.getDefault(); + DB.cacheManager().clearAll(); // ensure the customer is loaded in the L2 cache new QCustomer().id.eq(customer.getId()).findOne(); diff --git a/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java b/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java index 83982fbc1..f9f8d02cd 100644 --- a/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java +++ b/ebean-test/src/test/java/io/ebean/xtest/base/DtoQueryFromOrmTest.java @@ -164,6 +164,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { DtoQuery query = DB.find(Contact.class) // we must explicitly add the id property for DTO query (if we want it) + .setHint("SomeHint") .select("id, email, " + concat("lastName", ", ", "firstName") + " as fullName") .where() .isNotNull("email") @@ -183,7 +184,7 @@ public class DtoQueryFromOrmTest extends BaseTestCase { } List sql = LoggedSql.stop(); - assertSql(sql.get(0)).contains("select /* explicitId */ t0.id, t0.email, " + concat("t0.last_name", ", ", "t0.first_name") + assertSql(sql.get(0)).contains("select /*+ SomeHint */ /* explicitId */ 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"); } From 0b11c541c81cd1b2494568611367a25dba710432 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 21 Mar 2024 00:14:54 +1300 Subject: [PATCH 09/12] fix: #3142 Cascading a OneToMany, set the relationship when the child isn't new or dirty (#3366) That is, previously the relationship back from the child to the parent was being updated when the child bean was new or dirty BUT NOT in the case when the child bean was loaded and unchanged. This fix includes that case updating the ManyToOne side of the relationship on the child when the save is cascaded. --- .../server/deploy/BeanPropertyAssocMany.java | 30 +++++++++- .../server/persist/SaveManyBeans.java | 4 +- .../saveassociation/TestSaveAssociation.java | 58 +++++++++++++++++-- 3 files changed, 84 insertions(+), 8 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java index 423f5415c..ef6643e4d 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanPropertyAssocMany.java @@ -588,10 +588,9 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST } /** - * Set the join properties from the parent bean to the child bean. - * This is only valid for OneToMany and NOT valid for ManyToMany. + * Set the parent bean to the child (update the relationship). */ - public void setJoinValuesToChild(EntityBean parent, EntityBean child, Object mapKeyValue) { + public void setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue) { if (mapKeyProperty != null) { mapKeyProperty.setValue(child, mapKeyValue); } @@ -602,6 +601,31 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc implements ST } } + /** + * Return true if the parent bean has been set to the child (updated the relationship). + */ + public boolean setParentToChild(EntityBean parent, EntityBean child, Object mapKeyValue, BeanDescriptor parentDesc) { + if (manyToMany + || childMasterProperty == null + || !child._ebean_getIntercept().isLoadedProperty(childMasterProperty.propertyIndex())) { + return false; + } + + Object currentParent = childMasterProperty.getValue(child); + if (currentParent != null) { + Object newId = parentDesc.getId(parent); + Object oldId = parentDesc.id(currentParent); + if (Objects.equals(newId, oldId)) { + return false; + } + } + childMasterProperty.setValueIntercept(child, parent); + if (mapKeyProperty != null) { + mapKeyProperty.setValue(child, mapKeyValue); + } + return true; + } + /** * Return the order by clause used to order the fetching of the data for * this list, set or map. diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java index e82c16961..b6e5d8a96 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java @@ -172,7 +172,9 @@ final class SaveManyBeans extends SaveManyBase { } else if (ebi.isNewOrDirty()) { skipSavingThisBean = false; // set the parent bean to detailBean - many.setJoinValuesToChild(parentBean, detail, mapKeyValue); + many.setParentToChild(parentBean, detail, mapKeyValue); + } else if (many.setParentToChild(parentBean, detail, mapKeyValue, request.descriptor())) { + skipSavingThisBean = false; } else { skipSavingThisBean = saveRecurseSkippable; } diff --git a/ebean-test/src/test/java/org/tests/saveassociation/TestSaveAssociation.java b/ebean-test/src/test/java/org/tests/saveassociation/TestSaveAssociation.java index 41ae6c338..5f19f102f 100644 --- a/ebean-test/src/test/java/org/tests/saveassociation/TestSaveAssociation.java +++ b/ebean-test/src/test/java/org/tests/saveassociation/TestSaveAssociation.java @@ -6,12 +6,12 @@ import org.junit.jupiter.api.Test; import org.tests.model.basic.TSDetail; import org.tests.model.basic.TSMaster; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.assertj.core.api.Assertions.assertThat; -public class TestSaveAssociation extends BaseTestCase { +class TestSaveAssociation extends BaseTestCase { @Test - public void test() { + void test() { TSMaster m0 = new TSMaster(); m0.setName("master1"); @@ -26,7 +26,57 @@ public class TestSaveAssociation extends BaseTestCase { TSMaster m0Check = DB.find(TSMaster.class).fetch("details").where().idEq(m0.getId()) .findOne(); - assertEquals(2, m0Check.getDetails().size()); + assertThat(m0Check.getDetails()).hasSize(2); + DB.delete(m0); } + + @Test + void testCascadeSetParent() { + // setup + TSDetail detail = new TSDetail("master1 detail1"); + DB.save(detail); + + // act + TSMaster m0 = new TSMaster(); + m0.setName("master2"); + m0.addDetail(detail); + DB.save(m0); + + // assert + TSMaster check = DB.find(TSMaster.class).fetch("details") + .where().idEq(m0.getId()) + .findOne(); + + assertThat(check.getDetails()).hasSize(1); + assertThat(check.getDetails().get(0).getId()).isEqualTo(detail.getId()); + DB.delete(m0); + } + + @Test + void testCascadeChangeParent() { + // setup + TSDetail detail = new TSDetail("master3 detail1"); + TSMaster m0 = new TSMaster(); + m0.setName("master3"); + m0.addDetail(detail); + DB.save(m0); + + // act + TSMaster m1 = new TSMaster(); + m1.setName("master4"); + m1.addDetail(detail); + DB.save(m1); + + // assert + TSMaster check = DB.find(TSMaster.class).fetch("details") + .where().idEq(m1.getId()) + .findOne(); + + assertThat(check.getDetails()).hasSize(1); + assertThat(check.getDetails().get(0).getId()).isEqualTo(detail.getId()); + + DB.delete(m1); + DB.delete(TSMaster.class, m0.getId()); + } } From 582fec7ce45277707f177f0758ad5ae202f18a14 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 21 Mar 2024 21:51:10 +1300 Subject: [PATCH 10/12] For #3363 disable flushOnQuery before BeanPersistAdapter post-processors (#3367) --- .../server/core/PersistRequestBean.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java index f13227fc5..d6145f514 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/PersistRequestBean.java @@ -919,21 +919,27 @@ public final class PersistRequestBean extends PersistRequest implements BeanP } private void controllerPost() { - switch (type) { - case INSERT: - controller.postInsert(this); - break; - case UPDATE: - controller.postUpdate(this); - break; - case DELETE_SOFT: - controller.postSoftDelete(this); - break; - case DELETE: - controller.postDelete(this); - break; - default: - break; + boolean old = transaction.isFlushOnQuery(); + transaction.setFlushOnQuery(false); + try { + switch (type) { + case INSERT: + controller.postInsert(this); + break; + case UPDATE: + controller.postUpdate(this); + break; + case DELETE_SOFT: + controller.postSoftDelete(this); + break; + case DELETE: + controller.postDelete(this); + break; + default: + break; + } + } finally { + transaction.setFlushOnQuery(old); } } From 24b514f8510df5fdb8f9e3b1e50bc54c1f68d535 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 21 Mar 2024 21:55:02 +1300 Subject: [PATCH 11/12] Bump ebean-agent, no effective change --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d587836bf..d3d27ea6b 100644 --- a/pom.xml +++ b/pom.xml @@ -53,8 +53,8 @@ 14.0.0 7.3 8.12 - 14.0.1 - 14.0.1 + 14.0.2 + 14.0.2 false From ab45ad34e051622152b197b657cb39e560330a9a Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 21 Mar 2024 22:07:12 +1300 Subject: [PATCH 12/12] Version 14.0.2 --- composites/ebean-clickhouse/pom.xml | 10 +++--- composites/ebean-cockroach/pom.xml | 10 +++--- composites/ebean-db2/pom.xml | 10 +++--- composites/ebean-h2/pom.xml | 10 +++--- composites/ebean-hana/pom.xml | 10 +++--- composites/ebean-mariadb/pom.xml | 10 +++--- composites/ebean-mysql/pom.xml | 10 +++--- composites/ebean-nuodb/pom.xml | 10 +++--- composites/ebean-oracle/pom.xml | 10 +++--- composites/ebean-postgis/pom.xml | 12 +++---- composites/ebean-postgres/pom.xml | 10 +++--- composites/ebean-sqlite/pom.xml | 10 +++--- composites/ebean-sqlserver/pom.xml | 10 +++--- composites/ebean-yugabyte/pom.xml | 10 +++--- composites/ebean/pom.xml | 12 +++---- composites/pom.xml | 2 +- ebean-api/pom.xml | 2 +- ebean-bom/pom.xml | 52 ++++++++++++++--------------- ebean-core-type/pom.xml | 4 +-- ebean-core/pom.xml | 12 +++---- ebean-ddl-generator/pom.xml | 8 ++--- ebean-jackson-mapper/pom.xml | 4 +-- ebean-postgis-types/pom.xml | 8 ++--- ebean-querybean/pom.xml | 10 +++--- ebean-redis/pom.xml | 12 +++---- ebean-spring-txn/pom.xml | 6 ++-- ebean-test/pom.xml | 12 +++---- howto-deploy-to-central.md | 3 ++ kotlin-querybean-generator/pom.xml | 10 +++--- platforms/all/pom.xml | 28 ++++++++-------- platforms/clickhouse/pom.xml | 4 +-- platforms/db2/pom.xml | 4 +-- platforms/h2/pom.xml | 4 +-- platforms/hana/pom.xml | 4 +-- platforms/hsqldb/pom.xml | 4 +-- platforms/mariadb/pom.xml | 6 ++-- platforms/mysql/pom.xml | 4 +-- platforms/nuodb/pom.xml | 4 +-- platforms/oracle/pom.xml | 4 +-- platforms/pom.xml | 2 +- platforms/postgres/pom.xml | 4 +-- platforms/sqlanywhere/pom.xml | 4 +-- platforms/sqlite/pom.xml | 4 +-- platforms/sqlserver/pom.xml | 4 +-- pom.xml | 2 +- querybean-generator/pom.xml | 2 +- tests/pom.xml | 2 +- tests/test-java16/pom.xml | 8 ++--- tests/test-kotlin/pom.xml | 6 ++-- 49 files changed, 203 insertions(+), 200 deletions(-) diff --git a/composites/ebean-clickhouse/pom.xml b/composites/ebean-clickhouse/pom.xml index 06d7b16a7..8f543acfd 100644 --- a/composites/ebean-clickhouse/pom.xml +++ b/composites/ebean-clickhouse/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-clickhouse - 14.0.1 + 14.0.2 diff --git a/composites/ebean-cockroach/pom.xml b/composites/ebean-cockroach/pom.xml index 20acfa443..a4ff24d15 100644 --- a/composites/ebean-cockroach/pom.xml +++ b/composites/ebean-cockroach/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 diff --git a/composites/ebean-db2/pom.xml b/composites/ebean-db2/pom.xml index 18567b46d..75994cb42 100644 --- a/composites/ebean-db2/pom.xml +++ b/composites/ebean-db2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-db2 - 14.0.1 + 14.0.2 diff --git a/composites/ebean-h2/pom.xml b/composites/ebean-h2/pom.xml index e99c020f1..1ea2f32d5 100644 --- a/composites/ebean-h2/pom.xml +++ b/composites/ebean-h2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-h2 - 14.0.1 + 14.0.2 diff --git a/composites/ebean-hana/pom.xml b/composites/ebean-hana/pom.xml index 1bbc036c2..2a41a2c87 100644 --- a/composites/ebean-hana/pom.xml +++ b/composites/ebean-hana/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-hana - 14.0.1 + 14.0.2 diff --git a/composites/ebean-mariadb/pom.xml b/composites/ebean-mariadb/pom.xml index 5e6bd20d8..2d2f14801 100644 --- a/composites/ebean-mariadb/pom.xml +++ b/composites/ebean-mariadb/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-mariadb - 14.0.1 + 14.0.2 diff --git a/composites/ebean-mysql/pom.xml b/composites/ebean-mysql/pom.xml index cac8d8a9f..6d7dd883f 100644 --- a/composites/ebean-mysql/pom.xml +++ b/composites/ebean-mysql/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-mysql - 14.0.1 + 14.0.2 diff --git a/composites/ebean-nuodb/pom.xml b/composites/ebean-nuodb/pom.xml index 1b1fb3857..64b0bf1da 100644 --- a/composites/ebean-nuodb/pom.xml +++ b/composites/ebean-nuodb/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-nuodb - 14.0.1 + 14.0.2 diff --git a/composites/ebean-oracle/pom.xml b/composites/ebean-oracle/pom.xml index 34a27740d..38098ef6f 100644 --- a/composites/ebean-oracle/pom.xml +++ b/composites/ebean-oracle/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-oracle - 14.0.1 + 14.0.2 diff --git a/composites/ebean-postgis/pom.xml b/composites/ebean-postgis/pom.xml index f360523d7..c325f6963 100644 --- a/composites/ebean-postgis/pom.xml +++ b/composites/ebean-postgis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -22,13 +22,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -47,19 +47,19 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 io.ebean ebean-postgis-types - 14.0.1 + 14.0.2 diff --git a/composites/ebean-postgres/pom.xml b/composites/ebean-postgres/pom.xml index 48650fbd4..dd2e8a253 100644 --- a/composites/ebean-postgres/pom.xml +++ b/composites/ebean-postgres/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 diff --git a/composites/ebean-sqlite/pom.xml b/composites/ebean-sqlite/pom.xml index e8ba4b984..fc51534f5 100644 --- a/composites/ebean-sqlite/pom.xml +++ b/composites/ebean-sqlite/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-sqlite - 14.0.1 + 14.0.2 diff --git a/composites/ebean-sqlserver/pom.xml b/composites/ebean-sqlserver/pom.xml index adcfe732c..03e19ad97 100644 --- a/composites/ebean-sqlserver/pom.xml +++ b/composites/ebean-sqlserver/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-sqlserver - 14.0.1 + 14.0.2 diff --git a/composites/ebean-yugabyte/pom.xml b/composites/ebean-yugabyte/pom.xml index 3ef2e2c3a..400ddd9a7 100644 --- a/composites/ebean-yugabyte/pom.xml +++ b/composites/ebean-yugabyte/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -42,13 +42,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 diff --git a/composites/ebean/pom.xml b/composites/ebean/pom.xml index f37e439d6..ebcbe0a23 100644 --- a/composites/ebean/pom.xml +++ b/composites/ebean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -17,13 +17,13 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 @@ -41,7 +41,7 @@ io.ebean ebean-jackson-mapper - 14.0.1 + 14.0.2 @@ -60,13 +60,13 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean ebean-platform-all - 14.0.1 + 14.0.2 diff --git a/composites/pom.xml b/composites/pom.xml index b16cabddb..fa7d7178b 100644 --- a/composites/pom.xml +++ b/composites/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 composites diff --git a/ebean-api/pom.xml b/ebean-api/pom.xml index e2020d174..03656a18f 100644 --- a/ebean-api/pom.xml +++ b/ebean-api/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean api diff --git a/ebean-bom/pom.xml b/ebean-bom/pom.xml index b2881bd78..200917b00 100644 --- a/ebean-bom/pom.xml +++ b/ebean-bom/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean bom @@ -89,25 +89,25 @@ io.ebean ebean - 14.0.1 + 14.0.2 io.ebean ebean-api - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 io.ebean ebean-core-type - 14.0.1 + 14.0.2 @@ -125,13 +125,13 @@ io.ebean ebean-jackson-mapper - 14.0.1 + 14.0.2 io.ebean ebean-ddl-generator - 14.0.1 + 14.0.2 @@ -155,37 +155,37 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 io.ebean querybean-generator - 14.0.1 + 14.0.2 io.ebean kotlin-querybean-generator - 14.0.1 + 14.0.2 io.ebean ebean-test - 14.0.1 + 14.0.2 io.ebean ebean-redis - 14.0.1 + 14.0.2 io.ebean ebean-spring-txn - 14.0.1 + 14.0.2 @@ -193,79 +193,79 @@ io.ebean ebean-clickhouse - 14.0.1 + 14.0.2 io.ebean ebean-db2 - 14.0.1 + 14.0.2 io.ebean ebean-h2 - 14.0.1 + 14.0.2 io.ebean ebean-hana - 14.0.1 + 14.0.2 io.ebean ebean-mariadb - 14.0.1 + 14.0.2 io.ebean ebean-mysql - 14.0.1 + 14.0.2 io.ebean ebean-nuodb - 14.0.1 + 14.0.2 io.ebean ebean-oracle - 14.0.1 + 14.0.2 io.ebean ebean-postgres - 14.0.1 + 14.0.2 io.ebean ebean-postgis - 14.0.1 + 14.0.2 io.ebean ebean-postgis-types - 14.0.1 + 14.0.2 io.ebean ebean-sqlite - 14.0.1 + 14.0.2 io.ebean ebean-sqlserver - 14.0.1 + 14.0.2 diff --git a/ebean-core-type/pom.xml b/ebean-core-type/pom.xml index 7fdfb41d0..27f99a55d 100644 --- a/ebean-core-type/pom.xml +++ b/ebean-core-type/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean-core-type @@ -16,7 +16,7 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 diff --git a/ebean-core/pom.xml b/ebean-core/pom.xml index be3df0dea..13aca6ac0 100644 --- a/ebean-core/pom.xml +++ b/ebean-core/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean-core @@ -22,7 +22,7 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 @@ -46,7 +46,7 @@ io.ebean ebean-core-type - 14.0.1 + 14.0.2 @@ -159,21 +159,21 @@ io.ebean ebean-platform-h2 - 14.0.1 + 14.0.2 test io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 test io.ebean ebean-platform-sqlserver - 14.0.1 + 14.0.2 test diff --git a/ebean-ddl-generator/pom.xml b/ebean-ddl-generator/pom.xml index add4d7720..c2d2bdf5c 100644 --- a/ebean-ddl-generator/pom.xml +++ b/ebean-ddl-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean ddl generation @@ -28,14 +28,14 @@ io.ebean ebean-core-type - 14.0.1 + 14.0.2 provided io.ebean ebean-core - 14.0.1 + 14.0.2 provided @@ -65,7 +65,7 @@ io.ebean ebean-platform-all - 14.0.1 + 14.0.2 test diff --git a/ebean-jackson-mapper/pom.xml b/ebean-jackson-mapper/pom.xml index 898933704..8da3fb671 100644 --- a/ebean-jackson-mapper/pom.xml +++ b/ebean-jackson-mapper/pom.xml @@ -3,7 +3,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 4.0.0 @@ -14,7 +14,7 @@ io.ebean ebean-core-type - 14.0.1 + 14.0.2 provided diff --git a/ebean-postgis-types/pom.xml b/ebean-postgis-types/pom.xml index 5b1e733a6..62d9d9894 100644 --- a/ebean-postgis-types/pom.xml +++ b/ebean-postgis-types/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean postgis types @@ -19,14 +19,14 @@ io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 provided @@ -62,7 +62,7 @@ io.ebean ebean-test - 14.0.1 + 14.0.2 test diff --git a/ebean-querybean/pom.xml b/ebean-querybean/pom.xml index d21e44808..62256686d 100644 --- a/ebean-querybean/pom.xml +++ b/ebean-querybean/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean querybean @@ -17,7 +17,7 @@ io.ebean ebean-core - 14.0.1 + 14.0.2 provided @@ -63,14 +63,14 @@ io.ebean ebean-ddl-generator - 14.0.1 + 14.0.2 test io.ebean ebean-test - 14.0.1 + 14.0.2 test @@ -84,7 +84,7 @@ io.ebean querybean-generator - 14.0.1 + 14.0.2 provided diff --git a/ebean-redis/pom.xml b/ebean-redis/pom.xml index b3f711962..802b2dcb1 100644 --- a/ebean-redis/pom.xml +++ b/ebean-redis/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean-redis @@ -22,28 +22,28 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 provided io.ebean ebean-core - 14.0.1 + 14.0.2 provided io.ebean ebean-querybean - 14.0.1 + 14.0.2 test io.ebean ebean-test - 14.0.1 + 14.0.2 test @@ -57,7 +57,7 @@ io.ebean querybean-generator - 14.0.1 + 14.0.2 provided diff --git a/ebean-spring-txn/pom.xml b/ebean-spring-txn/pom.xml index 6cb0cda91..f02874352 100644 --- a/ebean-spring-txn/pom.xml +++ b/ebean-spring-txn/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean-spring-txn @@ -28,7 +28,7 @@ io.ebean ebean-core - 14.0.1 + 14.0.2 provided @@ -77,7 +77,7 @@ io.ebean ebean-test - 14.0.1 + 14.0.2 test diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 192631849..50ec14edc 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ebean test @@ -33,20 +33,20 @@ io.ebean ebean-platform-h2 - 14.0.1 + 14.0.2 io.ebean ebean-core - 14.0.1 + 14.0.2 provided io.ebean ebean-ddl-generator - 14.0.1 + 14.0.2 @@ -149,14 +149,14 @@ io.ebean ebean-jackson-mapper - 14.0.1 + 14.0.2 test io.ebean ebean-platform-all - 14.0.1 + 14.0.2 test diff --git a/howto-deploy-to-central.md b/howto-deploy-to-central.md index 6aad49903..92578d30a 100644 --- a/howto-deploy-to-central.md +++ b/howto-deploy-to-central.md @@ -15,6 +15,9 @@ mvn -T 4 clean package mvn -T 4 deploy -pl '!composites,!platforms' -Pcentral -DskipTests -DskipStagingRepositoryClose=true -DstagingProgressTimeoutMinutes=9 ## git commit, git tag, git push --tags +git commit -am 'Version 14.0.2' +git tag 14.0.2 +git push --tags ## convert to javax ./jakarta-to-javax.sh diff --git a/kotlin-querybean-generator/pom.xml b/kotlin-querybean-generator/pom.xml index 23f0e470f..4728dc347 100644 --- a/kotlin-querybean-generator/pom.xml +++ b/kotlin-querybean-generator/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 kotlin querybean generator @@ -21,7 +21,7 @@ io.ebean ebean-querybean - 14.0.1 + 14.0.2 test @@ -35,7 +35,7 @@ io.ebean ebean-core - 14.0.1 + 14.0.2 test @@ -56,14 +56,14 @@ io.ebean ebean-platform-h2 - 14.0.1 + 14.0.2 test io.ebean ebean-ddl-generator - 14.0.1 + 14.0.2 test diff --git a/platforms/all/pom.xml b/platforms/all/pom.xml index ad48fd2d3..c025d3dff 100644 --- a/platforms/all/pom.xml +++ b/platforms/all/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -15,67 +15,67 @@ io.ebean ebean-platform-h2 - 14.0.1 + 14.0.2 io.ebean ebean-platform-clickhouse - 14.0.1 + 14.0.2 io.ebean ebean-platform-db2 - 14.0.1 + 14.0.2 io.ebean ebean-platform-hana - 14.0.1 + 14.0.2 io.ebean ebean-platform-hsqldb - 14.0.1 + 14.0.2 io.ebean ebean-platform-mysql - 14.0.1 + 14.0.2 io.ebean ebean-platform-mariadb - 14.0.1 + 14.0.2 io.ebean ebean-platform-nuodb - 14.0.1 + 14.0.2 io.ebean ebean-platform-oracle - 14.0.1 + 14.0.2 io.ebean ebean-platform-postgres - 14.0.1 + 14.0.2 io.ebean ebean-platform-sqlanywhere - 14.0.1 + 14.0.2 io.ebean ebean-platform-sqlite - 14.0.1 + 14.0.2 io.ebean ebean-platform-sqlserver - 14.0.1 + 14.0.2 diff --git a/platforms/clickhouse/pom.xml b/platforms/clickhouse/pom.xml index ad911aefc..f481cc2b5 100644 --- a/platforms/clickhouse/pom.xml +++ b/platforms/clickhouse/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 diff --git a/platforms/db2/pom.xml b/platforms/db2/pom.xml index 5cd12a9d3..35794cbfa 100644 --- a/platforms/db2/pom.xml +++ b/platforms/db2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.1 + 14.0.2 diff --git a/platforms/h2/pom.xml b/platforms/h2/pom.xml index 9dccef1a2..8209910b7 100644 --- a/platforms/h2/pom.xml +++ b/platforms/h2/pom.xml @@ -4,7 +4,7 @@ ebean-parent io.ebean - 14.0.1 + 14.0.2 ../.. @@ -15,7 +15,7 @@ io.ebean ebean-api - 14.0.1 + 14.0.2