Skip to content

Commit 750b7ad

Browse files
committed
Introduce QueryTransformer for functions
1 parent b721aa9 commit 750b7ad

File tree

16 files changed

+180
-45
lines changed

16 files changed

+180
-45
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
2222
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
2323
import org.hibernate.sql.ast.tree.SqlAstNode;
24+
import org.hibernate.sql.ast.tree.expression.Expression;
2425
import org.hibernate.sql.ast.tree.predicate.Predicate;
2526

2627
/**
@@ -74,7 +75,7 @@ public SelfRenderingSqmAggregateFunction<T> copy(SqmCopyContext context) {
7475
}
7576

7677
@Override
77-
public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverter walker) {
78+
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
7879
final ReturnableType<?> resultType = resolveResultType(
7980
walker.getCreationContext().getMappingMetamodel().getTypeConfiguration()
8081
);

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.hibernate.query.sqm.tree.SqmVisitableNode;
2424
import org.hibernate.query.sqm.tree.expression.SqmFunction;
2525
import org.hibernate.sql.ast.tree.SqlAstNode;
26+
import org.hibernate.sql.ast.tree.expression.Expression;
2627
import org.hibernate.type.spi.TypeConfiguration;
2728

2829
import static java.util.Collections.emptyList;
@@ -109,7 +110,7 @@ protected static List<SqlAstNode> resolveSqlAstArguments(List<? extends SqmTyped
109110
}
110111

111112
@Override
112-
public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverter walker) {
113+
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
113114
final ReturnableType<?> resultType = resolveResultType(
114115
walker.getCreationContext().getMappingMetamodel().getTypeConfiguration()
115116
);

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmOrderedSetAggregateFunction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
2626
import org.hibernate.sql.ast.Clause;
2727
import org.hibernate.sql.ast.tree.SqlAstNode;
28+
import org.hibernate.sql.ast.tree.expression.Expression;
2829
import org.hibernate.sql.ast.tree.predicate.Predicate;
2930
import org.hibernate.sql.ast.tree.select.SortSpecification;
3031

@@ -91,7 +92,7 @@ public SelfRenderingSqmOrderedSetAggregateFunction<T> copy(SqmCopyContext contex
9192
}
9293

9394
@Override
94-
public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverter walker) {
95+
public Expression convertToSqlAst(SqmToSqlAstConverter walker) {
9596
final ReturnableType<?> resultType = resolveResultType(
9697
walker.getCreationContext().getMappingMetamodel().getTypeConfiguration()
9798
);

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

Lines changed: 80 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -94,28 +94,28 @@
9494
import org.hibernate.persister.entity.AbstractEntityPersister;
9595
import org.hibernate.persister.entity.EntityPersister;
9696
import org.hibernate.persister.entity.Joinable;
97-
import org.hibernate.query.sqm.BinaryArithmeticOperator;
9897
import org.hibernate.query.BindableType;
99-
import org.hibernate.query.sqm.CastType;
100-
import org.hibernate.query.sqm.ComparisonOperator;
101-
import org.hibernate.query.sqm.DynamicInstantiationNature;
102-
import org.hibernate.query.sqm.FetchClauseType;
103-
import org.hibernate.query.spi.NavigablePath;
10498
import org.hibernate.query.QueryLogging;
10599
import org.hibernate.query.ReturnableType;
106100
import org.hibernate.query.SemanticException;
107-
import org.hibernate.query.sqm.SortOrder;
108-
import org.hibernate.query.sqm.TemporalUnit;
109-
import org.hibernate.query.sqm.UnaryArithmeticOperator;
110101
import org.hibernate.query.criteria.JpaPath;
102+
import org.hibernate.query.spi.NavigablePath;
111103
import org.hibernate.query.spi.QueryOptions;
112104
import org.hibernate.query.spi.QueryParameterBinding;
113105
import org.hibernate.query.spi.QueryParameterBindings;
114106
import org.hibernate.query.spi.QueryParameterImplementor;
107+
import org.hibernate.query.sqm.BinaryArithmeticOperator;
108+
import org.hibernate.query.sqm.CastType;
109+
import org.hibernate.query.sqm.ComparisonOperator;
110+
import org.hibernate.query.sqm.DynamicInstantiationNature;
111+
import org.hibernate.query.sqm.FetchClauseType;
115112
import org.hibernate.query.sqm.InterpretationException;
113+
import org.hibernate.query.sqm.SortOrder;
116114
import org.hibernate.query.sqm.SqmExpressible;
117115
import org.hibernate.query.sqm.SqmPathSource;
118116
import org.hibernate.query.sqm.SqmQuerySource;
117+
import org.hibernate.query.sqm.TemporalUnit;
118+
import org.hibernate.query.sqm.UnaryArithmeticOperator;
119119
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
120120
import org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression;
121121
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
@@ -260,6 +260,7 @@
260260
import org.hibernate.sql.ast.spi.SqlSelection;
261261
import org.hibernate.sql.ast.tree.Statement;
262262
import org.hibernate.sql.ast.tree.cte.CteColumn;
263+
import org.hibernate.sql.ast.tree.cte.CteContainer;
263264
import org.hibernate.sql.ast.tree.cte.CteStatement;
264265
import org.hibernate.sql.ast.tree.cte.CteTable;
265266
import org.hibernate.sql.ast.tree.cte.SearchClauseSpecification;
@@ -286,6 +287,7 @@
286287
import org.hibernate.sql.ast.tree.expression.Over;
287288
import org.hibernate.sql.ast.tree.expression.Overflow;
288289
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
290+
import org.hibernate.sql.ast.tree.expression.QueryTransformer;
289291
import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression;
290292
import org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression;
291293
import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression;
@@ -383,6 +385,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
383385
private final SqlAstCreationContext creationContext;
384386
private final boolean jpaQueryComplianceEnabled;
385387
private final SqmStatement<?> statement;
388+
private final CteContainer cteContainer = new GlobalCteContainer();
386389

387390
private final QueryOptions queryOptions;
388391
private final LoadQueryInfluencers loadQueryInfluencers;
@@ -416,6 +419,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
416419
private final Stack<Supplier<MappingModelExpressible<?>>> inferrableTypeAccessStack = new StandardStack<>(
417420
() -> null
418421
);
422+
private final Stack<List<QueryTransformer>> queryTransformers = new StandardStack<>();
419423
private boolean inTypeInference;
420424

421425
private SqmByUnit appliedByUnit;
@@ -645,7 +649,7 @@ public Statement visitStatement(SqmStatement<?> sqmStatement) {
645649

646650
@Override
647651
public UpdateStatement visitUpdateStatement(SqmUpdateStatement<?> sqmStatement) {
648-
Map<String, CteStatement> cteStatements = this.visitCteContainer( sqmStatement );
652+
final CteContainer cteContainer = this.visitCteContainer( sqmStatement );
649653

650654
final SqmRoot<?> sqmTarget = sqmStatement.getTarget();
651655
final String entityName = sqmTarget.getEntityName();
@@ -711,7 +715,7 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement<?> sqmStatement)
711715
}
712716

713717
return new UpdateStatement(
714-
sqmStatement.isWithRecursive(), cteStatements,
718+
cteContainer,
715719
(NamedTableReference) rootTableGroup.getPrimaryTableReference(),
716720
assignments,
717721
SqlAstTreeHelper.combinePredicates( suppliedPredicate, additionalRestrictions ),
@@ -889,7 +893,7 @@ public Expression resolveSqlExpression(
889893

890894
@Override
891895
public DeleteStatement visitDeleteStatement(SqmDeleteStatement<?> statement) {
892-
Map<String, CteStatement> cteStatements = this.visitCteContainer( statement );
896+
final CteContainer cteContainer = this.visitCteContainer( statement );
893897

894898
final String entityName = statement.getTarget().getEntityName();
895899
final EntityPersister entityDescriptor = creationContext.getSessionFactory()
@@ -945,8 +949,7 @@ public DeleteStatement visitDeleteStatement(SqmDeleteStatement<?> statement) {
945949
}
946950

947951
return new DeleteStatement(
948-
statement.isWithRecursive(),
949-
cteStatements,
952+
cteContainer,
950953
(NamedTableReference) rootTableGroup.getPrimaryTableReference(),
951954
SqlAstTreeHelper.combinePredicates( suppliedPredicate, additionalRestrictions ),
952955
Collections.emptyList()
@@ -962,7 +965,7 @@ public DeleteStatement visitDeleteStatement(SqmDeleteStatement<?> statement) {
962965

963966
@Override
964967
public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sqmStatement) {
965-
Map<String, CteStatement> cteStatements = this.visitCteContainer( sqmStatement );
968+
final CteContainer cteContainer = this.visitCteContainer( sqmStatement );
966969

967970
final String entityName = sqmStatement.getTarget().getEntityName();
968971
final EntityPersister entityDescriptor = creationContext.getSessionFactory()
@@ -1003,8 +1006,7 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sq
10031006
getFromClauseAccess().registerTableGroup( rootPath, rootTableGroup );
10041007

10051008
insertStatement = new InsertStatement(
1006-
sqmStatement.isWithRecursive(),
1007-
cteStatements,
1009+
cteContainer,
10081010
(NamedTableReference) rootTableGroup.getPrimaryTableReference(),
10091011
Collections.emptyList()
10101012
);
@@ -1049,7 +1051,7 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sq
10491051

10501052
@Override
10511053
public InsertStatement visitInsertValuesStatement(SqmInsertValuesStatement<?> sqmStatement) {
1052-
Map<String, CteStatement> cteStatements = this.visitCteContainer( sqmStatement );
1054+
final CteContainer cteContainer = this.visitCteContainer( sqmStatement );
10531055
final String entityName = sqmStatement.getTarget().getEntityName();
10541056
final EntityPersister entityDescriptor = creationContext.getSessionFactory()
10551057
.getRuntimeMetamodels()
@@ -1085,8 +1087,7 @@ public InsertStatement visitInsertValuesStatement(SqmInsertValuesStatement<?> sq
10851087
getFromClauseAccess().registerTableGroup( rootPath, rootTableGroup );
10861088

10871089
final InsertStatement insertStatement = new InsertStatement(
1088-
sqmStatement.isWithRecursive(),
1089-
cteStatements,
1090+
cteContainer,
10901091
(NamedTableReference) rootTableGroup.getPrimaryTableReference(),
10911092
Collections.emptyList()
10921093
);
@@ -1369,10 +1370,10 @@ public Values visitValues(SqmValues sqmValues) {
13691370

13701371
@Override
13711372
public SelectStatement visitSelectStatement(SqmSelectStatement<?> statement) {
1372-
Map<String, CteStatement> cteStatements = this.visitCteContainer( statement );
1373+
final CteContainer cteContainer = this.visitCteContainer( statement );
13731374
final QueryPart queryPart = visitQueryPart( statement.getQueryPart() );
13741375
final List<DomainResult<?>> domainResults = queryPart.isRoot() ? this.domainResults : Collections.emptyList();
1375-
return new SelectStatement( statement.isWithRecursive(), cteStatements, queryPart, domainResults );
1376+
return new SelectStatement( cteContainer, queryPart, domainResults );
13761377
}
13771378

13781379
@Override
@@ -1558,14 +1559,15 @@ public static CteTable createCteTable(
15581559
}
15591560

15601561
@Override
1561-
public Map<String, CteStatement> visitCteContainer(SqmCteContainer consumer) {
1562+
public CteContainer visitCteContainer(SqmCteContainer consumer) {
15621563
final Collection<SqmCteStatement<?>> sqmCteStatements = consumer.getCteStatements();
1563-
final Map<String, CteStatement> cteStatements = new LinkedHashMap<>( sqmCteStatements.size() );
1564+
if ( consumer.isWithRecursive() ) {
1565+
cteContainer.setWithRecursive( true );
1566+
}
15641567
for ( SqmCteStatement<?> sqmCteStatement : sqmCteStatements ) {
1565-
final CteStatement cteStatement = visitCteStatement( sqmCteStatement );
1566-
cteStatements.put( cteStatement.getCteTable().getTableExpression(), cteStatement );
1568+
cteContainer.addCteStatement( visitCteStatement( sqmCteStatement ) );
15671569
}
1568-
return cteStatements;
1570+
return cteContainer;
15691571
}
15701572

15711573
private boolean trackSelectionsForGroup;
@@ -1635,7 +1637,7 @@ public QuerySpec visitQuerySpec(SqmQuerySpec<?> sqmQuerySpec) {
16351637
);
16361638
final SqmSelectClause selectClause = sqmQuerySpec.getSelectClause();
16371639

1638-
Predicate originalAdditionalRestrictions = additionalRestrictions;
1640+
final Predicate originalAdditionalRestrictions = additionalRestrictions;
16391641
additionalRestrictions = null;
16401642

16411643
final boolean trackAliasedNodePositions;
@@ -1686,6 +1688,7 @@ else if ( sqmQuerySpec.hasPositionalGroupItem() ) {
16861688
// In sub-queries, we can never deduplicate the selection items as that might change semantics
16871689
deduplicateSelectionItems = false;
16881690
pushProcessingState( processingState );
1691+
queryTransformers.push( new ArrayList<>() );
16891692

16901693
try {
16911694
// we want to visit the from-clause first
@@ -1725,14 +1728,23 @@ else if ( sqmQuerySpec.hasPositionalGroupItem() ) {
17251728
applyCollectionFilterPredicates( sqlQuerySpec );
17261729
}
17271730

1728-
return sqlQuerySpec;
1731+
QuerySpec finalQuerySpec = sqlQuerySpec;
1732+
for ( QueryTransformer transformer : queryTransformers.getCurrent() ) {
1733+
finalQuerySpec = transformer.transform(
1734+
cteContainer,
1735+
finalQuerySpec,
1736+
this
1737+
);
1738+
}
1739+
return finalQuerySpec;
17291740
}
17301741
finally {
17311742
if ( additionalRestrictions != null ) {
17321743
sqlQuerySpec.applyPredicate( additionalRestrictions );
17331744
}
17341745
additionalRestrictions = originalAdditionalRestrictions;
17351746
popProcessingStateStack();
1747+
queryTransformers.pop();
17361748
currentSqmQueryPart = sqmQueryPart;
17371749
deduplicateSelectionItems = originalDeduplicateSelectionItems;
17381750
}
@@ -4566,6 +4578,11 @@ public Expression visitFunction(SqmFunction<?> sqmFunction) {
45664578
}
45674579
}
45684580

4581+
@Override
4582+
public void registerQueryTransformer(QueryTransformer transformer) {
4583+
queryTransformers.getCurrent().add( transformer );
4584+
}
4585+
45694586
@Override
45704587
public Star visitStar(SqmStar sqmStar) {
45714588
return new Star();
@@ -6313,4 +6330,38 @@ private static JdbcMappingContainer highestPrecedence(JdbcMappingContainer type1
63136330

63146331
return type1;
63156332
}
6333+
6334+
private class GlobalCteContainer implements CteContainer {
6335+
private final Map<String, CteStatement> cteStatements;
6336+
private boolean recursive;
6337+
6338+
public GlobalCteContainer() {
6339+
this.cteStatements = new LinkedHashMap<>();
6340+
}
6341+
6342+
@Override
6343+
public boolean isWithRecursive() {
6344+
return recursive;
6345+
}
6346+
6347+
@Override
6348+
public void setWithRecursive(boolean recursive) {
6349+
this.recursive = recursive;
6350+
}
6351+
6352+
@Override
6353+
public Map<String, CteStatement> getCteStatements() {
6354+
return cteStatements;
6355+
}
6356+
6357+
@Override
6358+
public CteStatement getCteStatement(String cteLabel) {
6359+
return cteStatements.get( cteLabel );
6360+
}
6361+
6362+
@Override
6363+
public void addCteStatement(CteStatement cteStatement) {
6364+
cteStatements.put( cteStatement.getCteTable().getTableExpression(), cteStatement );
6365+
}
6366+
}
63166367
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
2121
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
2222
import org.hibernate.sql.ast.tree.expression.Expression;
23+
import org.hibernate.sql.ast.tree.expression.QueryTransformer;
2324

2425
/**
2526
*
@@ -73,6 +74,10 @@ public Stack<Clause> getCurrentClauseStack() {
7374
return null;
7475
}
7576

77+
@Override
78+
public void registerQueryTransformer(QueryTransformer transformer) {
79+
}
80+
7681
@Override
7782
public List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter<?> sqmParameter) {
7883
return null;

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
@@ -14,6 +14,7 @@
1414
import org.hibernate.sql.ast.spi.SqlAstCreationState;
1515
import org.hibernate.sql.ast.Clause;
1616
import org.hibernate.sql.ast.tree.expression.Expression;
17+
import org.hibernate.sql.ast.tree.expression.QueryTransformer;
1718

1819
/**
1920
* Specialized SemanticQueryWalker (SQM visitor) for producing SQL AST.
@@ -23,6 +24,8 @@
2324
public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAstCreationState {
2425
Stack<Clause> getCurrentClauseStack();
2526

27+
void registerQueryTransformer(QueryTransformer transformer);
28+
2629
List<Expression> expandSelfRenderingFunctionMultiValueParameter(SqmParameter<?> sqmParameter);
2730

2831
}

hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1313,7 +1313,7 @@ protected void visitReturningColumns(MutationStatement mutationStatement) {
13131313
}
13141314

13151315
public void visitCteContainer(CteContainer cteContainer) {
1316-
final Collection<CteStatement> cteStatements = cteContainer.getCteStatements();
1316+
final Collection<CteStatement> cteStatements = cteContainer.getCteStatements().values();
13171317
if ( cteStatements.isEmpty() ) {
13181318
return;
13191319
}

0 commit comments

Comments
 (0)