HHH-18378 Check where clause before reusing existing joins for fetch

This commit is contained in:
Marco Belladelli 2024-07-29 15:11:18 +02:00
parent 0272fc7fbd
commit 4da2659292
3 changed files with 45 additions and 11 deletions

View File

@ -74,6 +74,7 @@ import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQueryGroup;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
@ -105,6 +106,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import static java.util.stream.Collectors.toList;
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
import static org.hibernate.query.sqm.tree.jpa.ParameterCollector.collectParameters;
/**
@ -232,6 +234,15 @@ public class SqmUtil {
return false;
}
public static List<NavigablePath> getWhereClauseNavigablePaths(SqmQuerySpec<?> querySpec) {
final SqmWhereClause where = querySpec.getWhereClause();
if ( where == null || where.getPredicate() == null ) {
return Collections.emptyList();
}
return collectNavigablePaths( List.of( where.getPredicate() ) );
}
public static List<NavigablePath> getGroupByNavigablePaths(SqmQuerySpec<?> querySpec) {
final List<SqmExpression<?>> expressions = querySpec.getGroupByClauseExpressions();
if ( expressions.isEmpty() ) {
@ -255,7 +266,7 @@ public class SqmUtil {
}
private static List<NavigablePath> collectNavigablePaths(final List<SqmExpression<?>> expressions) {
final List<NavigablePath> navigablePaths = new ArrayList<>( expressions.size() );
final List<NavigablePath> navigablePaths = arrayList( expressions.size() );
final SqmPathVisitor pathVisitor = new SqmPathVisitor( path -> navigablePaths.add( path.getNavigablePath() ) );
for ( final SqmExpression<?> expression : expressions ) {
if ( expression instanceof SqmAliasedNodeRef ) {

View File

@ -8406,7 +8406,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
joinProducer,
joinProducer.determineSqlJoinType( lhs, null, true )
);
if ( compatibleTableGroup == null ) {
final SqmQueryPart<?> queryPart = getCurrentSqmQueryPart();
if ( compatibleTableGroup == null
// If the compatible table group is used in the where clause it cannot be reused for fetching
|| ( queryPart != null && queryPart.getFirstQuerySpec().whereClauseContains( compatibleTableGroup.getNavigablePath(), this ) ) ) {
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
fetchablePath,
lhs,

View File

@ -629,15 +629,26 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
super.appendHqlString( sb );
}
@Internal
public boolean whereClauseContains(NavigablePath navigablePath, SqmToSqlAstConverter sqlAstConverter) {
if ( whereClause == null ) {
return false;
}
return isSameOrParent(
navigablePath,
sqlAstConverter.resolveMetadata( this, SqmUtil::getWhereClauseNavigablePaths )
);
}
@Internal
public boolean groupByClauseContains(NavigablePath navigablePath, SqmToSqlAstConverter sqlAstConverter) {
if ( groupByClauseExpressions.isEmpty() ) {
return false;
}
return navigablePathsContain( sqlAstConverter.resolveMetadata(
this,
SqmUtil::getGroupByNavigablePaths
), navigablePath );
return isSameOrChildren(
navigablePath,
sqlAstConverter.resolveMetadata( this, SqmUtil::getGroupByNavigablePaths )
);
}
@Internal
@ -646,13 +657,13 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
if ( orderByClause == null || orderByClause.getSortSpecifications().isEmpty() ) {
return false;
}
return navigablePathsContain( sqlAstConverter.resolveMetadata(
this,
SqmUtil::getOrderByNavigablePaths
), navigablePath );
return isSameOrChildren(
navigablePath,
sqlAstConverter.resolveMetadata( this, SqmUtil::getOrderByNavigablePaths )
);
}
private boolean navigablePathsContain(List<NavigablePath> navigablePaths, NavigablePath navigablePath) {
private boolean isSameOrChildren(NavigablePath navigablePath, List<NavigablePath> navigablePaths) {
for ( NavigablePath path : navigablePaths ) {
if ( path.isParentOrEqual( navigablePath ) ) {
return true;
@ -660,4 +671,13 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
}
return false;
}
private boolean isSameOrParent(NavigablePath navigablePath, List<NavigablePath> navigablePaths) {
for ( NavigablePath path : navigablePaths ) {
if ( navigablePath.isParentOrEqual( path ) ) {
return true;
}
}
return false;
}
}