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 1cc94c76b9
commit bbb7bcf389
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 !getTableGroupJoins().contains( join );
assert join.getJoinType() == SqlAstJoinType.INNER; assert join.getJoinType() == SqlAstJoinType.INNER;
querySpec.getFromClause().addRoot( join.getJoinedGroup() ); querySpec.getFromClause().addRoot( join.getJoinedGroup() );
joinPredicateConsumer.accept( join.getPredicate() ); registerPredicate( join );
super.addTableGroupJoin( join ); super.addTableGroupJoin( join );
} }
@ -71,10 +71,22 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
assert !getTableGroupJoins().contains( join ); assert !getTableGroupJoins().contains( join );
assert join.getJoinType() == SqlAstJoinType.INNER; assert join.getJoinType() == SqlAstJoinType.INNER;
querySpec.getFromClause().addRoot( join.getJoinedGroup() ); querySpec.getFromClause().addRoot( join.getJoinedGroup() );
joinPredicateConsumer.accept( join.getPredicate() ); registerPredicate( join );
super.addNestedTableGroupJoin( 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 @Override
public TableReference getTableReference( public TableReference getTableReference(
NavigablePath navigablePath, NavigablePath navigablePath,

View File

@ -104,7 +104,16 @@ public class LazyTableGroup extends DelegatingTableGroup {
tableGroupConsumer.accept( tableGroup ); tableGroupConsumer.accept( tableGroup );
} }
else { 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;
}
}