66package org .hibernate .reactive .query .sqm .internal ;
77
88import java .util .List ;
9- import java .util .Map ;
109import java .util .concurrent .CompletionStage ;
1110import java .util .function .Supplier ;
1211
1312import org .hibernate .ScrollMode ;
14- import org .hibernate .engine .jdbc .env .spi .JdbcEnvironment ;
15- import org .hibernate .engine .jdbc .spi .JdbcServices ;
16- import org .hibernate .engine .spi .SessionFactoryImplementor ;
17- import org .hibernate .engine .spi .SharedSessionContractImplementor ;
1813import org .hibernate .engine .spi .SubselectFetch ;
19- import org .hibernate .metamodel . mapping . MappingModelExpressible ;
14+ import org .hibernate .internal . util . MutableObject ;
2015import org .hibernate .query .Query ;
2116import org .hibernate .query .spi .DomainQueryExecutionContext ;
22- import org .hibernate .query .spi .QueryEngine ;
2317import org .hibernate .query .spi .QueryOptions ;
24- import org .hibernate .query .spi .QueryParameterImplementor ;
2518import org .hibernate .query .spi .ScrollableResultsImplementor ;
19+ import org .hibernate .query .sqm .internal .CacheableSqmInterpretation ;
2620import org .hibernate .query .sqm .internal .ConcreteSqmSelectQueryPlan ;
2721import org .hibernate .query .sqm .internal .DomainParameterXref ;
28- import org .hibernate .query .sqm .internal .SqmUtil ;
29- import org .hibernate .query .sqm .spi .SqmParameterMappingModelResolutionAccess ;
30- import org .hibernate .query .sqm .sql .SqmTranslation ;
31- import org .hibernate .query .sqm .sql .SqmTranslator ;
32- import org .hibernate .query .sqm .sql .SqmTranslatorFactory ;
33- import org .hibernate .query .sqm .tree .expression .SqmParameter ;
3422import org .hibernate .query .sqm .tree .select .SqmSelectStatement ;
3523import org .hibernate .reactive .engine .spi .ReactiveSharedSessionContractImplementor ;
3624import org .hibernate .reactive .query .sqm .spi .ReactiveSelectQueryPlan ;
3725import org .hibernate .reactive .sql .exec .internal .StandardReactiveSelectExecutor ;
3826import org .hibernate .reactive .sql .results .spi .ReactiveListResultsConsumer ;
3927import org .hibernate .reactive .sql .results .spi .ReactiveResultsConsumer ;
40- import org .hibernate .sql .ast .SqlAstTranslator ;
41- import org .hibernate .sql .ast .SqlAstTranslatorFactory ;
42- import org .hibernate .sql .ast .spi .FromClauseAccess ;
4328import org .hibernate .sql .ast .tree .expression .Expression ;
4429import org .hibernate .sql .ast .tree .select .SelectStatement ;
4530import org .hibernate .sql .exec .spi .JdbcOperationQuerySelect ;
@@ -68,7 +53,7 @@ public class ConcreteSqmSelectReactiveQueryPlan<R> extends ConcreteSqmSelectQuer
6853 private final SqmSelectStatement <?> sqm ;
6954 private final DomainParameterXref domainParameterXref ;
7055
71- private volatile CacheableSqmInterpretation cacheableSqmInterpretation ;
56+ private volatile CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > cacheableSqmInterpretation ;
7257
7358 public ConcreteSqmSelectReactiveQueryPlan (
7459 SqmSelectStatement <?> sqm ,
@@ -91,25 +76,33 @@ private static <R> CompletionStage<List<R>> listInterpreter(
9176 String hql ,
9277 DomainParameterXref domainParameterXref ,
9378 DomainQueryExecutionContext executionContext ,
94- CacheableSqmInterpretation sqmInterpretation ,
79+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
9580 JdbcParameterBindings jdbcParameterBindings ,
9681 RowTransformer <R > rowTransformer ) {
9782 final ReactiveSharedSessionContractImplementor session = (ReactiveSharedSessionContractImplementor ) executionContext .getSession ();
98- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
83+ JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
9984 // I'm using a supplier so that the whenComplete at the end will catch any errors, like a finally-block
10085 Supplier <SubselectFetch .RegistrationHandler > fetchHandlerSupplier = () -> SubselectFetch
101- .createRegistrationHandler ( session .getPersistenceContext ().getBatchFetchQueue (), sqmInterpretation .selectStatement , JdbcParametersList .empty (), jdbcParameterBindings );
86+ .createRegistrationHandler ( session .getPersistenceContext ().getBatchFetchQueue (), sqmInterpretation .statement () , JdbcParametersList .empty (), jdbcParameterBindings );
10287 return completedFuture ( fetchHandlerSupplier )
10388 .thenApply ( Supplier ::get )
10489 .thenCompose ( subSelectFetchKeyHandler -> session
10590 .reactiveAutoFlushIfRequired ( jdbcSelect .getAffectedTableNames () )
106- .thenCompose ( required -> StandardReactiveSelectExecutor .INSTANCE
107- .list ( jdbcSelect ,
108- jdbcParameterBindings ,
109- ConcreteSqmSelectQueryPlan .listInterpreterExecutionContext ( hql , executionContext , jdbcSelect , subSelectFetchKeyHandler ),
110- rowTransformer ,
111- ReactiveListResultsConsumer .UniqueSemantic .ALLOW
112- )
91+ .thenCompose ( required -> {
92+ final Expression fetchExpression = sqmInterpretation .statement ().getQueryPart ().getFetchClauseExpression ();
93+ final int resultCountEstimate = fetchExpression != null
94+ ? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
95+ : -1 ;
96+ return StandardReactiveSelectExecutor .INSTANCE .list (
97+ jdbcSelect ,
98+ jdbcParameterBindings ,
99+ ConcreteSqmSelectQueryPlan .listInterpreterExecutionContext ( hql , executionContext , jdbcSelect , subSelectFetchKeyHandler ),
100+ rowTransformer ,
101+ (Class <R >) executionContext .getResultType (),
102+ ReactiveListResultsConsumer .UniqueSemantic .ALLOW ,
103+ resultCountEstimate
104+ );
105+ }
113106 )
114107 )
115108 .whenComplete ( (rs , t ) -> domainParameterXref .clearExpansions () );
@@ -119,15 +112,15 @@ private static <R> CompletionStage<Object> executeQueryInterpreter(
119112 String hql ,
120113 DomainParameterXref domainParameterXref ,
121114 DomainQueryExecutionContext executionContext ,
122- CacheableSqmInterpretation sqmInterpretation ,
115+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
123116 JdbcParameterBindings jdbcParameterBindings ,
124117 RowTransformer <R > rowTransformer ,
125118 ReactiveResultsConsumer <Object , R > resultsConsumer ) {
126119 final ReactiveSharedSessionContractImplementor session = (ReactiveSharedSessionContractImplementor ) executionContext .getSession ();
127- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
120+ final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
128121 // I'm using a supplier so that the whenComplete at the end will catch any errors, like a finally-block
129- Supplier <SubselectFetch .RegistrationHandler > fetchHandlerSupplier = () -> SubselectFetch
130- .createRegistrationHandler ( session .getPersistenceContext ().getBatchFetchQueue (), sqmInterpretation .selectStatement , JdbcParametersList .empty (), jdbcParameterBindings );
122+ final Supplier <SubselectFetch .RegistrationHandler > fetchHandlerSupplier = () -> SubselectFetch
123+ .createRegistrationHandler ( session .getPersistenceContext ().getBatchFetchQueue (), sqmInterpretation .statement () , JdbcParametersList .empty (), jdbcParameterBindings );
131124 return completedFuture ( fetchHandlerSupplier )
132125 .thenApply ( Supplier ::get )
133126 .thenCompose ( subSelectFetchKeyHandler -> session
@@ -153,9 +146,9 @@ private static <R> CompletionStage<Object> executeQueryInterpreter(
153146 }
154147
155148 private static int resultCountEstimate (
156- CacheableSqmInterpretation sqmInterpretation ,
149+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
157150 JdbcParameterBindings jdbcParameterBindings ) {
158- final Expression fetchExpression = sqmInterpretation .selectStatement .getQueryPart ()
151+ final Expression fetchExpression = sqmInterpretation .statement () .getQueryPart ()
159152 .getFetchClauseExpression ();
160153 return fetchExpression != null
161154 ? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
@@ -191,32 +184,32 @@ private <T, X> CompletionStage<T> withCacheableSqmInterpretation(DomainQueryExec
191184 // to protect access. However, synchronized is much simpler here. We will verify
192185 // during throughput testing whether this is an issue and consider changes then
193186
194- CacheableSqmInterpretation localCopy = cacheableSqmInterpretation ;
187+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > localCopy = cacheableSqmInterpretation ;
195188 JdbcParameterBindings jdbcParameterBindings = null ;
196189
197190 if ( localCopy == null ) {
198191 synchronized ( this ) {
199192 localCopy = cacheableSqmInterpretation ;
200193 if ( localCopy == null ) {
201- localCopy = buildCacheableSqmInterpretation ( sqm , domainParameterXref , executionContext );
202- jdbcParameterBindings = localCopy . firstParameterBindings ;
203- localCopy . firstParameterBindings = null ;
194+ final MutableObject < JdbcParameterBindings > mutableValue = new MutableObject <>( );
195+ localCopy = buildInterpretation ( sqm , domainParameterXref , executionContext , mutableValue ) ;
196+ jdbcParameterBindings = mutableValue . get () ;
204197 cacheableSqmInterpretation = localCopy ;
205198 }
206199 }
207200 }
208201 else {
209202 // If the translation depends on parameter bindings, or it isn't compatible with the current query options,
210203 // we have to rebuild the JdbcSelect, which is still better than having to translate from SQM to SQL AST again
211- if ( localCopy .jdbcSelect .dependsOnParameterBindings () ) {
204+ if ( localCopy .jdbcOperation () .dependsOnParameterBindings () ) {
212205 jdbcParameterBindings = createJdbcParameterBindings ( localCopy , executionContext );
213206 }
214207 // If the translation depends on the limit or lock options, we have to rebuild the JdbcSelect
215208 // We could avoid this by putting the lock options into the cache key
216- if ( !localCopy .jdbcSelect .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
217- localCopy = buildCacheableSqmInterpretation ( sqm , domainParameterXref , executionContext );
218- jdbcParameterBindings = localCopy . firstParameterBindings ;
219- localCopy . firstParameterBindings = null ;
209+ if ( !localCopy .jdbcOperation () .isCompatibleWith ( jdbcParameterBindings , executionContext .getQueryOptions () ) ) {
210+ final MutableObject < JdbcParameterBindings > mutableValue = new MutableObject <>( );
211+ localCopy = buildInterpretation ( sqm , domainParameterXref , executionContext , mutableValue ) ;
212+ jdbcParameterBindings = mutableValue . get () ;
220213 cacheableSqmInterpretation = localCopy ;
221214 }
222215 }
@@ -228,130 +221,12 @@ private <T, X> CompletionStage<T> withCacheableSqmInterpretation(DomainQueryExec
228221 return interpreter .interpret ( context , executionContext , localCopy , jdbcParameterBindings );
229222 }
230223
231- // Copy and paste from ORM
232- private JdbcParameterBindings createJdbcParameterBindings (CacheableSqmInterpretation sqmInterpretation , DomainQueryExecutionContext executionContext ) {
233- return SqmUtil .createJdbcParameterBindings (
234- executionContext .getQueryParameterBindings (),
235- domainParameterXref ,
236- sqmInterpretation .getJdbcParamsXref (),
237- new SqmParameterMappingModelResolutionAccess () {
238- //this is pretty ugly!
239- @ Override @ SuppressWarnings ("unchecked" )
240- public <T > MappingModelExpressible <T > getResolvedMappingModelType (SqmParameter <T > parameter ) {
241- return (MappingModelExpressible <T >) sqmInterpretation .getSqmParameterMappingModelTypes ().get (parameter );
242- }
243- },
244- executionContext .getSession ()
245- );
246- }
247-
248- private static CacheableSqmInterpretation buildCacheableSqmInterpretation (
249- SqmSelectStatement <?> sqm ,
250- DomainParameterXref domainParameterXref ,
251- DomainQueryExecutionContext executionContext ) {
252- final SharedSessionContractImplementor session = executionContext .getSession ();
253- final SessionFactoryImplementor sessionFactory = session .getFactory ();
254- final QueryEngine queryEngine = sessionFactory .getQueryEngine ();
255-
256- final SqmTranslatorFactory sqmTranslatorFactory = queryEngine .getSqmTranslatorFactory ();
257-
258- final SqmTranslator <SelectStatement > sqmConverter = sqmTranslatorFactory .createSelectTranslator (
259- sqm ,
260- executionContext .getQueryOptions (),
261- domainParameterXref ,
262- executionContext .getQueryParameterBindings (),
263- executionContext .getSession ().getLoadQueryInfluencers (),
264- sessionFactory .getSqlTranslationEngine (),
265- true
266- );
267-
268- // tableGroupAccess = sqmConverter.getFromClauseAccess();
269- final SqmTranslation <SelectStatement > sqmInterpretation = sqmConverter .translate ();
270- final FromClauseAccess tableGroupAccess = sqmConverter .getFromClauseAccess ();
271- final JdbcServices jdbcServices = sessionFactory .getJdbcServices ();
272- final JdbcEnvironment jdbcEnvironment = jdbcServices .getJdbcEnvironment ();
273- final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment .getSqlAstTranslatorFactory ();
274- final SqlAstTranslator <JdbcOperationQuerySelect > selectTranslator = sqlAstTranslatorFactory
275- .buildSelectTranslator ( sessionFactory , sqmInterpretation .getSqlAst () );
276- final Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> jdbcParamsXref = SqmUtil
277- .generateJdbcParamsXref ( domainParameterXref , sqmInterpretation ::getJdbcParamsBySqmParam );
278- final JdbcParameterBindings jdbcParameterBindings = SqmUtil .createJdbcParameterBindings (
279- executionContext .getQueryParameterBindings (),
280- domainParameterXref ,
281- jdbcParamsXref ,
282- new SqmParameterMappingModelResolutionAccess () {
283- @ Override @ SuppressWarnings ("unchecked" )
284- public <T > MappingModelExpressible <T > getResolvedMappingModelType (SqmParameter <T > parameter ) {
285- return (MappingModelExpressible <T >) sqmInterpretation .getSqmParameterMappingModelTypeResolutions ().get (parameter );
286- }
287- },
288- session
289- );
290-
291- final JdbcOperationQuerySelect jdbcSelect = selectTranslator .translate (
292- jdbcParameterBindings ,
293- executionContext .getQueryOptions ()
294- );
295-
296- return new CacheableSqmInterpretation (
297- sqmInterpretation .getSqlAst (),
298- jdbcSelect ,
299- tableGroupAccess ,
300- jdbcParamsXref ,
301- sqmInterpretation .getSqmParameterMappingModelTypeResolutions (),
302- jdbcParameterBindings
303- );
304- }
305-
306224 private interface SqmInterpreter <T , X > {
307225 CompletionStage <T > interpret (
308226 X context ,
309227 DomainQueryExecutionContext executionContext ,
310- CacheableSqmInterpretation sqmInterpretation ,
228+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
311229 JdbcParameterBindings jdbcParameterBindings );
312230 }
313231
314- private static class CacheableSqmInterpretation {
315- private final SelectStatement selectStatement ;
316- private final JdbcOperationQuerySelect jdbcSelect ;
317- private final FromClauseAccess tableGroupAccess ;
318- private final Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> jdbcParamsXref ;
319- private final Map <SqmParameter <?>, MappingModelExpressible <?>> sqmParameterMappingModelTypes ;
320- private transient JdbcParameterBindings firstParameterBindings ;
321-
322- CacheableSqmInterpretation (
323- SelectStatement selectStatement ,
324- JdbcOperationQuerySelect jdbcSelect ,
325- FromClauseAccess tableGroupAccess ,
326- Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> jdbcParamsXref ,
327- Map <SqmParameter <?>, MappingModelExpressible <?>> sqmParameterMappingModelTypes ,
328- JdbcParameterBindings firstParameterBindings ) {
329- this .selectStatement = selectStatement ;
330- this .jdbcSelect = jdbcSelect ;
331- this .tableGroupAccess = tableGroupAccess ;
332- this .jdbcParamsXref = jdbcParamsXref ;
333- this .sqmParameterMappingModelTypes = sqmParameterMappingModelTypes ;
334- this .firstParameterBindings = firstParameterBindings ;
335- }
336-
337- SelectStatement getSelectStatement () {
338- return selectStatement ;
339- }
340-
341- JdbcOperationQuerySelect getJdbcSelect () {
342- return jdbcSelect ;
343- }
344-
345- FromClauseAccess getTableGroupAccess () {
346- return tableGroupAccess ;
347- }
348-
349- Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> getJdbcParamsXref () {
350- return jdbcParamsXref ;
351- }
352-
353- public Map <SqmParameter <?>, MappingModelExpressible <?>> getSqmParameterMappingModelTypes () {
354- return sqmParameterMappingModelTypes ;
355- }
356- }
357232}
0 commit comments