2222import  org .hibernate .query .sqm .SqmPathSource ;
2323import  org .hibernate .query .sqm .tree .domain .SqmDomainType ;
2424import  org .hibernate .query .sqm .tree .domain .SqmPluralPersistentAttribute ;
25+ import  org .hibernate .query .sqm .tree .select .SqmSelectQuery ;
26+ import  org .hibernate .query .sqm .tree .select .SqmSelection ;
2527import  org .hibernate .query .sqm .tuple .TupleType ;
2628import  org .hibernate .query .SemanticException ;
2729import  org .hibernate .query .sqm .SqmExpressible ;
2830import  org .hibernate .query .sqm .tree .domain .SqmPath ;
2931import  org .hibernate .query .sqm .tree .select .SqmSelectClause ;
3032import  org .hibernate .query .sqm .tree .select .SqmSelectableNode ;
31- import  org .hibernate .query .sqm .tree .select .SqmSubQuery ;
3233import  org .hibernate .spi .NavigablePath ;
3334import  org .hibernate .sql .ast .spi .FromClauseAccess ;
3435import  org .hibernate .sql .ast .spi .SqlSelection ;
@@ -55,26 +56,47 @@ public class AnonymousTupleType<T>
5556	private  final  String [] componentNames ;
5657	private  final  Map <String , Integer > componentIndexMap ;
5758
58- 	public  AnonymousTupleType (SqmSubQuery <T > subQuery ) {
59- 		this ( extractSqmExpressibles ( subQuery  ) );
60- 	}
59+ 	public  AnonymousTupleType (SqmSelectQuery <T > selectQuery ) {
60+ 		final  SqmSelectClause  selectClause  = selectQuery .getQueryPart ()
61+ 				.getFirstQuerySpec ()
62+ 				.getSelectClause ();
6163
62- 	public  AnonymousTupleType (SqmSelectableNode <?>[] components ) {
63- 		expressibles  = new  SqmBindableType <?>[components .length ];
64- 		componentSourcePaths  = new  NavigablePath [components .length ];
65- 		for  ( int  i  = 0 ; i  < components .length ; i ++ ) {
66- 			expressibles [i ] = components [i ].getNodeType ();
67- 			if  ( components [i ] instanceof  SqmPath <?> path  ) {
68- 				componentSourcePaths [i ] = path .getNavigablePath ();
64+ 		if  ( selectClause  == null  || selectClause .getSelections ().isEmpty () ) {
65+ 			throw  new  IllegalArgumentException ( "selectQuery has no selection items"  );
66+ 		}
67+ 		// todo: right now, we "snapshot" the state of the selectQuery when creating this type, but maybe we shouldn't? 
68+ 		//  i.e. what if the selectQuery changes later on? Or should we somehow mark the selectQuery to signal, 
69+ 		//  that changes to the select clause are invalid after a certain point? 
70+ 
71+ 		final  List <SqmSelection <?>> selections  = selectClause .getSelections ();
72+ 		final  List <SqmSelectableNode <?>> selectableNodes  = new  ArrayList <>();
73+ 		final  List <String > aliases  = new  ArrayList <>();
74+ 		for  ( SqmSelection <?> selection  : selections  ) {
75+ 			final  boolean  compound  = selection .getSelectableNode ().isCompoundSelection ();
76+ 			selection .getSelectableNode ().visitSubSelectableNodes ( node  -> {
77+ 				selectableNodes .add ( node  );
78+ 				if  ( compound  ) {
79+ 					aliases .add ( node .getAlias () );
80+ 				}
81+ 			} );
82+ 			if  ( !compound  ) {
83+ 				// for compound selections we use the sub-selectable nodes aliases 
84+ 				aliases .add ( selection .getAlias () );
6985			}
7086		}
71- 		componentNames  = new  String [components .length ];
87+ 
88+ 		expressibles  = new  SqmBindableType <?>[selectableNodes .size ()];
89+ 		componentSourcePaths  = new  NavigablePath [selectableNodes .size ()];
90+ 		componentNames  = new  String [selectableNodes .size ()];
7291		//noinspection unchecked 
73- 		javaTypeDescriptor  = (JavaType <T >) new  ObjectArrayJavaType ( getTypeDescriptors ( components  ) );
74- 		componentIndexMap  = linkedMapOfSize ( components .length  );
75- 		for  ( int  i  = 0 ; i  < components .length ; i ++ ) {
76- 			final  SqmSelectableNode <?> component  = components [i ];
77- 			final  String  alias  = component .getAlias ();
92+ 		javaTypeDescriptor  = (JavaType <T >) new  ObjectArrayJavaType ( getTypeDescriptors ( selectableNodes  ) );
93+ 		componentIndexMap  = linkedMapOfSize ( selectableNodes .size () );
94+ 		for  ( int  i  = 0 ; i  < selectableNodes .size (); i ++ ) {
95+ 			expressibles [i ] = selectableNodes .get ( i  ).getNodeType ();
96+ 			if  ( selectableNodes .get ( i  ) instanceof  SqmPath <?> path  ) {
97+ 				componentSourcePaths [i ] = path .getNavigablePath ();
98+ 			}
99+ 			String  alias  = aliases .get ( i  );
78100			if  ( alias  == null  ) {
79101				throw  new  SemanticException ( "Select item at position "  + (i +1 ) + " in select list has no alias" 
80102						+ " (aliases are required in CTEs and in subqueries occurring in from clause)"  );
@@ -110,21 +132,10 @@ public String getTypeName() {
110132		return  SqmDomainType .super .getTypeName ();
111133	}
112134
113- 	private  static  SqmSelectableNode <?>[] extractSqmExpressibles (SqmSubQuery <?> subQuery ) {
114- 		final  SqmSelectClause  selectClause  = subQuery .getQuerySpec ().getSelectClause ();
115- 		if  ( selectClause  == null  || selectClause .getSelectionItems ().isEmpty () ) {
116- 			throw  new  IllegalArgumentException ( "subquery has no selection items"  );
117- 		}
118- 		// todo: right now, we "snapshot" the state of the subquery when creating this type, but maybe we shouldn't? 
119- 		//  i.e. what if the subquery changes later on? Or should we somehow mark the subquery to signal, 
120- 		//  that changes to the select clause are invalid after a certain point? 
121- 		return  selectClause .getSelectionItems ().toArray ( SqmSelectableNode []::new  );
122- 	}
123- 
124- 	private  static  JavaType <?>[] getTypeDescriptors (SqmSelectableNode <?>[] components ) {
125- 		final  JavaType <?>[] typeDescriptors  = new  JavaType <?>[components .length ];
126- 		for  ( int  i  = 0 ; i  < components .length ; i ++ ) {
127- 			typeDescriptors [i ] = components [i ].getExpressible ().getExpressibleJavaType ();
135+ 	private  static  JavaType <?>[] getTypeDescriptors (List <SqmSelectableNode <?>> components ) {
136+ 		final  JavaType <?>[] typeDescriptors  = new  JavaType <?>[components .size ()];
137+ 		for  ( int  i  = 0 ; i  < components .size (); i ++ ) {
138+ 			typeDescriptors [i ] = components .get ( i  ).getExpressible ().getExpressibleJavaType ();
128139		}
129140		return  typeDescriptors ;
130141	}
0 commit comments