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.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin; import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot; 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.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQueryGroup; import org.hibernate.query.sqm.tree.select.SqmQueryGroup;
import org.hibernate.query.sqm.tree.select.SqmQueryPart; 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 java.util.stream.Collectors.toList;
import static org.hibernate.internal.util.NullnessUtil.castNonNull; 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; import static org.hibernate.query.sqm.tree.jpa.ParameterCollector.collectParameters;
/** /**
@ -232,6 +234,15 @@ public class SqmUtil {
return false; 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) { public static List<NavigablePath> getGroupByNavigablePaths(SqmQuerySpec<?> querySpec) {
final List<SqmExpression<?>> expressions = querySpec.getGroupByClauseExpressions(); final List<SqmExpression<?>> expressions = querySpec.getGroupByClauseExpressions();
if ( expressions.isEmpty() ) { if ( expressions.isEmpty() ) {
@ -255,7 +266,7 @@ public class SqmUtil {
} }
private static List<NavigablePath> collectNavigablePaths(final List<SqmExpression<?>> expressions) { 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() ) ); final SqmPathVisitor pathVisitor = new SqmPathVisitor( path -> navigablePaths.add( path.getNavigablePath() ) );
for ( final SqmExpression<?> expression : expressions ) { for ( final SqmExpression<?> expression : expressions ) {
if ( expression instanceof SqmAliasedNodeRef ) { if ( expression instanceof SqmAliasedNodeRef ) {

View File

@ -8406,7 +8406,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
joinProducer, joinProducer,
joinProducer.determineSqlJoinType( lhs, null, true ) 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( final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
fetchablePath, fetchablePath,
lhs, lhs,

View File

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