From ee76f005aa3a2e6e88003a1343181b6db2549248 Mon Sep 17 00:00:00 2001 From: Jan Schatteman Date: Wed, 28 Feb 2024 18:37:25 +0100 Subject: [PATCH] HHH-17776 - Add test and fix Signed-off-by: Jan Schatteman --- .../query/sqm/tree/select/SqmQuerySpec.java | 15 ++-- ...hereClauseTest.java => SubqueryTests.java} | 83 +++++++++++++++++-- 2 files changed, 82 insertions(+), 16 deletions(-) rename hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/{RootInSubqueryWhereClauseTest.java => SubqueryTests.java} (55%) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java index 29bde53e7f..347604f0c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java @@ -64,13 +64,13 @@ public class SqmQuerySpec extends SqmQueryPart public SqmQuerySpec(NodeBuilder nodeBuilder) { super( nodeBuilder ); + // Enforce non-nullness of the fromClause + this.fromClause = new SqmFromClause(); } public SqmQuerySpec(SqmQuerySpec original, SqmCopyContext context) { super( original, context ); - if ( original.fromClause != null ) { - this.fromClause = original.fromClause.copy( context ); - } + this.fromClause = original.fromClause.copy( context ); if ( original.selectClause != null ) { this.selectClause = original.selectClause.copy( context ); } @@ -96,9 +96,7 @@ public class SqmQuerySpec extends SqmQueryPart return existing; } final SqmQuerySpec querySpec = context.registerCopy( this, new SqmQuerySpec<>( nodeBuilder() ) ); - if ( fromClause != null ) { - querySpec.fromClause = fromClause.copy( context ); - } + querySpec.fromClause = fromClause.copy( context ); if ( selectClause != null ) { querySpec.selectClause = selectClause.copy( context ); } @@ -145,7 +143,10 @@ public class SqmQuerySpec extends SqmQueryPart } public void setFromClause(SqmFromClause fromClause) { - this.fromClause = fromClause; + // Enforce non-nullness of the fromClause + if ( fromClause != null ) { + this.fromClause = fromClause; + } } public boolean producesUniqueResults() { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/RootInSubqueryWhereClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryTests.java similarity index 55% rename from hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/RootInSubqueryWhereClauseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryTests.java index 7f60a2c990..334ee9aa61 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/RootInSubqueryWhereClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryTests.java @@ -9,35 +9,44 @@ package org.hibernate.orm.test.jpa.criteria.subquery; import java.util.ArrayList; import java.util.List; -import org.hibernate.testing.TestForIssue; +import org.hibernate.Session; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.criteria.JpaDerivedRoot; +import org.hibernate.query.criteria.JpaSubQuery; + import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.Jpa; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import jakarta.persistence.Entity; +import jakarta.persistence.EntityManager; import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import jakarta.persistence.Tuple; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; import jakarta.persistence.criteria.Subquery; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; @Jpa( annotatedClasses = { - RootInSubqueryWhereClauseTest.Person.class, - RootInSubqueryWhereClauseTest.Address.class + SubqueryTests.Person.class, + SubqueryTests.Address.class } ) -@TestForIssue(jiraKey = "HHH-15477") -public class RootInSubqueryWhereClauseTest { +public class SubqueryTests { - @BeforeEach + @BeforeAll public void setUp(EntityManagerFactoryScope scope){ scope.inTransaction( entityManager -> { @@ -54,7 +63,8 @@ public class RootInSubqueryWhereClauseTest { } @Test - public void testSubquery(EntityManagerFactoryScope scope) { + @JiraKey(value = "HHH-15477") + public void testRootInSubqueryWhereClause(EntityManagerFactoryScope scope) { scope.inTransaction( entityManager -> { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); @@ -76,6 +86,50 @@ public class RootInSubqueryWhereClauseTest { ); } + @Test + @JiraKey(value = "HHH-17776") + public void testNoFromClauseInSubquery(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + List entities = getEntities(entityManager); + assertEquals( 2, entities.size()); + assertEquals("Jack", entities.get(0).getName()); + assertEquals("Black", entities.get(0).getSurName()); + assertEquals("John", entities.get(1).getName()); + assertEquals("Doe", entities.get(1).getSurName()); + } + ); + } + + private List getEntities(EntityManager entityManager) { + + HibernateCriteriaBuilder builder = entityManager.unwrap( Session.class ).getCriteriaBuilder(); + JpaCriteriaQuery mainQuery = builder.createQuery( Person.class ); + + JpaSubQuery q1 = mainQuery.subquery(Tuple.class); + q1.multiselect( + builder.literal("John").alias("name"), + builder.literal("Doe").alias("surName") + ); + + JpaSubQuery q2 = mainQuery.subquery(Tuple.class); + q2.multiselect( + builder.literal("Jack").alias("name"), + builder.literal("Black").alias("surName") + ); + + JpaSubQuery unionAllSubQuery = builder.unionAll(q1, q2); + JpaDerivedRoot mainQueryRoot = mainQuery.from( unionAllSubQuery ); + + mainQuery.multiselect( + builder.trim(mainQueryRoot.get("name")).alias("name"), + builder.trim(mainQueryRoot.get("surName")).alias("surName") + ); + mainQuery.orderBy( builder.asc(mainQueryRoot.get("name")) ); + + return entityManager.createQuery(mainQuery).getResultList(); + } + @Entity(name = "Person") public static class Person { @Id @@ -83,6 +137,8 @@ public class RootInSubqueryWhereClauseTest { String name; + String surName; + @OneToMany List
addresses =new ArrayList<>(); @@ -90,8 +146,13 @@ public class RootInSubqueryWhereClauseTest { } public Person(Integer id, String name) { + this(id,name,null); + } + + public Person(Integer id, String name, String surName) { this.id = id; this.name = name; + this.surName = surName; } public void addAddress(Address address){ @@ -107,6 +168,10 @@ public class RootInSubqueryWhereClauseTest { return name; } + public String getSurName() { + return surName; + } + public List
getAddresses() { return addresses; }