HHH-16721 Make sure join predicate is propagated to correlation on lazy initialization

This commit is contained in:
Christian Beikov 2023-06-14 19:02:31 +02:00
parent 380962bd37
commit 01c8295968
3 changed files with 92 additions and 3 deletions

View File

@ -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,

View File

@ -104,7 +104,16 @@ public class LazyTableGroup extends DelegatingTableGroup {
tableGroupConsumer.accept( tableGroup );
}
else {
this.tableGroupConsumer = tableGroupConsumer;
final Consumer<TableGroup> previousConsumer = this.tableGroupConsumer;
if (previousConsumer != null ) {
this.tableGroupConsumer = tg -> {
previousConsumer.accept( tg );
tableGroupConsumer.accept( tg );
};
}
else {
this.tableGroupConsumer = tableGroupConsumer;
}
}
}

View File

@ -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;
}
}