1818import org .hibernate .engine .spi .SharedSessionContractImplementor ;
1919import org .hibernate .engine .spi .SubselectFetch ;
2020import org .hibernate .internal .EmptyScrollableResults ;
21+ import org .hibernate .internal .util .MutableObject ;
2122import org .hibernate .metamodel .mapping .MappingModelExpressible ;
2223import org .hibernate .query .QueryTypeMismatchException ;
2324import org .hibernate .query .TupleTransformer ;
2425import org .hibernate .query .spi .DomainQueryExecutionContext ;
2526import org .hibernate .query .spi .QueryOptions ;
26- import org .hibernate .query .spi .QueryParameterImplementor ;
2727import org .hibernate .query .spi .ScrollableResultsImplementor ;
2828import org .hibernate .query .spi .SelectQueryPlan ;
2929import org .hibernate .query .sqm .spi .SqmParameterMappingModelResolutionAccess ;
@@ -79,7 +79,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
7979 private final SqmInterpreter <List <R >, Void > listInterpreter ;
8080 private final SqmInterpreter <ScrollableResultsImplementor <R >, ScrollMode > scrollInterpreter ;
8181
82- private volatile CacheableSqmInterpretation cacheableSqmInterpretation ;
82+ private volatile CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > cacheableSqmInterpretation ;
8383
8484 public ConcreteSqmSelectQueryPlan (
8585 SqmSelectStatement <?> sqm ,
@@ -97,16 +97,16 @@ public ConcreteSqmSelectQueryPlan(
9797 : ListResultsConsumer .UniqueSemantic .ALLOW ;
9898 this .executeQueryInterpreter = (resultsConsumer , executionContext , sqmInterpretation , jdbcParameterBindings ) -> {
9999 final SharedSessionContractImplementor session = executionContext .getSession ();
100- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
100+ final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
101101 try {
102102 final SubselectFetch .RegistrationHandler subSelectFetchKeyHandler = SubselectFetch .createRegistrationHandler (
103103 session .getPersistenceContext ().getBatchFetchQueue (),
104- sqmInterpretation .selectStatement ,
104+ sqmInterpretation .statement () ,
105105 JdbcParametersList .empty (),
106106 jdbcParameterBindings
107107 );
108108 session .autoFlushIfRequired ( jdbcSelect .getAffectedTableNames (), true );
109- final Expression fetchExpression = sqmInterpretation .selectStatement .getQueryPart ()
109+ final Expression fetchExpression = sqmInterpretation .statement () .getQueryPart ()
110110 .getFetchClauseExpression ();
111111 final int resultCountEstimate = fetchExpression != null
112112 ? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
@@ -127,17 +127,17 @@ public ConcreteSqmSelectQueryPlan(
127127 };
128128 this .listInterpreter = (unused , executionContext , sqmInterpretation , jdbcParameterBindings ) -> {
129129 final SharedSessionContractImplementor session = executionContext .getSession ();
130- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
130+ final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
131131 try {
132132 final SubselectFetch .RegistrationHandler subSelectFetchKeyHandler = SubselectFetch .createRegistrationHandler (
133133 session .getPersistenceContext ().getBatchFetchQueue (),
134- sqmInterpretation .selectStatement ,
134+ sqmInterpretation .statement () ,
135135 JdbcParametersList .empty (),
136136 jdbcParameterBindings
137137 );
138138 session .autoFlushIfRequired ( jdbcSelect .getAffectedTableNames (), true );
139139 final Expression fetchExpression =
140- sqmInterpretation .selectStatement .getQueryPart ()
140+ sqmInterpretation .statement () .getQueryPart ()
141141 .getFetchClauseExpression ();
142142 final int resultCountEstimate = fetchExpression != null
143143 ? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
@@ -160,7 +160,7 @@ public ConcreteSqmSelectQueryPlan(
160160
161161 this .scrollInterpreter = (scrollMode , executionContext , sqmInterpretation , jdbcParameterBindings ) -> {
162162 final SharedSessionContractImplementor session = executionContext .getSession ();
163- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
163+ final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
164164 try {
165165// final SubselectFetch.RegistrationHandler subSelectFetchKeyHandler = SubselectFetch.createRegistrationHandler(
166166// executionContext.getSession().getPersistenceContext().getBatchFetchQueue(),
@@ -173,7 +173,7 @@ public ConcreteSqmSelectQueryPlan(
173173 session .getFactory ().getJdbcServices ().getJdbcSelectExecutor ();
174174 session .autoFlushIfRequired ( jdbcSelect .getAffectedTableNames (), true );
175175 final Expression fetchExpression =
176- sqmInterpretation .selectStatement .getQueryPart ()
176+ sqmInterpretation .statement () .getQueryPart ()
177177 .getFetchClauseExpression ();
178178 final int resultCountEstimate = fetchExpression != null
179179 ? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
@@ -401,7 +401,7 @@ private <T, X> T withCacheableSqmInterpretation(DomainQueryExecutionContext exec
401401 // to protect access. However, synchronized is much simpler here. We will verify
402402 // during throughput testing whether this is an issue and consider changes then
403403
404- CacheableSqmInterpretation localCopy = cacheableSqmInterpretation ;
404+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > localCopy = cacheableSqmInterpretation ;
405405 JdbcParameterBindings jdbcParameterBindings = null ;
406406
407407 executionContext .getSession ().autoPreFlush ();
@@ -410,23 +410,23 @@ private <T, X> T withCacheableSqmInterpretation(DomainQueryExecutionContext exec
410410 synchronized ( this ) {
411411 localCopy = cacheableSqmInterpretation ;
412412 if ( localCopy == null ) {
413- localCopy = buildCacheableSqmInterpretation ( sqm , domainParameterXref , executionContext );
414- jdbcParameterBindings = localCopy . firstParameterBindings ;
415- localCopy . firstParameterBindings = null ;
413+ final MutableObject < JdbcParameterBindings > mutableValue = new MutableObject <>( );
414+ localCopy = buildInterpretation ( sqm , domainParameterXref , executionContext , mutableValue ) ;
415+ jdbcParameterBindings = mutableValue . get () ;
416416 cacheableSqmInterpretation = localCopy ;
417417 }
418418 else {
419419 // If the translation depends on parameter bindings or it isn't compatible with the current query options,
420420 // we have to rebuild the JdbcSelect, which is still better than having to translate from SQM to SQL AST again
421- if ( localCopy .jdbcSelect .dependsOnParameterBindings () ) {
421+ if ( localCopy .jdbcOperation () .dependsOnParameterBindings () ) {
422422 jdbcParameterBindings = createJdbcParameterBindings ( localCopy , executionContext );
423423 }
424424 // If the translation depends on the limit or lock options, we have to rebuild the JdbcSelect
425425 // We could avoid this by putting the lock options into the cache key
426- if ( !localCopy .jdbcSelect .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
427- localCopy = buildCacheableSqmInterpretation ( sqm , domainParameterXref , executionContext );
428- jdbcParameterBindings = localCopy . firstParameterBindings ;
429- localCopy . firstParameterBindings = null ;
426+ if ( !localCopy .jdbcOperation () .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
427+ final MutableObject < JdbcParameterBindings > mutableValue = new MutableObject <>( );
428+ localCopy = buildInterpretation ( sqm , domainParameterXref , executionContext , mutableValue ) ;
429+ jdbcParameterBindings = mutableValue . get () ;
430430 cacheableSqmInterpretation = localCopy ;
431431 }
432432 }
@@ -435,15 +435,15 @@ private <T, X> T withCacheableSqmInterpretation(DomainQueryExecutionContext exec
435435 else {
436436 // If the translation depends on parameter bindings or it isn't compatible with the current query options,
437437 // we have to rebuild the JdbcSelect, which is still better than having to translate from SQM to SQL AST again
438- if ( localCopy .jdbcSelect .dependsOnParameterBindings () ) {
438+ if ( localCopy .jdbcOperation () .dependsOnParameterBindings () ) {
439439 jdbcParameterBindings = createJdbcParameterBindings ( localCopy , executionContext );
440440 }
441441 // If the translation depends on the limit or lock options, we have to rebuild the JdbcSelect
442442 // We could avoid this by putting the lock options into the cache key
443- if ( !localCopy .jdbcSelect .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
444- localCopy = buildCacheableSqmInterpretation ( sqm , domainParameterXref , executionContext );
445- jdbcParameterBindings = localCopy . firstParameterBindings ;
446- localCopy . firstParameterBindings = null ;
443+ if ( !localCopy .jdbcOperation () .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
444+ final MutableObject < JdbcParameterBindings > mutableValue = new MutableObject <>( );
445+ localCopy = buildInterpretation ( sqm , domainParameterXref , executionContext , mutableValue ) ;
446+ jdbcParameterBindings = mutableValue . get () ;
447447 cacheableSqmInterpretation = localCopy ;
448448 }
449449 }
@@ -455,26 +455,27 @@ private <T, X> T withCacheableSqmInterpretation(DomainQueryExecutionContext exec
455455 return interpreter .interpret ( context , executionContext , localCopy , jdbcParameterBindings );
456456 }
457457
458- private JdbcParameterBindings createJdbcParameterBindings (CacheableSqmInterpretation sqmInterpretation , DomainQueryExecutionContext executionContext ) {
458+ private JdbcParameterBindings createJdbcParameterBindings (CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation , DomainQueryExecutionContext executionContext ) {
459459 return SqmUtil .createJdbcParameterBindings (
460460 executionContext .getQueryParameterBindings (),
461461 domainParameterXref ,
462- sqmInterpretation .getJdbcParamsXref (),
462+ sqmInterpretation .jdbcParamsXref (),
463463 new SqmParameterMappingModelResolutionAccess () {
464464 //this is pretty ugly!
465465 @ Override @ SuppressWarnings ("unchecked" )
466466 public <T > MappingModelExpressible <T > getResolvedMappingModelType (SqmParameter <T > parameter ) {
467- return (MappingModelExpressible <T >) sqmInterpretation .getSqmParameterMappingModelTypes ().get (parameter );
467+ return (MappingModelExpressible <T >) sqmInterpretation .sqmParameterMappingModelTypes ().get (parameter );
468468 }
469469 },
470470 executionContext .getSession ()
471471 );
472472 }
473473
474- private static CacheableSqmInterpretation buildCacheableSqmInterpretation (
474+ private static CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > buildInterpretation (
475475 SqmSelectStatement <?> sqm ,
476476 DomainParameterXref domainParameterXref ,
477- DomainQueryExecutionContext executionContext ) {
477+ DomainQueryExecutionContext executionContext ,
478+ MutableObject <JdbcParameterBindings > firstJdbcParameterBindingsConsumer ) {
478479 final SharedSessionContractImplementor session = executionContext .getSession ();
479480 final SessionFactoryImplementor sessionFactory = session .getFactory ();
480481
@@ -511,57 +512,23 @@ public <T> MappingModelExpressible<T> getResolvedMappingModelType(SqmParameter<T
511512 },
512513 session
513514 );
514-
515- return new CacheableSqmInterpretation (
515+ firstJdbcParameterBindingsConsumer . set ( jdbcParameterBindings );
516+ return new CacheableSqmInterpretation <> (
516517 sqmInterpretation .getSqlAst (),
517518 selectTranslator .translate ( jdbcParameterBindings , executionContext .getQueryOptions () ),
518519 jdbcParamsXref ,
519- sqmInterpretation .getSqmParameterMappingModelTypeResolutions (),
520- jdbcParameterBindings
520+ sqmInterpretation .getSqmParameterMappingModelTypeResolutions ()
521521 );
522522 }
523523
524524 private interface SqmInterpreter <T , X > {
525525 T interpret (
526526 X context ,
527527 DomainQueryExecutionContext executionContext ,
528- CacheableSqmInterpretation sqmInterpretation ,
528+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
529529 JdbcParameterBindings jdbcParameterBindings );
530530 }
531531
532- private static class CacheableSqmInterpretation {
533- private final SelectStatement selectStatement ;
534- private final JdbcOperationQuerySelect jdbcSelect ;
535- private final Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> jdbcParamsXref ;
536- private final Map <SqmParameter <?>, MappingModelExpressible <?>> sqmParameterMappingModelTypes ;
537- private transient JdbcParameterBindings firstParameterBindings ;
538-
539- CacheableSqmInterpretation (
540- SelectStatement selectStatement ,
541- JdbcOperationQuerySelect jdbcSelect ,
542- Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> jdbcParamsXref ,
543- Map <SqmParameter <?>, MappingModelExpressible <?>> sqmParameterMappingModelTypes ,
544- JdbcParameterBindings firstParameterBindings ) {
545- this .selectStatement = selectStatement ;
546- this .jdbcSelect = jdbcSelect ;
547- this .jdbcParamsXref = jdbcParamsXref ;
548- this .sqmParameterMappingModelTypes = sqmParameterMappingModelTypes ;
549- this .firstParameterBindings = firstParameterBindings ;
550- }
551-
552- JdbcOperationQuerySelect getJdbcSelect () {
553- return jdbcSelect ;
554- }
555-
556- Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> getJdbcParamsXref () {
557- return jdbcParamsXref ;
558- }
559-
560- public Map <SqmParameter <?>, MappingModelExpressible <?>> getSqmParameterMappingModelTypes () {
561- return sqmParameterMappingModelTypes ;
562- }
563- }
564-
565532 private static class MySqmJdbcExecutionContextAdapter extends SqmJdbcExecutionContextAdapter {
566533 private final SubselectFetch .RegistrationHandler subSelectFetchKeyHandler ;
567534 private final String hql ;
0 commit comments