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