13
13
14
14
import jakarta .persistence .metamodel .Bindable ;
15
15
import org .hibernate .Incubating ;
16
- import org .hibernate .internal .util .collections .CollectionHelper ;
17
16
import org .hibernate .metamodel .UnsupportedMappingException ;
18
17
import org .hibernate .metamodel .model .domain .DomainType ;
19
18
import org .hibernate .metamodel .model .domain .EntityDomainType ;
28
27
import org .hibernate .query .sqm .SqmPathSource ;
29
28
import org .hibernate .query .sqm .tree .domain .SqmPath ;
30
29
import org .hibernate .query .sqm .tree .select .SqmSelectClause ;
30
+ import org .hibernate .query .sqm .tree .select .SqmSelectQuery ;
31
31
import 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 ;
33
33
import org .hibernate .sql .ast .spi .FromClauseAccess ;
34
34
import org .hibernate .sql .ast .spi .SqlSelection ;
35
- import org .hibernate .type .BasicType ;
36
35
import org .hibernate .type .descriptor .java .JavaType ;
37
36
import org .hibernate .type .descriptor .java .ObjectArrayJavaType ;
38
37
39
38
import jakarta .persistence .metamodel .Attribute ;
40
39
40
+ import static org .hibernate .internal .util .collections .CollectionHelper .linkedMapOfSize ;
41
+
41
42
42
43
/**
43
44
* @author Christian Beikov
@@ -47,43 +48,58 @@ public class AnonymousTupleType<T> implements TupleType<T>, DomainType<T>, Retur
47
48
48
49
private final ObjectArrayJavaType javaTypeDescriptor ;
49
50
private final SqmSelectableNode <?>[] components ;
51
+ private final String [] componentNames ;
50
52
private final Map <String , Integer > componentIndexMap ;
51
53
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 ();
55
58
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 );
63
90
if ( alias == null ) {
64
91
throw new SemanticException ( "Select item at position " + (i +1 ) + " in select list has no alias"
65
92
+ " (aliases are required in CTEs and in subqueries occurring in from clause)" );
66
93
}
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 ;
76
96
}
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 );
81
97
}
82
98
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 ();
87
103
}
88
104
return typeDescriptors ;
89
105
}
@@ -143,7 +159,7 @@ public int componentCount() {
143
159
144
160
@ Override
145
161
public String getComponentName (int index ) {
146
- return components [index ]. getAlias () ;
162
+ return componentNames [index ];
147
163
}
148
164
149
165
@ Override
0 commit comments