1313
1414import jakarta .persistence .metamodel .Bindable ;
1515import org .hibernate .Incubating ;
16- import org .hibernate .internal .util .collections .CollectionHelper ;
1716import org .hibernate .metamodel .UnsupportedMappingException ;
1817import org .hibernate .metamodel .model .domain .DomainType ;
1918import org .hibernate .metamodel .model .domain .EntityDomainType ;
2827import org .hibernate .query .sqm .SqmPathSource ;
2928import org .hibernate .query .sqm .tree .domain .SqmPath ;
3029import org .hibernate .query .sqm .tree .select .SqmSelectClause ;
30+ import org .hibernate .query .sqm .tree .select .SqmSelectQuery ;
3131import org .hibernate .query .sqm .tree .select .SqmSelectableNode ;
32- import org .hibernate .query .sqm .tree .select .SqmSubQuery ;
32+ import org .hibernate .query .sqm .tree .select .SqmSelection ;
3333import org .hibernate .sql .ast .spi .FromClauseAccess ;
3434import org .hibernate .sql .ast .spi .SqlSelection ;
35- import org .hibernate .type .BasicType ;
3635import org .hibernate .type .descriptor .java .JavaType ;
3736import org .hibernate .type .descriptor .java .ObjectArrayJavaType ;
3837
3938import jakarta .persistence .metamodel .Attribute ;
4039
40+ import static org .hibernate .internal .util .collections .CollectionHelper .linkedMapOfSize ;
41+
4142
4243/**
4344 * @author Christian Beikov
@@ -47,43 +48,58 @@ public class AnonymousTupleType<T> implements TupleType<T>, DomainType<T>, Retur
4748
4849 private final ObjectArrayJavaType javaTypeDescriptor ;
4950 private final SqmSelectableNode <?>[] components ;
51+ private final String [] componentNames ;
5052 private final Map <String , Integer > componentIndexMap ;
5153
52- public AnonymousTupleType (SqmSubQuery <T > subQuery ) {
53- this ( extractSqmExpressibles ( subQuery ) );
54- }
54+ public AnonymousTupleType (SqmSelectQuery <T > selectQuery ) {
55+ final SqmSelectClause selectClause = selectQuery .getQueryPart ()
56+ .getFirstQuerySpec ()
57+ .getSelectClause ();
5558
56- public AnonymousTupleType (SqmSelectableNode <?>[] components ) {
57- this .components = components ;
58- this .javaTypeDescriptor = new ObjectArrayJavaType ( getTypeDescriptors ( components ) );
59- final Map <String , Integer > map = CollectionHelper .linkedMapOfSize ( components .length );
60- for ( int i = 0 ; i < components .length ; i ++ ) {
61- final SqmSelectableNode <?> component = components [i ];
62- final String alias = component .getAlias ();
59+ if ( selectClause == null || selectClause .getSelections ().isEmpty () ) {
60+ throw new IllegalArgumentException ( "selectQuery has no selection items" );
61+ }
62+ // todo: right now, we "snapshot" the state of the selectQuery when creating this type, but maybe we shouldn't?
63+ // i.e. what if the selectQuery changes later on? Or should we somehow mark the selectQuery to signal,
64+ // that changes to the select clause are invalid after a certain point?
65+
66+ final List <SqmSelection <?>> selections = selectClause .getSelections ();
67+ final List <SqmSelectableNode <?>> selectableNodes = new ArrayList <>();
68+ final List <String > aliases = new ArrayList <>();
69+ for ( SqmSelection <?> selection : selections ) {
70+ final boolean compound = selection .getSelectableNode ().isCompoundSelection ();
71+ selection .getSelectableNode ().visitSubSelectableNodes ( node -> {
72+ selectableNodes .add ( node );
73+ if ( compound ) {
74+ aliases .add ( node .getAlias () );
75+ }
76+ } );
77+ if ( !compound ) {
78+ // for compound selections we use the sub-selectable nodes aliases
79+ aliases .add ( selection .getAlias () );
80+ }
81+ }
82+
83+ components = new SqmSelectableNode <?>[selectableNodes .size ()];
84+ componentNames = new String [selectableNodes .size ()];
85+ javaTypeDescriptor = new ObjectArrayJavaType ( getTypeDescriptors ( selectableNodes ) );
86+ componentIndexMap = linkedMapOfSize ( selectableNodes .size () );
87+ for ( int i = 0 ; i < selectableNodes .size (); i ++ ) {
88+ components [i ] = selectableNodes .get (i );
89+ String alias = aliases .get ( i );
6390 if ( alias == null ) {
6491 throw new SemanticException ( "Select item at position " + (i +1 ) + " in select list has no alias"
6592 + " (aliases are required in CTEs and in subqueries occurring in from clause)" );
6693 }
67- map .put ( alias , i );
68- }
69- this .componentIndexMap = map ;
70- }
71-
72- private static SqmSelectableNode <?>[] extractSqmExpressibles (SqmSubQuery <?> subQuery ) {
73- final SqmSelectClause selectClause = subQuery .getQuerySpec ().getSelectClause ();
74- if ( selectClause == null || selectClause .getSelectionItems ().isEmpty () ) {
75- throw new IllegalArgumentException ( "subquery has no selection items" );
94+ componentIndexMap .put ( alias , i );
95+ componentNames [i ] = alias ;
7696 }
77- // todo: right now, we "snapshot" the state of the subquery when creating this type, but maybe we shouldn't?
78- // i.e. what if the subquery changes later on? Or should we somehow mark the subquery to signal,
79- // that changes to the select clause are invalid after a certain point?
80- return selectClause .getSelectionItems ().toArray ( SqmSelectableNode []::new );
8197 }
8298
83- private static JavaType <?>[] getTypeDescriptors (SqmSelectableNode <?>[] components ) {
84- final JavaType <?>[] typeDescriptors = new JavaType <?>[components .length ];
85- for ( int i = 0 ; i < components .length ; i ++ ) {
86- typeDescriptors [i ] = components [ i ] .getExpressible ().getExpressibleJavaType ();
99+ private static JavaType <?>[] getTypeDescriptors (List < SqmSelectableNode <?>> components ) {
100+ final JavaType <?>[] typeDescriptors = new JavaType <?>[components .size () ];
101+ for ( int i = 0 ; i < components .size () ; i ++ ) {
102+ typeDescriptors [i ] = components . get ( i ) .getExpressible ().getExpressibleJavaType ();
87103 }
88104 return typeDescriptors ;
89105 }
@@ -143,7 +159,7 @@ public int componentCount() {
143159
144160 @ Override
145161 public String getComponentName (int index ) {
146- return components [index ]. getAlias () ;
162+ return componentNames [index ];
147163 }
148164
149165 @ Override
0 commit comments