|
55 | 55 | import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
56 | 56 | import org.hibernate.query.sqm.tree.from.SqmFrom;
|
57 | 57 | import org.hibernate.query.sqm.tree.from.SqmJoin;
|
| 58 | +import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin; |
58 | 59 | import org.hibernate.query.sqm.tree.from.SqmRoot;
|
59 | 60 | import org.hibernate.query.sqm.tree.select.SqmQueryPart;
|
60 | 61 | import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
|
@@ -127,27 +128,62 @@ public static IllegalQueryOperationException expectingNonSelect(SqmStatement<?>
|
127 | 128 | );
|
128 | 129 | }
|
129 | 130 |
|
| 131 | + /** |
| 132 | + * Utility that returns {@code true} if the specified {@link SqmPath sqmPath} has to be |
| 133 | + * dereferenced using the target table mapping, and does not support fk optimization. |
| 134 | + * <p> |
| 135 | + * This is the case when the path is used in both the {@linkplain Clause#GROUP group by} clause |
| 136 | + * and a clause which {@linkplain #isClauseDependantOnGroupBy depends on it} or when the left |
| 137 | + * hand side of the path is a {@linkplain #isNonOptimizableJoin non-optimizable join}. |
| 138 | + */ |
130 | 139 | public static boolean needsTargetTableMapping(
|
131 | 140 | SqmPath<?> sqmPath,
|
132 | 141 | ModelPartContainer modelPartContainer,
|
133 | 142 | SqmToSqlAstConverter sqlAstCreationState) {
|
134 |
| - final Clause currentClause = sqlAstCreationState.getCurrentClauseStack().getCurrent(); |
135 |
| - return ( currentClause == Clause.GROUP || currentClause == Clause.SELECT || currentClause == Clause.ORDER || currentClause == Clause.HAVING ) |
136 |
| - && modelPartContainer.getPartMappingType() != modelPartContainer |
| 143 | + return modelPartContainer.getPartMappingType() != modelPartContainer |
137 | 144 | && sqmPath.getLhs() instanceof SqmFrom<?, ?>
|
138 | 145 | && modelPartContainer.getPartMappingType() instanceof ManagedMappingType
|
139 |
| - && ( groupByClauseContains( sqlAstCreationState.getCurrentSqmQueryPart(), sqmPath.getNavigablePath() ) |
| 146 | + && ( groupByClauseContains( sqlAstCreationState, sqmPath.getNavigablePath() ) |
140 | 147 | || isNonOptimizableJoin( sqmPath.getLhs() ) );
|
141 | 148 | }
|
142 | 149 |
|
143 |
| - private static boolean groupByClauseContains(SqmQueryPart<?> sqmQueryPart, NavigablePath path) { |
144 |
| - return sqmQueryPart.isSimpleQueryPart() && sqmQueryPart.getFirstQuerySpec().groupByClauseContains( path ); |
| 150 | + private static boolean groupByClauseContains(SqmToSqlAstConverter sqlAstCreationState, NavigablePath path) { |
| 151 | + if ( isClauseDependantOnGroupBy( sqlAstCreationState.getCurrentClauseStack().getCurrent() ) ) { |
| 152 | + final SqmQueryPart<?> sqmQueryPart = sqlAstCreationState.getCurrentSqmQueryPart(); |
| 153 | + return sqmQueryPart.isSimpleQueryPart() && sqmQueryPart.getFirstQuerySpec().groupByClauseContains( path ); |
| 154 | + } |
| 155 | + return false; |
| 156 | + } |
| 157 | + |
| 158 | + private static boolean isClauseDependantOnGroupBy(Clause clause) { |
| 159 | + switch ( clause ) { |
| 160 | + case SELECT: |
| 161 | + case GROUP: |
| 162 | + case ORDER: |
| 163 | + case HAVING: |
| 164 | + return true; |
| 165 | + default: |
| 166 | + return false; |
| 167 | + } |
145 | 168 | }
|
146 | 169 |
|
147 |
| - private static boolean isNonOptimizableJoin(SqmPath<?> sqmPath) { |
| 170 | + /** |
| 171 | + * Utility that returns {@code true} when the provided {@link SqmPath sqmPath} is |
| 172 | + * a join that cannot be dereferenced through the foreign key on the associated table, |
| 173 | + * i.e. a join that's neither {@linkplain SqmJoinType#INNER} nor {@linkplain SqmJoinType#LEFT} |
| 174 | + * or one that has an explicit on clause predicate. |
| 175 | + */ |
| 176 | + public static boolean isNonOptimizableJoin(SqmPath<?> sqmPath) { |
148 | 177 | if ( sqmPath instanceof SqmJoin<?, ?> ) {
|
149 |
| - final SqmJoinType sqmJoinType = ( (SqmJoin<?, ?>) sqmPath ).getSqmJoinType(); |
150 |
| - return sqmJoinType != SqmJoinType.INNER && sqmJoinType != SqmJoinType.LEFT; |
| 178 | + final SqmJoin<?, ?> sqmJoin = (SqmJoin<?, ?>) sqmPath; |
| 179 | + switch ( sqmJoin.getSqmJoinType() ) { |
| 180 | + case INNER: |
| 181 | + case LEFT: |
| 182 | + return sqmJoin instanceof SqmQualifiedJoin<?, ?> |
| 183 | + && ( (SqmQualifiedJoin<?, ?>) sqmJoin ).getJoinPredicate() != null; |
| 184 | + default: |
| 185 | + return true; |
| 186 | + } |
151 | 187 | }
|
152 | 188 | return false;
|
153 | 189 | }
|
|
0 commit comments