Skip to content

Commit 4b2b79f

Browse files
committed
Give the exists renderer access to table aliases from the outer query
1 parent 128ffb7 commit 4b2b79f

File tree

5 files changed

+143
-40
lines changed

5 files changed

+143
-40
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2016-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.render;
17+
18+
import org.mybatis.dynamic.sql.SqlTable;
19+
20+
import java.util.Objects;
21+
import java.util.Optional;
22+
23+
public class TableAliasCalculatorWithParent implements TableAliasCalculator {
24+
private final TableAliasCalculator parent;
25+
private final TableAliasCalculator child;
26+
27+
public TableAliasCalculatorWithParent(TableAliasCalculator parent, TableAliasCalculator child) {
28+
this.parent = Objects.requireNonNull(parent);
29+
this.child = Objects.requireNonNull(child);
30+
}
31+
32+
@Override
33+
public Optional<String> aliasForColumn(SqlTable table) {
34+
Optional<String> answer = child.aliasForColumn(table);
35+
if (answer.isPresent()) {
36+
return answer;
37+
}
38+
return parent.aliasForColumn(table);
39+
}
40+
41+
@Override
42+
public Optional<String> aliasForTable(SqlTable table) {
43+
Optional<String> answer = child.aliasForTable(table);
44+
if (answer.isPresent()) {
45+
return answer;
46+
}
47+
return parent.aliasForTable(table);
48+
}
49+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2016-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.mybatis.dynamic.sql.select.render;
17+
18+
import org.mybatis.dynamic.sql.render.RenderingStrategy;
19+
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
20+
21+
import java.util.concurrent.atomic.AtomicInteger;
22+
23+
public abstract class AbstractQueryRendererBuilder<T extends AbstractQueryRendererBuilder<T>> {
24+
RenderingStrategy renderingStrategy;
25+
AtomicInteger sequence;
26+
TableAliasCalculator parentTableAliasCalculator;
27+
28+
public T withRenderingStrategy(RenderingStrategy renderingStrategy) {
29+
this.renderingStrategy = renderingStrategy;
30+
return getThis();
31+
}
32+
33+
public T withSequence(AtomicInteger sequence) {
34+
this.sequence = sequence;
35+
return getThis();
36+
}
37+
38+
public T withParentTableAliasCalculator(TableAliasCalculator parentTableAliasCalculator) {
39+
this.parentTableAliasCalculator = parentTableAliasCalculator;
40+
return getThis();
41+
}
42+
43+
abstract T getThis();
44+
}

src/main/java/org/mybatis/dynamic/sql/select/render/QueryExpressionRenderer.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.mybatis.dynamic.sql.render.GuaranteedTableAliasCalculator;
3030
import org.mybatis.dynamic.sql.render.RenderingStrategy;
3131
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
32+
import org.mybatis.dynamic.sql.render.TableAliasCalculatorWithParent;
3233
import org.mybatis.dynamic.sql.select.GroupByModel;
3334
import org.mybatis.dynamic.sql.select.QueryExpressionModel;
3435
import org.mybatis.dynamic.sql.select.join.JoinModel;
@@ -49,25 +50,45 @@ private QueryExpressionRenderer(Builder builder) {
4950
queryExpression = Objects.requireNonNull(builder.queryExpression);
5051
renderingStrategy = Objects.requireNonNull(builder.renderingStrategy);
5152
sequence = Objects.requireNonNull(builder.sequence);
52-
tableAliasCalculator = determineJoinTableAliasCalculator(queryExpression);
53+
tableAliasCalculator = calculateTableAliasCalculator(queryExpression, builder.parentTableAliasCalculator);
5354
tableExpressionRenderer = new TableExpressionRenderer.Builder()
5455
.withTableAliasCalculator(tableAliasCalculator)
5556
.withRenderingStrategy(renderingStrategy)
5657
.withSequence(sequence)
5758
.build();
5859
}
5960

60-
private TableAliasCalculator determineJoinTableAliasCalculator(QueryExpressionModel queryExpression) {
61-
return queryExpression.joinModel().map(JoinModel::containsSubQueries).map(containsSubQueries -> {
62-
if (containsSubQueries) {
63-
// if there are subQueries, then force explicit qualifiers
64-
return ExplicitTableAliasCalculator.of(queryExpression.tableAliases());
65-
} else {
66-
// there are joins, but no sub-queries. In this case, we can use the
67-
// table names as qualifiers without requiring explicit qualifiers
68-
return GuaranteedTableAliasCalculator.of(queryExpression.tableAliases());
69-
}
70-
}).orElseGet(() -> ExplicitTableAliasCalculator.of(queryExpression.tableAliases()));
61+
private TableAliasCalculator calculateTableAliasCalculator(QueryExpressionModel queryExpression,
62+
TableAliasCalculator parentTableAliasCalculator) {
63+
TableAliasCalculator baseTableAliasCalculator = queryExpression.joinModel()
64+
.map(JoinModel::containsSubQueries)
65+
.map(this::calculateTableAliasCalculatorWithJoins)
66+
.orElseGet(this::explicitTableAliasCalculator);
67+
68+
if (parentTableAliasCalculator == null) {
69+
return baseTableAliasCalculator;
70+
} else {
71+
return new TableAliasCalculatorWithParent(parentTableAliasCalculator, baseTableAliasCalculator);
72+
}
73+
}
74+
75+
private TableAliasCalculator calculateTableAliasCalculatorWithJoins(boolean hasSubQueries) {
76+
if (hasSubQueries) {
77+
// if there are subqueries, we cannot use the table name automatically
78+
// so all aliases must be specified
79+
return explicitTableAliasCalculator();
80+
} else {
81+
// without subqueries, we can automatically use table names as aliases
82+
return guaranteedTableAliasCalculator();
83+
}
84+
}
85+
86+
private TableAliasCalculator explicitTableAliasCalculator() {
87+
return ExplicitTableAliasCalculator.of(queryExpression.tableAliases());
88+
}
89+
90+
private TableAliasCalculator guaranteedTableAliasCalculator() {
91+
return GuaranteedTableAliasCalculator.of(queryExpression.tableAliases());
7192
}
7293

7394
public FragmentAndParameters render() {
@@ -157,23 +178,15 @@ public static Builder withQueryExpression(QueryExpressionModel model) {
157178
return new Builder().withQueryExpression(model);
158179
}
159180

160-
public static class Builder {
181+
public static class Builder extends AbstractQueryRendererBuilder<Builder> {
161182
private QueryExpressionModel queryExpression;
162-
private RenderingStrategy renderingStrategy;
163-
private AtomicInteger sequence;
164183

165184
public Builder withQueryExpression(QueryExpressionModel queryExpression) {
166185
this.queryExpression = queryExpression;
167186
return this;
168187
}
169188

170-
public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
171-
this.renderingStrategy = renderingStrategy;
172-
return this;
173-
}
174-
175-
public Builder withSequence(AtomicInteger sequence) {
176-
this.sequence = sequence;
189+
Builder getThis() {
177190
return this;
178191
}
179192

src/main/java/org/mybatis/dynamic/sql/select/render/SelectRenderer.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2020 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
2222

2323
import org.mybatis.dynamic.sql.SortSpecification;
2424
import org.mybatis.dynamic.sql.render.RenderingStrategy;
25+
import org.mybatis.dynamic.sql.render.TableAliasCalculator;
2526
import org.mybatis.dynamic.sql.select.OrderByModel;
2627
import org.mybatis.dynamic.sql.select.PagingModel;
2728
import org.mybatis.dynamic.sql.select.QueryExpressionModel;
@@ -34,11 +35,17 @@ public class SelectRenderer {
3435
private final SelectModel selectModel;
3536
private final RenderingStrategy renderingStrategy;
3637
private final AtomicInteger sequence;
38+
private final TableAliasCalculator parentTableAliasCalculator; // may be null
3739

3840
private SelectRenderer(Builder builder) {
3941
selectModel = Objects.requireNonNull(builder.selectModel);
4042
renderingStrategy = Objects.requireNonNull(builder.renderingStrategy);
41-
sequence = builder.sequence().orElseGet(() -> new AtomicInteger(1));
43+
if(builder.sequence == null) {
44+
sequence = new AtomicInteger(1);
45+
} else {
46+
sequence = builder.sequence;
47+
}
48+
parentTableAliasCalculator = builder.parentTableAliasCalculator;
4249
}
4350

4451
public SelectStatementProvider render() {
@@ -59,6 +66,7 @@ private FragmentAndParameters renderQueryExpression(QueryExpressionModel queryEx
5966
return QueryExpressionRenderer.withQueryExpression(queryExpressionModel)
6067
.withRenderingStrategy(renderingStrategy)
6168
.withSequence(sequence)
69+
.withParentTableAliasCalculator(parentTableAliasCalculator)
6270
.build()
6371
.render();
6472
}
@@ -99,32 +107,20 @@ public static Builder withSelectModel(SelectModel selectModel) {
99107
return new Builder().withSelectModel(selectModel);
100108
}
101109

102-
public static class Builder {
110+
public static class Builder extends AbstractQueryRendererBuilder<Builder> {
103111
private SelectModel selectModel;
104-
private RenderingStrategy renderingStrategy;
105-
private AtomicInteger sequence;
106112

107113
public Builder withSelectModel(SelectModel selectModel) {
108114
this.selectModel = selectModel;
109115
return this;
110116
}
111117

112-
public Builder withRenderingStrategy(RenderingStrategy renderingStrategy) {
113-
this.renderingStrategy = renderingStrategy;
114-
return this;
118+
public SelectRenderer build() {
119+
return new SelectRenderer(this);
115120
}
116121

117-
public Builder withSequence(AtomicInteger sequence) {
118-
this.sequence = sequence;
122+
Builder getThis() {
119123
return this;
120124
}
121-
122-
private Optional<AtomicInteger> sequence() {
123-
return Optional.ofNullable(sequence);
124-
}
125-
126-
public SelectRenderer build() {
127-
return new SelectRenderer(this);
128-
}
129125
}
130126
}

src/main/java/org/mybatis/dynamic/sql/where/render/CriterionRenderer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ private FragmentAndParameters renderExists(ExistsCriterion criterion) {
127127
.withSelectModel(existsPredicate.selectModelBuilder().build())
128128
.withRenderingStrategy(renderingStrategy)
129129
.withSequence(sequence)
130+
.withParentTableAliasCalculator(tableAliasCalculator)
130131
.build()
131132
.render();
132133

0 commit comments

Comments
 (0)