Skip to content

Commit 3543186

Browse files
committed
HHH-16409 Rework entity valued path expansion for group by and order by
1 parent 8098830 commit 3543186

File tree

4 files changed

+85
-61
lines changed

4 files changed

+85
-61
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 7 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,10 @@ public Stack<Clause> getCurrentClauseStack() {
751751
return currentClauseStack;
752752
}
753753

754+
@Override
755+
public SqmQueryPart<?> getCurrentSqmQueryPart() {
756+
return currentSqmQueryPart;
757+
}
754758

755759
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
756760
// Statements
@@ -2395,46 +2399,6 @@ else if ( selectableNode instanceof SqmJpaCompoundSelection<?> ) {
23952399
return -( offset + selections.size() );
23962400
}
23972401

2398-
private boolean selectClauseContains(SqmFrom<?, ?> from) {
2399-
final SqmQuerySpec<?> sqmQuerySpec = (SqmQuerySpec<?>) currentSqmQueryPart;
2400-
final List<SqmSelection<?>> selections = sqmQuerySpec.getSelectClause() == null
2401-
? Collections.emptyList()
2402-
: sqmQuerySpec.getSelectClause().getSelections();
2403-
if ( selections.isEmpty() && from instanceof SqmRoot<?> ) {
2404-
return true;
2405-
}
2406-
for ( SqmSelection<?> selection : selections ) {
2407-
if ( selectableNodeContains( selection.getSelectableNode(), from ) ) {
2408-
return true;
2409-
}
2410-
}
2411-
return false;
2412-
}
2413-
2414-
private boolean selectableNodeContains(SqmSelectableNode<?> selectableNode, SqmFrom<?, ?> from) {
2415-
if ( selectableNode == from ) {
2416-
return true;
2417-
}
2418-
else if ( selectableNode instanceof SqmDynamicInstantiation ) {
2419-
for ( SqmDynamicInstantiationArgument<?> argument : ( (SqmDynamicInstantiation<?>) selectableNode ).getArguments() ) {
2420-
if ( selectableNodeContains( argument.getSelectableNode(), from ) ) {
2421-
return true;
2422-
}
2423-
}
2424-
}
2425-
return false;
2426-
}
2427-
2428-
private boolean groupByClauseContains(SqmFrom<?, ?> from) {
2429-
final SqmQuerySpec<?> sqmQuerySpec = (SqmQuerySpec<?>) currentSqmQueryPart;
2430-
for ( SqmExpression<?> expression : sqmQuerySpec.getGroupByClauseExpressions() ) {
2431-
if ( expression == from ) {
2432-
return true;
2433-
}
2434-
}
2435-
return false;
2436-
}
2437-
24382402
@Override
24392403
public List<Expression> visitGroupByClause(List<SqmExpression<?>> groupByClauseExpressions) {
24402404
if ( !groupByClauseExpressions.isEmpty() ) {
@@ -3755,8 +3719,8 @@ private Expression visitTableGroup(TableGroup tableGroup, SqmFrom<?, ?> path) {
37553719
final EntityValuedModelPart interpretationModelPart;
37563720
final TableGroup tableGroupToUse;
37573721
if ( inferredEntityMapping == null ) {
3758-
// When the inferred mapping is null, we try to resolve to the FK by default,
3759-
// which is fine because expansion to all target columns for select and group by clauses is handled below
3722+
// When the inferred mapping is null, we try to resolve to the FK by default, which is fine because
3723+
// expansion to all target columns for select and group by clauses is handled in EntityValuedPathInterpretation
37603724
if ( entityValuedModelPart instanceof EntityAssociationMapping && ( (EntityAssociationMapping) entityValuedModelPart ).isFkOptimizationAllowed() ) {
37613725
// If the table group uses an association mapping that is not a one-to-many,
37623726
// we make use of the FK model part
@@ -3883,22 +3847,6 @@ else if ( entityValuedModelPart instanceof AnonymousTupleEntityValuedModelPart )
38833847
tableGroupToUse = null;
38843848
}
38853849

3886-
final boolean expandToAllColumns;
3887-
if ( currentClauseStack.getCurrent() == Clause.GROUP ) {
3888-
// When the table group is known to be fetched i.e. a fetch join
3889-
// but also when the from clause is part of the select clause
3890-
// we need to expand to all columns, as we also expand this to all columns in the select clause
3891-
expandToAllColumns = tableGroup.isFetched() || selectClauseContains( path );
3892-
}
3893-
else if ( currentClauseStack.getCurrent() == Clause.ORDER ) {
3894-
// We must ensure that the order by expression be expanded if the group by
3895-
// contained the same expression, and that was expanded as well
3896-
expandToAllColumns = groupByClauseContains( path ) && ( tableGroup.isFetched() || selectClauseContains( path ) );
3897-
}
3898-
else {
3899-
expandToAllColumns = false;
3900-
}
3901-
39023850
final EntityMappingType treatedMapping;
39033851
if ( path instanceof SqmTreatedPath ) {
39043852
treatedMapping = creationContext.getSessionFactory()
@@ -3913,7 +3861,7 @@ else if ( currentClauseStack.getCurrent() == Clause.ORDER ) {
39133861
result = EntityValuedPathInterpretation.from(
39143862
navigablePath,
39153863
tableGroupToUse == null ? tableGroup : tableGroupToUse,
3916-
expandToAllColumns ? null : resultModelPart,
3864+
resultModelPart,
39173865
interpretationModelPart,
39183866
treatedMapping,
39193867
this

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/FakeSqmToSqlAstConverter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.hibernate.query.sqm.tree.expression.SqmExpression;
1919
import org.hibernate.query.sqm.tree.expression.SqmParameter;
2020
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
21+
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
2122
import org.hibernate.sql.ast.Clause;
2223
import org.hibernate.sql.ast.spi.FromClauseAccess;
2324
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
@@ -86,6 +87,11 @@ public Stack<Clause> getCurrentClauseStack() {
8687
return null;
8788
}
8889

90+
@Override
91+
public SqmQueryPart<?> getCurrentSqmQueryPart() {
92+
return null;
93+
}
94+
8995
@Override
9096
public void registerQueryTransformer(QueryTransformer transformer) {
9197
}

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmToSqlAstConverter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.hibernate.query.sqm.tree.expression.SqmExpression;
1717
import org.hibernate.query.sqm.tree.expression.SqmParameter;
1818
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
19+
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
1920
import org.hibernate.sql.ast.spi.SqlAstCreationState;
2021
import org.hibernate.sql.ast.Clause;
2122
import org.hibernate.sql.ast.tree.expression.Expression;
@@ -30,6 +31,8 @@
3031
public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAstCreationState {
3132
Stack<Clause> getCurrentClauseStack();
3233

34+
SqmQueryPart<?> getCurrentSqmQueryPart();
35+
3336
void registerQueryTransformer(QueryTransformer transformer);
3437

3538
/**

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@
2727
import org.hibernate.query.derived.AnonymousTupleEntityValuedModelPart;
2828
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
2929
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
30+
import org.hibernate.query.sqm.tree.domain.SqmPath;
31+
import org.hibernate.query.sqm.tree.expression.SqmExpression;
32+
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
33+
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument;
34+
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
35+
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
36+
import org.hibernate.query.sqm.tree.select.SqmSelection;
3037
import org.hibernate.spi.NavigablePath;
38+
import org.hibernate.sql.ast.Clause;
3139
import org.hibernate.sql.ast.SqlAstWalker;
3240
import org.hibernate.sql.ast.spi.FromClauseAccess;
3341
import org.hibernate.sql.ast.spi.SqlAstCreationState;
@@ -284,10 +292,28 @@ public static <T> EntityValuedPathInterpretation<T> from(
284292
EntityValuedModelPart mapping,
285293
EntityValuedModelPart treatedMapping,
286294
SqmToSqlAstConverter sqlAstCreationState) {
295+
final boolean expandToAllColumns;
296+
final Clause currentClause = sqlAstCreationState.getCurrentClauseStack().getCurrent();
297+
if ( currentClause == Clause.GROUP || currentClause == Clause.ORDER ) {
298+
final SqmQuerySpec<?> querySpec = (SqmQuerySpec<?>) sqlAstCreationState.getCurrentSqmQueryPart();
299+
if ( currentClause == Clause.ORDER && !groupByClauseContains( navigablePath, querySpec ) ) {
300+
// We must ensure that the order by expression be expanded but only if the group by
301+
// contained the same expression, and that was expanded as well
302+
expandToAllColumns = false;
303+
}
304+
else {
305+
// When the table group is selected and the navigablePath is selected we need to expand
306+
// to all columns, as we also expand this to all columns in the select clause
307+
expandToAllColumns = isSelected( tableGroup, navigablePath, querySpec );
308+
}
309+
}
310+
else {
311+
expandToAllColumns = false;
312+
}
313+
287314
final SqlExpressionResolver sqlExprResolver = sqlAstCreationState.getSqlExpressionResolver();
288315
final Expression sqlExpression;
289-
290-
if ( resultModelPart == null ) {
316+
if ( expandToAllColumns ) {
291317
// Expand to all columns of the entity mapping type, as we already did for the selection
292318
final EntityMappingType entityMappingType = mapping.getEntityMappingType();
293319
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
@@ -352,6 +378,47 @@ public static <T> EntityValuedPathInterpretation<T> from(
352378
);
353379
}
354380

381+
private static boolean isSelected(TableGroup tableGroup, NavigablePath path, SqmQuerySpec<?> sqmQuerySpec) {
382+
// If the table group is selected (initialized), check if the entity valued
383+
// navigable path or any child path appears in the select clause
384+
return tableGroup.isInitialized() && selectClauseContains( path, sqmQuerySpec );
385+
}
386+
387+
private static boolean selectClauseContains(NavigablePath path, SqmQuerySpec<?> sqmQuerySpec) {
388+
final List<SqmSelection<?>> selections = sqmQuerySpec.getSelectClause() == null
389+
? Collections.emptyList()
390+
: sqmQuerySpec.getSelectClause().getSelections();
391+
for ( SqmSelection<?> selection : selections ) {
392+
if ( selectableNodeContains( selection.getSelectableNode(), path ) ) {
393+
return true;
394+
}
395+
}
396+
return false;
397+
}
398+
399+
private static boolean selectableNodeContains(SqmSelectableNode<?> selectableNode, NavigablePath path) {
400+
if ( selectableNode instanceof SqmPath && path.isParentOrEqual( ( (SqmPath<?>) selectableNode ).getNavigablePath() ) ) {
401+
return true;
402+
}
403+
else if ( selectableNode instanceof SqmDynamicInstantiation ) {
404+
for ( SqmDynamicInstantiationArgument<?> argument : ( (SqmDynamicInstantiation<?>) selectableNode ).getArguments() ) {
405+
if ( selectableNodeContains( argument.getSelectableNode(), path ) ) {
406+
return true;
407+
}
408+
}
409+
}
410+
return false;
411+
}
412+
413+
private static boolean groupByClauseContains(NavigablePath path, SqmQuerySpec<?> sqmQuerySpec) {
414+
for ( SqmExpression<?> expression : sqmQuerySpec.getGroupByClauseExpressions() ) {
415+
if ( expression instanceof SqmPath && ( (SqmPath<?>) expression ).getNavigablePath() == path ) {
416+
return true;
417+
}
418+
}
419+
return false;
420+
}
421+
355422
private final Expression sqlExpression;
356423

357424
public EntityValuedPathInterpretation(

0 commit comments

Comments
 (0)