24
24
import org .hibernate .metamodel .MappingMetamodel ;
25
25
import org .hibernate .metamodel .mapping .BasicValuedMapping ;
26
26
import org .hibernate .metamodel .mapping .Bindable ;
27
+ import org .hibernate .metamodel .mapping .CollectionPart ;
27
28
import org .hibernate .metamodel .mapping .EntityAssociationMapping ;
28
29
import org .hibernate .metamodel .mapping .EntityIdentifierMapping ;
29
30
import org .hibernate .metamodel .mapping .EntityMappingType ;
30
31
import org .hibernate .metamodel .mapping .ForeignKeyDescriptor ;
31
32
import org .hibernate .metamodel .mapping .JdbcMapping ;
32
- import org .hibernate .metamodel .mapping .ManagedMappingType ;
33
33
import org .hibernate .metamodel .mapping .MappingModelExpressible ;
34
+ import org .hibernate .metamodel .mapping .ModelPart ;
34
35
import org .hibernate .metamodel .mapping .ModelPartContainer ;
35
36
import org .hibernate .metamodel .mapping .PluralAttributeMapping ;
36
37
import org .hibernate .query .IllegalQueryOperationException ;
44
45
import org .hibernate .query .sqm .SqmQuerySource ;
45
46
import org .hibernate .query .sqm .spi .JdbcParameterBySqmParameterAccess ;
46
47
import org .hibernate .query .sqm .spi .SqmParameterMappingModelResolutionAccess ;
48
+ import org .hibernate .query .sqm .sql .SqmToSqlAstConverter ;
47
49
import org .hibernate .query .sqm .tree .SqmDmlStatement ;
48
50
import org .hibernate .query .sqm .tree .SqmJoinType ;
49
51
import org .hibernate .query .sqm .tree .SqmStatement ;
50
52
import org .hibernate .query .sqm .tree .domain .SqmPath ;
51
53
import org .hibernate .query .sqm .tree .expression .JpaCriteriaParameter ;
52
54
import org .hibernate .query .sqm .tree .expression .SqmAliasedNodeRef ;
55
+ import org .hibernate .query .sqm .tree .expression .SqmExpression ;
53
56
import org .hibernate .query .sqm .tree .expression .SqmJpaCriteriaParameterWrapper ;
54
57
import org .hibernate .query .sqm .tree .expression .SqmParameter ;
55
58
import org .hibernate .query .sqm .tree .from .SqmFrom ;
56
59
import org .hibernate .query .sqm .tree .from .SqmJoin ;
57
60
import org .hibernate .query .sqm .tree .from .SqmQualifiedJoin ;
58
61
import org .hibernate .query .sqm .tree .from .SqmRoot ;
62
+ import org .hibernate .query .sqm .tree .select .SqmOrderByClause ;
63
+ import org .hibernate .query .sqm .tree .select .SqmQueryPart ;
64
+ import org .hibernate .query .sqm .tree .select .SqmQuerySpec ;
59
65
import org .hibernate .query .sqm .tree .select .SqmSelectStatement ;
60
66
import org .hibernate .query .sqm .tree .select .SqmSelectableNode ;
61
67
import org .hibernate .query .sqm .tree .select .SqmSortSpecification ;
62
68
import org .hibernate .spi .NavigablePath ;
69
+ import org .hibernate .sql .ast .Clause ;
63
70
import org .hibernate .sql .ast .SqlTreeCreationException ;
64
71
import org .hibernate .sql .ast .tree .expression .JdbcParameter ;
65
72
import org .hibernate .sql .ast .tree .from .TableGroup ;
73
80
import org .hibernate .type .internal .ConvertedBasicTypeImpl ;
74
81
import org .hibernate .type .spi .TypeConfiguration ;
75
82
83
+ import static org .hibernate .internal .util .NullnessUtil .castNonNull ;
76
84
import static org .hibernate .query .sqm .tree .jpa .ParameterCollector .collectParameters ;
77
85
78
86
/**
@@ -126,13 +134,57 @@ public static IllegalQueryOperationException expectingNonSelect(SqmStatement<?>
126
134
}
127
135
128
136
/**
129
- * Utility that returns {@code true} if the specified {@link SqmPath sqmPath} should be
130
- * dereferenced using the target table mapping, i.e. when the path's lhs is an explicit join.
137
+ * Utility that returns the entity association target's mapping type if the specified {@code sqmPath} should
138
+ * be dereferenced using the target table, i.e. when the path's lhs is an explicit join that is used in the
139
+ * group by clause, or defaults to the provided {@code modelPartContainer} otherwise.
131
140
*/
132
- public static boolean needsTargetTableMapping (SqmPath <?> sqmPath , ModelPartContainer modelPartContainer ) {
133
- return modelPartContainer .getPartMappingType () != modelPartContainer
134
- && sqmPath .getLhs () instanceof SqmFrom <?, ?>
135
- && modelPartContainer .getPartMappingType () instanceof ManagedMappingType ;
141
+ public static ModelPartContainer getTargetMappingIfNeeded (
142
+ SqmPath <?> sqmPath ,
143
+ ModelPartContainer modelPartContainer ,
144
+ SqmToSqlAstConverter sqlAstCreationState ) {
145
+ final SqmQueryPart <?> queryPart = sqlAstCreationState .getCurrentSqmQueryPart ();
146
+ if ( queryPart != null ) {
147
+ // We only need to do this for queries
148
+ final Clause clause = sqlAstCreationState .getCurrentClauseStack ().getCurrent ();
149
+ if ( clause != Clause .FROM && modelPartContainer .getPartMappingType () != modelPartContainer && sqmPath .getLhs () instanceof SqmFrom <?, ?> ) {
150
+ final ModelPart modelPart ;
151
+ if ( modelPartContainer instanceof PluralAttributeMapping ) {
152
+ modelPart = getCollectionPart (
153
+ (PluralAttributeMapping ) modelPartContainer ,
154
+ castNonNull ( sqmPath .getNavigablePath ().getParent () )
155
+ );
156
+ }
157
+ else {
158
+ modelPart = modelPartContainer ;
159
+ }
160
+ if ( modelPart instanceof EntityAssociationMapping ) {
161
+ final EntityAssociationMapping association = (EntityAssociationMapping ) modelPart ;
162
+ // If the path is one of the association's target key properties,
163
+ // we need to render the target side if in group/order by
164
+ if ( association .getTargetKeyPropertyNames ().contains ( sqmPath .getReferencedPathSource ().getPathName () )
165
+ && ( clause == Clause .GROUP || clause == Clause .ORDER
166
+ || !isFkOptimizationAllowed ( sqmPath .getLhs () )
167
+ || queryPart .getFirstQuerySpec ().groupByClauseContains ( sqmPath .getNavigablePath (), sqlAstCreationState )
168
+ || queryPart .getFirstQuerySpec ().orderByClauseContains ( sqmPath .getNavigablePath (), sqlAstCreationState ) ) ) {
169
+ return association .getAssociatedEntityMappingType ();
170
+ }
171
+ }
172
+ }
173
+ }
174
+ return modelPartContainer ;
175
+ }
176
+
177
+ private static CollectionPart getCollectionPart (PluralAttributeMapping attribute , NavigablePath path ) {
178
+ final CollectionPart .Nature nature = CollectionPart .Nature .fromNameExact ( path .getLocalName () );
179
+ if ( nature != null ) {
180
+ switch ( nature ) {
181
+ case ELEMENT :
182
+ return attribute .getElementDescriptor ();
183
+ case INDEX :
184
+ return attribute .getIndexDescriptor ();
185
+ }
186
+ }
187
+ return null ;
136
188
}
137
189
138
190
/**
@@ -156,6 +208,35 @@ public static boolean isFkOptimizationAllowed(SqmPath<?> sqmPath) {
156
208
return false ;
157
209
}
158
210
211
+ public static List <NavigablePath > getGroupByNavigablePaths (SqmQuerySpec <?> querySpec ) {
212
+ final List <SqmExpression <?>> expressions = querySpec .getGroupByClauseExpressions ();
213
+ if ( expressions .isEmpty () ) {
214
+ return Collections .emptyList ();
215
+ }
216
+
217
+ final List <NavigablePath > navigablePaths = new ArrayList <>( expressions .size () );
218
+ final SqmPathVisitor pathVisitor = new SqmPathVisitor ( path -> navigablePaths .add ( path .getNavigablePath () ) );
219
+ for ( SqmExpression <?> expression : expressions ) {
220
+ expression .accept ( pathVisitor );
221
+ }
222
+ return navigablePaths ;
223
+ }
224
+
225
+ public static List <NavigablePath > getOrderByNavigablePaths (SqmQuerySpec <?> querySpec ) {
226
+ final SqmOrderByClause order = querySpec .getOrderByClause ();
227
+ if ( order == null || order .getSortSpecifications ().isEmpty () ) {
228
+ return Collections .emptyList ();
229
+ }
230
+
231
+ final List <SqmSortSpecification > sortSpecifications = order .getSortSpecifications ();
232
+ final List <NavigablePath > navigablePaths = new ArrayList <>( sortSpecifications .size () );
233
+ final SqmPathVisitor pathVisitor = new SqmPathVisitor ( path -> navigablePaths .add ( path .getNavigablePath () ) );
234
+ for ( SqmSortSpecification sortSpec : sortSpecifications ) {
235
+ sortSpec .getSortExpression ().accept ( pathVisitor );
236
+ }
237
+ return navigablePaths ;
238
+ }
239
+
159
240
public static Map <QueryParameterImplementor <?>, Map <SqmParameter <?>, List <JdbcParametersList >>> generateJdbcParamsXref (
160
241
DomainParameterXref domainParameterXref ,
161
242
JdbcParameterBySqmParameterAccess jdbcParameterBySqmParameterAccess ) {
0 commit comments