9494import org .hibernate .persister .entity .AbstractEntityPersister ;
9595import org .hibernate .persister .entity .EntityPersister ;
9696import org .hibernate .persister .entity .Joinable ;
97- import org .hibernate .query .sqm .BinaryArithmeticOperator ;
9897import 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 ;
10498import org .hibernate .query .QueryLogging ;
10599import org .hibernate .query .ReturnableType ;
106100import 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 ;
110101import org .hibernate .query .criteria .JpaPath ;
102+ import org .hibernate .query .spi .NavigablePath ;
111103import org .hibernate .query .spi .QueryOptions ;
112104import org .hibernate .query .spi .QueryParameterBinding ;
113105import org .hibernate .query .spi .QueryParameterBindings ;
114106import 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 ;
115112import org .hibernate .query .sqm .InterpretationException ;
113+ import org .hibernate .query .sqm .SortOrder ;
116114import org .hibernate .query .sqm .SqmExpressible ;
117115import org .hibernate .query .sqm .SqmPathSource ;
118116import org .hibernate .query .sqm .SqmQuerySource ;
117+ import org .hibernate .query .sqm .TemporalUnit ;
118+ import org .hibernate .query .sqm .UnaryArithmeticOperator ;
119119import org .hibernate .query .sqm .function .AbstractSqmSelfRenderingFunctionDescriptor ;
120120import org .hibernate .query .sqm .function .SelfRenderingAggregateFunctionSqlAstExpression ;
121121import org .hibernate .query .sqm .function .SelfRenderingFunctionSqlAstExpression ;
260260import org .hibernate .sql .ast .spi .SqlSelection ;
261261import org .hibernate .sql .ast .tree .Statement ;
262262import org .hibernate .sql .ast .tree .cte .CteColumn ;
263+ import org .hibernate .sql .ast .tree .cte .CteContainer ;
263264import org .hibernate .sql .ast .tree .cte .CteStatement ;
264265import org .hibernate .sql .ast .tree .cte .CteTable ;
265266import org .hibernate .sql .ast .tree .cte .SearchClauseSpecification ;
286287import org .hibernate .sql .ast .tree .expression .Over ;
287288import org .hibernate .sql .ast .tree .expression .Overflow ;
288289import org .hibernate .sql .ast .tree .expression .QueryLiteral ;
290+ import org .hibernate .sql .ast .tree .expression .QueryTransformer ;
289291import org .hibernate .sql .ast .tree .expression .SelfRenderingExpression ;
290292import org .hibernate .sql .ast .tree .expression .SelfRenderingSqlFragmentExpression ;
291293import 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}
0 commit comments