diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java index 64afc2192b..3309960ca9 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java @@ -57,7 +57,7 @@ public class CorrelatedTableGroup extends AbstractTableGroup { assert !getTableGroupJoins().contains( join ); assert join.getJoinType() == SqlAstJoinType.INNER; querySpec.getFromClause().addRoot( join.getJoinedGroup() ); - joinPredicateConsumer.accept( join.getPredicate() ); + registerPredicate( join ); super.addTableGroupJoin( join ); } @@ -71,10 +71,22 @@ public class CorrelatedTableGroup extends AbstractTableGroup { assert !getTableGroupJoins().contains( join ); assert join.getJoinType() == SqlAstJoinType.INNER; querySpec.getFromClause().addRoot( join.getJoinedGroup() ); - joinPredicateConsumer.accept( join.getPredicate() ); + registerPredicate( join ); super.addNestedTableGroupJoin( join ); } + private void registerPredicate(TableGroupJoin join) { + if ( join.getPredicate() != null ) { + joinPredicateConsumer.accept( join.getPredicate() ); + } + else if ( join.getJoinedGroup() instanceof LazyTableGroup ) { + // Wait for the table group to get initialized before consuming the predicate + ( (LazyTableGroup) join.getJoinedGroup() ).setTableGroupInitializerCallback( + tableGroup -> joinPredicateConsumer.accept( join.getPredicate() ) + ); + } + } + @Override public TableReference getTableReference( NavigablePath navigablePath, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java index a5d3569936..fad670ca5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java @@ -104,7 +104,16 @@ public class LazyTableGroup extends DelegatingTableGroup { tableGroupConsumer.accept( tableGroup ); } else { - this.tableGroupConsumer = tableGroupConsumer; + final Consumer previousConsumer = this.tableGroupConsumer; + if (previousConsumer != null ) { + this.tableGroupConsumer = tg -> { + previousConsumer.accept( tg ); + tableGroupConsumer.accept( tg ); + }; + } + else { + this.tableGroupConsumer = tableGroupConsumer; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java new file mode 100644 index 0000000000..78f59669d7 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ImplicitJoinInSubqueryTest.java @@ -0,0 +1,68 @@ +package org.hibernate.orm.test.query; + +import org.hibernate.testing.jdbc.SQLStatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import org.assertj.core.api.Assertions; + +import static org.assertj.core.api.Assertions.assertThat; + +@JiraKey("HHH-16721") +@DomainModel(annotatedClasses = { + ImplicitJoinInSubqueryTest.A.class, + ImplicitJoinInSubqueryTest.B.class, + ImplicitJoinInSubqueryTest.C.class +}) +@SessionFactory(useCollectingStatementInspector = true) +public class ImplicitJoinInSubqueryTest { + + @Test + public void testImplicitJoinInSubquery(SessionFactoryScope scope) { + SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); + statementInspector.clear(); + scope.inTransaction( + entityManager -> { + entityManager.createSelectionQuery( + "select 1 from A a where exists (select 1 from B b where a.b.c.id = 5)" + ).getResultList(); + assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "b2_0.id=a1_0.b_id" ); + } + ); + } + + @Entity(name = "A") + public static class A { + @Id + @GeneratedValue + Long id; + @ManyToOne(fetch = FetchType.LAZY) + B b; + } + + @Entity(name = "B") + public static class B { + @Id + @GeneratedValue + Long id; + @ManyToOne(fetch = FetchType.LAZY) + C c; + } + + @Entity(name = "C") + public static class C { + @Id + @GeneratedValue + Long id; + } +}