37
37
import org .hibernate .query .sqm .tree .expression .ValueBindJpaCriteriaParameter ;
38
38
import org .hibernate .query .sqm .tree .expression .SqmParameter ;
39
39
import org .hibernate .query .sqm .tree .from .SqmFromClause ;
40
+ import org .hibernate .query .sqm .tree .from .SqmRoot ;
40
41
42
+ import static org .hibernate .query .sqm .tree .SqmCopyContext .noParamCopyContext ;
41
43
import static org .hibernate .query .sqm .tree .jpa .ParameterCollector .collectParameters ;
42
44
43
45
/**
@@ -119,6 +121,10 @@ public SqmSelectStatement<T> copy(SqmCopyContext context) {
119
121
if ( existing != null ) {
120
122
return existing ;
121
123
}
124
+ return createCopy ( context , getResultType () );
125
+ }
126
+
127
+ private <X > SqmSelectStatement <X > createCopy (SqmCopyContext context , Class <X > resultType ) {
122
128
final Set <SqmParameter <?>> parameters ;
123
129
if ( this .parameters == null ) {
124
130
parameters = null ;
@@ -129,17 +135,19 @@ public SqmSelectStatement<T> copy(SqmCopyContext context) {
129
135
parameters .add ( parameter .copy ( context ) );
130
136
}
131
137
}
132
- final SqmSelectStatement <T > statement = context .registerCopy (
138
+ //noinspection unchecked
139
+ final SqmSelectStatement <X > statement = (SqmSelectStatement <X >) context .registerCopy (
133
140
this ,
134
141
new SqmSelectStatement <>(
135
142
nodeBuilder (),
136
143
copyCteStatements ( context ),
137
- getResultType () ,
144
+ resultType ,
138
145
getQuerySource (),
139
146
parameters
140
147
)
141
148
);
142
- statement .setQueryPart ( getQueryPart ().copy ( context ) );
149
+ //noinspection unchecked
150
+ statement .setQueryPart ( (SqmQueryPart <X >) getQueryPart ().copy ( context ) );
143
151
return statement ;
144
152
}
145
153
@@ -266,9 +274,6 @@ public SqmSelectStatement<T> select(Selection<? extends T> selection) {
266
274
checkSelectionIsJpaCompliant ( selection );
267
275
}
268
276
getQuerySpec ().setSelection ( (JpaSelection <T >) selection );
269
- if ( getResultType () == Object .class ) {
270
- setResultType ( (Class <T >) selection .getJavaType () );
271
- }
272
277
return this ;
273
278
}
274
279
@@ -309,7 +314,6 @@ public SqmSelectStatement<T> multiselect(List<Selection<?>> selectionList) {
309
314
break ;
310
315
}
311
316
default : {
312
- setResultType ( (Class <T >) Object [].class );
313
317
resultSelection = ( Selection <? extends T > ) nodeBuilder ().array ( selections );
314
318
}
315
319
}
@@ -460,49 +464,43 @@ private void validateComplianceFetchOffset() {
460
464
}
461
465
462
466
@ Override
463
- public JpaCriteriaQuery <Long > createCountQuery () {
464
- final SqmCopyContext context = new NoParamSqmCopyContext () {
465
- @ Override
466
- public boolean copyFetchedFlag () {
467
- return false ;
467
+ public SqmSelectStatement <Long > createCountQuery () {
468
+ final SqmSelectStatement <?> copy = createCopy ( noParamCopyContext (), Object .class );
469
+ final SqmQueryPart <?> queryPart = copy .getQueryPart ();
470
+ final SqmQuerySpec <?> querySpec ;
471
+ //TODO: detect queries with no 'group by', but aggregate functions
472
+ // in 'select' list (we don't even need to hit the database to
473
+ // know they return exactly one row)
474
+ if ( queryPart .isSimpleQueryPart ()
475
+ && !( querySpec = (SqmQuerySpec <?>) queryPart ).isDistinct ()
476
+ && querySpec .getGroupingExpressions ().isEmpty () ) {
477
+ for ( SqmRoot <?> root : querySpec .getRootList () ) {
478
+ root .removeLeftFetchJoins ();
468
479
}
469
- };
470
- final NodeBuilder nodeBuilder = nodeBuilder ();
471
- final Set <SqmParameter <?>> parameters ;
472
- if ( this .parameters == null ) {
473
- parameters = null ;
480
+ querySpec .getSelectClause ().setSelection ( nodeBuilder ().count ( new SqmStar ( nodeBuilder () )) );
481
+ if ( querySpec .getFetch () == null && querySpec .getOffset () == null ) {
482
+ querySpec .setOrderByClause ( null );
483
+ }
484
+
485
+ return (SqmSelectStatement <Long >) copy ;
474
486
}
475
487
else {
476
- parameters = new LinkedHashSet <>( this .parameters .size () );
477
- for ( SqmParameter <?> parameter : this .parameters ) {
478
- parameters .add ( parameter .copy ( context ) );
488
+ final JpaSelection <?> selection = queryPart .getFirstQuerySpec ().getSelection ();
489
+ if ( selection .isCompoundSelection () ) {
490
+ char c = 'a' ;
491
+ for ( JpaSelection <?> item : selection .getSelectionItems () ) {
492
+ item .alias ( Character .toString ( ++c ) + '_' );
493
+ }
479
494
}
495
+ else {
496
+ selection .alias ( "a_" );
497
+ }
498
+ final SqmSubQuery <?> subquery = new SqmSubQuery <>( copy , queryPart , null , nodeBuilder () );
499
+ final SqmSelectStatement <Long > query = nodeBuilder ().createQuery ( Long .class );
500
+ query .from ( subquery );
501
+ query .select ( nodeBuilder ().count ( new SqmStar (nodeBuilder ())) );
502
+ return query ;
480
503
}
481
- final SqmSelectStatement <Long > selectStatement = new SqmSelectStatement <>(
482
- nodeBuilder ,
483
- copyCteStatements ( context ),
484
- Long .class ,
485
- SqmQuerySource .CRITERIA ,
486
- parameters
487
- );
488
- final SqmQuerySpec <Long > querySpec = new SqmQuerySpec <>( nodeBuilder );
489
-
490
- final SqmSubQuery <Tuple > subquery = new SqmSubQuery <>( selectStatement , Tuple .class , nodeBuilder );
491
- final SqmQueryPart <T > queryPart = getQueryPart ().copy ( context );
492
- resetSelections ( queryPart );
493
- // Reset the
494
- if ( queryPart .getFetch () == null && queryPart .getOffset () == null ) {
495
- queryPart .setOrderByClause ( null );
496
- }
497
- //noinspection unchecked
498
- subquery .setQueryPart ( (SqmQueryPart <Tuple >) queryPart );
499
-
500
- querySpec .setFromClause ( new SqmFromClause ( 1 ) );
501
- querySpec .setSelectClause ( new SqmSelectClause ( false , 1 , nodeBuilder ) );
502
- selectStatement .setQueryPart ( querySpec );
503
- selectStatement .select ( nodeBuilder .count ( new SqmStar ( nodeBuilder ) ) );
504
- selectStatement .from ( subquery );
505
- return selectStatement ;
506
504
}
507
505
508
506
private void resetSelections (SqmQueryPart <?> queryPart ) {
0 commit comments