9595import org .hibernate .persister .entity .EntityPersister ;
9696import org .hibernate .persister .entity .Joinable ;
9797import org .hibernate .persister .entity .SingleTableEntityPersister ;
98- import org .hibernate .query .sqm .BinaryArithmeticOperator ;
9998import org .hibernate .query .BindableType ;
100- import org .hibernate .query .sqm .CastType ;
101- import org .hibernate .query .sqm .ComparisonOperator ;
102- import org .hibernate .query .sqm .DynamicInstantiationNature ;
103- import org .hibernate .query .sqm .FetchClauseType ;
104- import org .hibernate .query .spi .NavigablePath ;
10599import org .hibernate .query .QueryLogging ;
106100import org .hibernate .query .ReturnableType ;
107101import org .hibernate .query .SemanticException ;
108- import org .hibernate .query .sqm .SortOrder ;
109- import org .hibernate .query .sqm .TemporalUnit ;
110- import org .hibernate .query .sqm .UnaryArithmeticOperator ;
111102import org .hibernate .query .criteria .JpaPath ;
103+ import org .hibernate .query .spi .NavigablePath ;
112104import org .hibernate .query .spi .QueryOptions ;
113105import org .hibernate .query .spi .QueryParameterBinding ;
114106import org .hibernate .query .spi .QueryParameterBindings ;
115107import org .hibernate .query .spi .QueryParameterImplementor ;
108+ import org .hibernate .query .sqm .BinaryArithmeticOperator ;
109+ import org .hibernate .query .sqm .CastType ;
110+ import org .hibernate .query .sqm .ComparisonOperator ;
111+ import org .hibernate .query .sqm .DynamicInstantiationNature ;
112+ import org .hibernate .query .sqm .FetchClauseType ;
116113import org .hibernate .query .sqm .InterpretationException ;
114+ import org .hibernate .query .sqm .SortOrder ;
117115import org .hibernate .query .sqm .SqmExpressible ;
118116import org .hibernate .query .sqm .SqmPathSource ;
119117import org .hibernate .query .sqm .SqmQuerySource ;
118+ import org .hibernate .query .sqm .TemporalUnit ;
119+ import org .hibernate .query .sqm .UnaryArithmeticOperator ;
120120import org .hibernate .query .sqm .function .AbstractSqmSelfRenderingFunctionDescriptor ;
121121import org .hibernate .query .sqm .function .SelfRenderingAggregateFunctionSqlAstExpression ;
122122import org .hibernate .query .sqm .function .SelfRenderingFunctionSqlAstExpression ;
261261import org .hibernate .sql .ast .spi .SqlSelection ;
262262import org .hibernate .sql .ast .tree .Statement ;
263263import org .hibernate .sql .ast .tree .cte .CteColumn ;
264+ import org .hibernate .sql .ast .tree .cte .CteContainer ;
264265import org .hibernate .sql .ast .tree .cte .CteStatement ;
265266import org .hibernate .sql .ast .tree .cte .CteTable ;
266267import org .hibernate .sql .ast .tree .cte .SearchClauseSpecification ;
287288import org .hibernate .sql .ast .tree .expression .Over ;
288289import org .hibernate .sql .ast .tree .expression .Overflow ;
289290import org .hibernate .sql .ast .tree .expression .QueryLiteral ;
291+ import org .hibernate .sql .ast .tree .expression .QueryTransformer ;
290292import org .hibernate .sql .ast .tree .expression .SelfRenderingExpression ;
291293import org .hibernate .sql .ast .tree .expression .SelfRenderingSqlFragmentExpression ;
292294import org .hibernate .sql .ast .tree .expression .SqlSelectionExpression ;
@@ -384,6 +386,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
384386 private final SqlAstCreationContext creationContext ;
385387 private final boolean jpaQueryComplianceEnabled ;
386388 private final SqmStatement <?> statement ;
389+ private final CteContainer cteContainer = new GlobalCteContainer ();
387390
388391 private final QueryOptions queryOptions ;
389392 private final LoadQueryInfluencers loadQueryInfluencers ;
@@ -429,6 +432,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
429432 private final Stack <Supplier <MappingModelExpressible <?>>> inferrableTypeAccessStack = new StandardStack <>(
430433 () -> null
431434 );
435+ private final Stack <List <QueryTransformer >> queryTransformers = new StandardStack <>();
432436 private boolean inTypeInference ;
433437
434438 private SqmByUnit appliedByUnit ;
@@ -658,7 +662,7 @@ public Statement visitStatement(SqmStatement<?> sqmStatement) {
658662
659663 @ Override
660664 public UpdateStatement visitUpdateStatement (SqmUpdateStatement <?> sqmStatement ) {
661- Map < String , CteStatement > cteStatements = this .visitCteContainer ( sqmStatement );
665+ final CteContainer cteContainer = this .visitCteContainer ( sqmStatement );
662666
663667 final SqmRoot <?> sqmTarget = sqmStatement .getTarget ();
664668 final String entityName = sqmTarget .getEntityName ();
@@ -718,7 +722,7 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement<?> sqmStatement)
718722 }
719723
720724 return new UpdateStatement (
721- sqmStatement . isWithRecursive (), cteStatements ,
725+ cteContainer ,
722726 (NamedTableReference ) rootTableGroup .getPrimaryTableReference (),
723727 assignments ,
724728 SqlAstTreeHelper .combinePredicates ( suppliedPredicate , additionalRestrictions ),
@@ -896,7 +900,7 @@ public Expression resolveSqlExpression(
896900
897901 @ Override
898902 public DeleteStatement visitDeleteStatement (SqmDeleteStatement <?> statement ) {
899- Map < String , CteStatement > cteStatements = this .visitCteContainer ( statement );
903+ final CteContainer cteContainer = this .visitCteContainer ( statement );
900904
901905 final String entityName = statement .getTarget ().getEntityName ();
902906 final EntityPersister entityDescriptor = creationContext .getSessionFactory ()
@@ -946,8 +950,7 @@ public DeleteStatement visitDeleteStatement(SqmDeleteStatement<?> statement) {
946950 }
947951
948952 return new DeleteStatement (
949- statement .isWithRecursive (),
950- cteStatements ,
953+ cteContainer ,
951954 (NamedTableReference ) rootTableGroup .getPrimaryTableReference (),
952955 SqlAstTreeHelper .combinePredicates ( suppliedPredicate , additionalRestrictions ),
953956 Collections .emptyList ()
@@ -963,7 +966,7 @@ public DeleteStatement visitDeleteStatement(SqmDeleteStatement<?> statement) {
963966
964967 @ Override
965968 public InsertStatement visitInsertSelectStatement (SqmInsertSelectStatement <?> sqmStatement ) {
966- Map < String , CteStatement > cteStatements = this .visitCteContainer ( sqmStatement );
969+ final CteContainer cteContainer = this .visitCteContainer ( sqmStatement );
967970
968971 final String entityName = sqmStatement .getTarget ().getEntityName ();
969972 final EntityPersister entityDescriptor = creationContext .getSessionFactory ()
@@ -1004,8 +1007,7 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sq
10041007 getFromClauseAccess ().registerTableGroup ( rootPath , rootTableGroup );
10051008
10061009 insertStatement = new InsertStatement (
1007- sqmStatement .isWithRecursive (),
1008- cteStatements ,
1010+ cteContainer ,
10091011 (NamedTableReference ) rootTableGroup .getPrimaryTableReference (),
10101012 Collections .emptyList ()
10111013 );
@@ -1050,7 +1052,7 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sq
10501052
10511053 @ Override
10521054 public InsertStatement visitInsertValuesStatement (SqmInsertValuesStatement <?> sqmStatement ) {
1053- Map < String , CteStatement > cteStatements = this .visitCteContainer ( sqmStatement );
1055+ final CteContainer cteContainer = this .visitCteContainer ( sqmStatement );
10541056 final String entityName = sqmStatement .getTarget ().getEntityName ();
10551057 final EntityPersister entityDescriptor = creationContext .getSessionFactory ()
10561058 .getRuntimeMetamodels ()
@@ -1086,8 +1088,7 @@ public InsertStatement visitInsertValuesStatement(SqmInsertValuesStatement<?> sq
10861088 getFromClauseAccess ().registerTableGroup ( rootPath , rootTableGroup );
10871089
10881090 final InsertStatement insertStatement = new InsertStatement (
1089- sqmStatement .isWithRecursive (),
1090- cteStatements ,
1091+ cteContainer ,
10911092 (NamedTableReference ) rootTableGroup .getPrimaryTableReference (),
10921093 Collections .emptyList ()
10931094 );
@@ -1370,10 +1371,10 @@ public Values visitValues(SqmValues sqmValues) {
13701371
13711372 @ Override
13721373 public SelectStatement visitSelectStatement (SqmSelectStatement <?> statement ) {
1373- Map < String , CteStatement > cteStatements = this .visitCteContainer ( statement );
1374+ final CteContainer cteContainer = this .visitCteContainer ( statement );
13741375 final QueryPart queryPart = visitQueryPart ( statement .getQueryPart () );
13751376 final List <DomainResult <?>> domainResults = queryPart .isRoot () ? this .domainResults : Collections .emptyList ();
1376- return new SelectStatement ( statement . isWithRecursive (), cteStatements , queryPart , domainResults );
1377+ return new SelectStatement ( cteContainer , queryPart , domainResults );
13771378 }
13781379
13791380 @ Override
@@ -1559,14 +1560,15 @@ public static CteTable createCteTable(
15591560 }
15601561
15611562 @ Override
1562- public Map < String , CteStatement > visitCteContainer (SqmCteContainer consumer ) {
1563+ public CteContainer visitCteContainer (SqmCteContainer consumer ) {
15631564 final Collection <SqmCteStatement <?>> sqmCteStatements = consumer .getCteStatements ();
1564- final Map <String , CteStatement > cteStatements = new LinkedHashMap <>( sqmCteStatements .size () );
1565+ if ( consumer .isWithRecursive () ) {
1566+ cteContainer .setWithRecursive ( true );
1567+ }
15651568 for ( SqmCteStatement <?> sqmCteStatement : sqmCteStatements ) {
1566- final CteStatement cteStatement = visitCteStatement ( sqmCteStatement );
1567- cteStatements .put ( cteStatement .getCteTable ().getTableExpression (), cteStatement );
1569+ cteContainer .addCteStatement ( visitCteStatement ( sqmCteStatement ) );
15681570 }
1569- return cteStatements ;
1571+ return cteContainer ;
15701572 }
15711573
15721574 private boolean trackSelectionsForGroup ;
@@ -1687,6 +1689,7 @@ else if ( sqmQuerySpec.hasPositionalGroupItem() ) {
16871689 // In sub-queries, we can never deduplicate the selection items as that might change semantics
16881690 deduplicateSelectionItems = false ;
16891691 pushProcessingState ( processingState );
1692+ queryTransformers .push ( new ArrayList <>() );
16901693
16911694 try {
16921695 // we want to visit the from-clause first
@@ -1720,14 +1723,23 @@ else if ( sqmQuerySpec.hasPositionalGroupItem() ) {
17201723 applyCollectionFilterPredicates ( sqlQuerySpec );
17211724 }
17221725
1723- return sqlQuerySpec ;
1726+ QuerySpec finalQuerySpec = sqlQuerySpec ;
1727+ for ( QueryTransformer transformer : queryTransformers .getCurrent () ) {
1728+ finalQuerySpec = transformer .transform (
1729+ cteContainer ,
1730+ finalQuerySpec ,
1731+ this
1732+ );
1733+ }
1734+ return finalQuerySpec ;
17241735 }
17251736 finally {
17261737 if ( additionalRestrictions != null ) {
17271738 sqlQuerySpec .applyPredicate ( additionalRestrictions );
17281739 }
17291740 additionalRestrictions = originalAdditionalRestrictions ;
17301741 popProcessingStateStack ();
1742+ queryTransformers .pop ();
17311743 currentSqmQueryPart = sqmQueryPart ;
17321744 deduplicateSelectionItems = originalDeduplicateSelectionItems ;
17331745 }
@@ -4662,6 +4674,11 @@ public Expression visitFunction(SqmFunction<?> sqmFunction) {
46624674 }
46634675 }
46644676
4677+ @ Override
4678+ public void registerQueryTransformer (QueryTransformer transformer ) {
4679+ queryTransformers .getCurrent ().add ( transformer );
4680+ }
4681+
46654682 @ Override
46664683 public Star visitStar (SqmStar sqmStar ) {
46674684 return new Star ();
@@ -6488,4 +6505,38 @@ private static JdbcMappingContainer highestPrecedence(JdbcMappingContainer type1
64886505
64896506 return type1 ;
64906507 }
6508+
6509+ private class GlobalCteContainer implements CteContainer {
6510+ private final Map <String , CteStatement > cteStatements ;
6511+ private boolean recursive ;
6512+
6513+ public GlobalCteContainer () {
6514+ this .cteStatements = new LinkedHashMap <>();
6515+ }
6516+
6517+ @ Override
6518+ public boolean isWithRecursive () {
6519+ return recursive ;
6520+ }
6521+
6522+ @ Override
6523+ public void setWithRecursive (boolean recursive ) {
6524+ this .recursive = recursive ;
6525+ }
6526+
6527+ @ Override
6528+ public Map <String , CteStatement > getCteStatements () {
6529+ return cteStatements ;
6530+ }
6531+
6532+ @ Override
6533+ public CteStatement getCteStatement (String cteLabel ) {
6534+ return cteStatements .get ( cteLabel );
6535+ }
6536+
6537+ @ Override
6538+ public void addCteStatement (CteStatement cteStatement ) {
6539+ cteStatements .put ( cteStatement .getCteTable ().getTableExpression (), cteStatement );
6540+ }
6541+ }
64916542}
0 commit comments