From 69a753fc4f78958f409e8514dcbe44eabbc866eb Mon Sep 17 00:00:00 2001 From: Noemi Szemenyei Date: Fri, 21 Jan 2022 14:30:06 +0100 Subject: [PATCH] DB2:Unselect LOBs when making a distinct select --- .../server/deploy/BeanProperty.java | 21 +++++++- .../DynamicPropertyAggregationFormula.java | 5 ++ .../server/query/CQueryBuilder.java | 4 ++ .../server/query/STreeProperty.java | 5 ++ .../server/query/SqlTreeNode.java | 8 ++- .../java/org/tests/json/TestJsonMapBasic.java | 54 +++++++++++++++---- 6 files changed, 85 insertions(+), 12 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 bbee58e60..72379b232 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 @@ -1160,7 +1160,26 @@ public class BeanProperty implements ElPropertyValue, Property, STreeProperty { public boolean isLob() { return lob; } - + + /** + * Returns true if this isLob() or the type will effectively map to a lob. + */ + public boolean isDbLob() { + if (lob) { + return true; + } + switch (dbType) { + case DbPlatformType.JSON: + case DbPlatformType.JSONB: + return dbLength == 0; // must be analog to DbPlatformTypeMapping.lookup + case DbPlatformType.JSONBlob: + case DbPlatformType.JSONClob: + return true; + default: + return false; + } + } + public static boolean isLobType(int type) { switch (type) { case Types.CLOB: 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 970145632..ec1c7035b 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 @@ -62,4 +62,9 @@ class DynamicPropertyAggregationFormula extends DynamicPropertyBase { ctx.appendParseSelect(parsedFormula, alias); } + @Override + public boolean isDbLob() { + return false; + } + } 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 1ad0dae58..1d32ce994 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 @@ -760,6 +760,10 @@ final class CQueryBuilder { return dbPlatform.isPlatform(Platform.POSTGRES); } + boolean isPlatformDistinctNoLobs() { + return dbPlatform.isPlatform(Platform.DB2); // CHECKME: Also oracle? + } + /** * Return the 'for update' FROM hint (sql server). */ 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 0981d5ac4..c13126858 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 @@ -28,6 +28,11 @@ public interface STreeProperty extends ScalarDataReader { * Return true if the property is the Id. */ boolean isId(); + + /** + * Returns true, if this is a lob property from db-perspective. + */ + boolean isDbLob(); /** * Return true if the property is an embedded type. 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 d4d22908c..3d50a9377 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 @@ -78,6 +78,10 @@ interface SqlTreeNode { * Create the loader for this node. */ SqlTreeLoad createLoad(); - - default void unselectLobs() {}; + + /** + * Unselect lobs (for distinct queries on DB2 and Oracle). + */ + default void unselectLobs() { + }; } diff --git a/ebean-test/src/test/java/org/tests/json/TestJsonMapBasic.java b/ebean-test/src/test/java/org/tests/json/TestJsonMapBasic.java index e186de792..1c1cebb43 100644 --- a/ebean-test/src/test/java/org/tests/json/TestJsonMapBasic.java +++ b/ebean-test/src/test/java/org/tests/json/TestJsonMapBasic.java @@ -3,13 +3,18 @@ package org.tests.json; import io.ebean.BaseTestCase; import io.ebean.DB; import io.ebean.Query; +import io.ebean.annotation.ForPlatform; +import io.ebean.annotation.Platform; import io.ebean.test.LoggedSql; import io.ebean.text.json.EJson; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.tests.model.json.EBasicJsonMap; import org.tests.model.json.EBasicJsonMapDetail; import java.io.IOException; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,15 +23,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class TestJsonMapBasic extends BaseTestCase { - @Test - public void whereManyPredicate() { + private final EBasicJsonMap bean = new EBasicJsonMap();; - if (!isPostgres()) { - // testing postgres specific select distinct on clause - return; + @AfterEach + void cleanup() { + if (bean != null && bean.getId() != null) { + DB.delete(EBasicJsonMap.class, bean.getId()); } + } + + @Test + @ForPlatform(Platform.POSTGRES) + public void whereManyPredicatePg() { - EBasicJsonMap bean = new EBasicJsonMap(); bean.setName("own1"); bean.getDetails().add(new EBasicJsonMapDetail("detail1")); bean.getDetails().add(new EBasicJsonMapDetail("detail2")); @@ -50,6 +59,36 @@ public class TestJsonMapBasic extends BaseTestCase { assertThat(query2.getGeneratedSql()).contains("select distinct on (t0.id) "); } + @Test + @ForPlatform(Platform.DB2) + public void whereManyPredicateDb2() { + + Map m1 = new HashMap<>(); + m1.put("foo", "bar"); + bean.setContent(m1); + bean.setName("own1"); + bean.getDetails().add(new EBasicJsonMapDetail("db2-detail1")); + bean.getDetails().add(new EBasicJsonMapDetail("db2-detail2")); + + DB.save(bean); + Query query1 = DB.find(EBasicJsonMap.class).select("*").fetch("details").where() + .startsWith("details.name", "db2-detail").query(); + + List lst = query1.findList(); + + assertThat(query1.getGeneratedSql()).contains("select distinct t0.id, t0.name, t0.version,") + .doesNotContain("content"); + assertThat(lst).hasSize(1); + assertThat(lst.get(0).getContent()).containsEntry("foo", "bar"); + + Query query2 = DB.find(EBasicJsonMap.class).where().startsWith("details.name", "db2-detail") + .query(); + query2.findList(); + + assertThat(query2.getGeneratedSql()).contains("select distinct t0.id, t0.name, t0.version from"); + + } + @Test public void testInsertUpdateDelete() throws IOException { @@ -58,7 +97,6 @@ public class TestJsonMapBasic extends BaseTestCase { Map content = EJson.parseObject(s0); - EBasicJsonMap bean = new EBasicJsonMap(); bean.setName("one"); bean.setContent(content); @@ -106,7 +144,6 @@ public class TestJsonMapBasic extends BaseTestCase { String s0 = "{\"docId\":22,\"contentId\":\"initialDoc\"}"; Map content = EJson.parseObject(s0); - EBasicJsonMap bean = new EBasicJsonMap(); bean.setName("one"); bean.setContent(content); @@ -133,6 +170,5 @@ public class TestJsonMapBasic extends BaseTestCase { assertThat(content2.get("contentId")).isEqualTo("updatedDoc222"); assertThat(content2.get("docId")).isEqualTo(222L); - DB.delete(found); } }