6
6
package org .hibernate .reactive .query .sqm .internal ;
7
7
8
8
import java .util .List ;
9
- import java .util .Map ;
10
9
import java .util .concurrent .CompletionStage ;
11
10
import java .util .function .Supplier ;
12
11
13
12
import 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 ;
18
13
import org .hibernate .engine .spi .SubselectFetch ;
19
- import org .hibernate .metamodel . mapping . MappingModelExpressible ;
14
+ import org .hibernate .internal . util . MutableObject ;
20
15
import org .hibernate .query .Query ;
21
16
import org .hibernate .query .spi .DomainQueryExecutionContext ;
22
- import org .hibernate .query .spi .QueryEngine ;
23
17
import org .hibernate .query .spi .QueryOptions ;
24
- import org .hibernate .query .spi .QueryParameterImplementor ;
25
18
import org .hibernate .query .spi .ScrollableResultsImplementor ;
19
+ import org .hibernate .query .sqm .internal .CacheableSqmInterpretation ;
26
20
import org .hibernate .query .sqm .internal .ConcreteSqmSelectQueryPlan ;
27
21
import 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 ;
34
22
import org .hibernate .query .sqm .tree .select .SqmSelectStatement ;
35
23
import org .hibernate .reactive .engine .spi .ReactiveSharedSessionContractImplementor ;
36
24
import org .hibernate .reactive .query .sqm .spi .ReactiveSelectQueryPlan ;
37
25
import org .hibernate .reactive .sql .exec .internal .StandardReactiveSelectExecutor ;
38
26
import org .hibernate .reactive .sql .results .spi .ReactiveListResultsConsumer ;
39
27
import 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 ;
43
28
import org .hibernate .sql .ast .tree .expression .Expression ;
44
29
import org .hibernate .sql .ast .tree .select .SelectStatement ;
45
30
import org .hibernate .sql .exec .spi .JdbcOperationQuerySelect ;
@@ -68,7 +53,7 @@ public class ConcreteSqmSelectReactiveQueryPlan<R> extends ConcreteSqmSelectQuer
68
53
private final SqmSelectStatement <?> sqm ;
69
54
private final DomainParameterXref domainParameterXref ;
70
55
71
- private volatile CacheableSqmInterpretation cacheableSqmInterpretation ;
56
+ private volatile CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > cacheableSqmInterpretation ;
72
57
73
58
public ConcreteSqmSelectReactiveQueryPlan (
74
59
SqmSelectStatement <?> sqm ,
@@ -91,25 +76,33 @@ private static <R> CompletionStage<List<R>> listInterpreter(
91
76
String hql ,
92
77
DomainParameterXref domainParameterXref ,
93
78
DomainQueryExecutionContext executionContext ,
94
- CacheableSqmInterpretation sqmInterpretation ,
79
+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
95
80
JdbcParameterBindings jdbcParameterBindings ,
96
81
RowTransformer <R > rowTransformer ) {
97
82
final ReactiveSharedSessionContractImplementor session = (ReactiveSharedSessionContractImplementor ) executionContext .getSession ();
98
- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
83
+ JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
99
84
// I'm using a supplier so that the whenComplete at the end will catch any errors, like a finally-block
100
85
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 );
102
87
return completedFuture ( fetchHandlerSupplier )
103
88
.thenApply ( Supplier ::get )
104
89
.thenCompose ( subSelectFetchKeyHandler -> session
105
90
.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
+ }
113
106
)
114
107
)
115
108
.whenComplete ( (rs , t ) -> domainParameterXref .clearExpansions () );
@@ -119,15 +112,15 @@ private static <R> CompletionStage<Object> executeQueryInterpreter(
119
112
String hql ,
120
113
DomainParameterXref domainParameterXref ,
121
114
DomainQueryExecutionContext executionContext ,
122
- CacheableSqmInterpretation sqmInterpretation ,
115
+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
123
116
JdbcParameterBindings jdbcParameterBindings ,
124
117
RowTransformer <R > rowTransformer ,
125
118
ReactiveResultsConsumer <Object , R > resultsConsumer ) {
126
119
final ReactiveSharedSessionContractImplementor session = (ReactiveSharedSessionContractImplementor ) executionContext .getSession ();
127
- final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .getJdbcSelect ();
120
+ final JdbcOperationQuerySelect jdbcSelect = sqmInterpretation .jdbcOperation ();
128
121
// 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 );
131
124
return completedFuture ( fetchHandlerSupplier )
132
125
.thenApply ( Supplier ::get )
133
126
.thenCompose ( subSelectFetchKeyHandler -> session
@@ -153,9 +146,9 @@ private static <R> CompletionStage<Object> executeQueryInterpreter(
153
146
}
154
147
155
148
private static int resultCountEstimate (
156
- CacheableSqmInterpretation sqmInterpretation ,
149
+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
157
150
JdbcParameterBindings jdbcParameterBindings ) {
158
- final Expression fetchExpression = sqmInterpretation .selectStatement .getQueryPart ()
151
+ final Expression fetchExpression = sqmInterpretation .statement () .getQueryPart ()
159
152
.getFetchClauseExpression ();
160
153
return fetchExpression != null
161
154
? interpretIntExpression ( fetchExpression , jdbcParameterBindings )
@@ -191,32 +184,32 @@ private <T, X> CompletionStage<T> withCacheableSqmInterpretation(DomainQueryExec
191
184
// to protect access. However, synchronized is much simpler here. We will verify
192
185
// during throughput testing whether this is an issue and consider changes then
193
186
194
- CacheableSqmInterpretation localCopy = cacheableSqmInterpretation ;
187
+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > localCopy = cacheableSqmInterpretation ;
195
188
JdbcParameterBindings jdbcParameterBindings = null ;
196
189
197
190
if ( localCopy == null ) {
198
191
synchronized ( this ) {
199
192
localCopy = cacheableSqmInterpretation ;
200
193
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 () ;
204
197
cacheableSqmInterpretation = localCopy ;
205
198
}
206
199
}
207
200
}
208
201
else {
209
202
// If the translation depends on parameter bindings, or it isn't compatible with the current query options,
210
203
// 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 () ) {
212
205
jdbcParameterBindings = createJdbcParameterBindings ( localCopy , executionContext );
213
206
}
214
207
// If the translation depends on the limit or lock options, we have to rebuild the JdbcSelect
215
208
// 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 () ;
220
213
cacheableSqmInterpretation = localCopy ;
221
214
}
222
215
}
@@ -228,130 +221,12 @@ private <T, X> CompletionStage<T> withCacheableSqmInterpretation(DomainQueryExec
228
221
return interpreter .interpret ( context , executionContext , localCopy , jdbcParameterBindings );
229
222
}
230
223
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
-
306
224
private interface SqmInterpreter <T , X > {
307
225
CompletionStage <T > interpret (
308
226
X context ,
309
227
DomainQueryExecutionContext executionContext ,
310
- CacheableSqmInterpretation sqmInterpretation ,
228
+ CacheableSqmInterpretation < SelectStatement , JdbcOperationQuerySelect > sqmInterpretation ,
311
229
JdbcParameterBindings jdbcParameterBindings );
312
230
}
313
231
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
- }
357
232
}
0 commit comments