Skip to content

Commit f0e78f4

Browse files
author
gaohongtao
committed
Merge branch 'StormAll-210'
fixed #210 Routing to single table reomve derived SQL
2 parents ab78772 + 255d422 commit f0e78f4

File tree

4 files changed

+77
-27
lines changed

4 files changed

+77
-27
lines changed

sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parser/result/router/SQLBuilder.java

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
package com.dangdang.ddframe.rdb.sharding.parser.result.router;
1919

2020
import com.google.common.base.Joiner;
21+
import lombok.AccessLevel;
2122
import lombok.Getter;
2223

2324
import java.io.IOException;
24-
import java.util.Collection;
25+
import java.util.ArrayList;
2526
import java.util.HashMap;
26-
import java.util.HashSet;
2727
import java.util.LinkedList;
2828
import java.util.List;
2929
import java.util.Map;
@@ -35,6 +35,8 @@
3535
*/
3636
public class SQLBuilder implements Appendable {
3737

38+
private final List<SQLBuilder> derivedSQLBuilders = new ArrayList<>();
39+
3840
private final List<Object> segments;
3941

4042
private final Map<String, StringToken> tokenMap;
@@ -46,6 +48,11 @@ public class SQLBuilder implements Appendable {
4648
@Getter
4749
private boolean changed;
4850

51+
@Getter(AccessLevel.PRIVATE)
52+
private boolean removeDerivedSQLToken;
53+
54+
private boolean hasExistedDerivedSQLToken;
55+
4956
public SQLBuilder() {
5057
segments = new LinkedList<>();
5158
tokenMap = new HashMap<>();
@@ -83,24 +90,41 @@ public void appendToken(final String label, final String token) {
8390
stringToken.label = label;
8491
stringToken.value = token;
8592
tokenMap.put(label, stringToken);
86-
stringToken.listeners.add(this);
8793
}
8894
stringToken.indices.add(segments.size());
8995
segments.add(stringToken);
9096
currentSegment = new StringBuilder();
9197
segments.add(currentSegment);
9298
}
93-
99+
94100
/**
95101
* 用实际的值替代占位符.
96102
*
97103
* @param label 占位符
98104
* @param token 实际的值
99105
*/
100106
public void buildSQL(final String label, final String token) {
101-
if (tokenMap.containsKey(label)) {
102-
tokenMap.get(label).setValue(token);
107+
buildSQL(label, token, false);
108+
}
109+
110+
/**
111+
* 用实际的值替代占位符,并可以标记该SQL是否为派生SQL.
112+
*
113+
* @param label 占位符
114+
* @param token 实际的值
115+
* @param isDerived 是否是派生的SQL
116+
*/
117+
public void buildSQL(final String label, final String token, final boolean isDerived) {
118+
if (!tokenMap.containsKey(label)) {
119+
return;
120+
}
121+
if (isDerived) {
122+
hasExistedDerivedSQLToken = true;
103123
}
124+
StringToken labelSQL = tokenMap.get(label);
125+
labelSQL.isDerived = isDerived;
126+
labelSQL.value = token;
127+
changeState();
104128
}
105129

106130
/**
@@ -134,9 +158,7 @@ public SQLBuilder buildSQLWithNewToken() {
134158
result.segments.set(index, each);
135159
}
136160
}
137-
for (StringToken each : result.tokenMap.values()) {
138-
each.listeners.add(result);
139-
}
161+
derivedSQLBuilders.add(result);
140162
newTokenList.clear();
141163
return result;
142164
}
@@ -173,15 +195,28 @@ public Appendable append(final char c) throws IOException {
173195
changeState();
174196
return this;
175197
}
176-
198+
177199
private void changeState() {
178200
changed = true;
201+
for (SQLBuilder each : derivedSQLBuilders) {
202+
each.changeState();
203+
}
179204
}
180205

181206
private void clearState() {
182207
changed = false;
183208
}
184209

210+
/**
211+
* 移除衍生的SQL片段.
212+
*/
213+
public void removeDerivedSQL() {
214+
if (hasExistedDerivedSQLToken) {
215+
removeDerivedSQLToken = true;
216+
changeState();
217+
}
218+
}
219+
185220
@Override
186221
public String toString() {
187222
StringBuilder result = new StringBuilder();
@@ -200,29 +235,26 @@ private class StringToken {
200235
private String label;
201236

202237
private String value;
238+
239+
private boolean isDerived;
203240

204241
private final List<Integer> indices = new LinkedList<>();
205242

206-
private final Collection<SQLBuilder> listeners = new HashSet<>();
207-
208-
public void setValue(final String value) {
209-
this.value = value;
210-
for (SQLBuilder each : listeners) {
211-
each.changeState();
212-
}
213-
}
214-
215243
String toToken() {
216-
if (null == value) {
244+
if (isEmptyValueOutput()) {
217245
return "";
218246
}
219247
Joiner joiner = Joiner.on("");
220248
return label.equals(value) ? joiner.join("[Token(", value, ")]") : joiner.join("[", label, "(", value, ")]");
221249
}
222250

251+
private boolean isEmptyValueOutput() {
252+
return null == value || isDerived && isRemoveDerivedSQLToken();
253+
}
254+
223255
@Override
224256
public String toString() {
225-
return null == value ? "" : value;
257+
return isEmptyValueOutput() ? "" : value;
226258
}
227259
}
228260
}

sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/parser/visitor/basic/mysql/MySQLSelectVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ public void endVisit(final MySqlSelectQueryBlock x) {
213213
appendSortableColumn(derivedSelectItems, getParseContext().getParsedResult().getMergeContext().getGroupByColumns());
214214
appendSortableColumn(derivedSelectItems, getParseContext().getParsedResult().getMergeContext().getOrderByColumns());
215215
if (0 != derivedSelectItems.length()) {
216-
getSQLBuilder().buildSQL(getParseContext().getAutoGenTokenKey(), derivedSelectItems.toString());
216+
getSQLBuilder().buildSQL(getParseContext().getAutoGenTokenKey(), derivedSelectItems.toString(), true);
217217
}
218218
super.endVisit(x);
219219
stepOutQuery();

sharding-jdbc-core/src/main/java/com/dangdang/ddframe/rdb/sharding/router/SQLRouteEngine.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.dangdang.ddframe.rdb.sharding.parser.result.SQLParsedResult;
2727
import com.dangdang.ddframe.rdb.sharding.parser.result.merger.Limit;
2828
import com.dangdang.ddframe.rdb.sharding.parser.result.router.ConditionContext;
29+
import com.dangdang.ddframe.rdb.sharding.parser.result.router.SQLBuilder;
2930
import com.dangdang.ddframe.rdb.sharding.parser.result.router.Table;
3031
import com.dangdang.ddframe.rdb.sharding.router.binding.BindingTablesRouter;
3132
import com.dangdang.ddframe.rdb.sharding.router.mixed.MixedTablesRouter;
@@ -93,12 +94,8 @@ SQLRouteResult routeSQL(final SQLParsedResult parsedResult, final List<Object> p
9394
RoutingResult routingResult = routeSQL(each, parsedResult);
9495
result.getExecutionUnits().addAll(routingResult.getSQLExecutionUnits(parsedResult.getRouteContext().getSqlBuilder()));
9596
}
97+
amendSQLAccordingToRouteResult(parsedResult, parameters, result);
9698
MetricsContext.stop(context);
97-
Limit limit = result.getMergeContext().getLimit();
98-
if (null != limit) {
99-
limit.replaceSQL(parsedResult.getRouteContext().getSqlBuilder(), result.getExecutionUnits().size() > 1);
100-
limit.replaceParameters(parameters, result.getExecutionUnits().size() > 1);
101-
}
10299
log.debug("final route result is {} target", result.getExecutionUnits().size());
103100
for (SQLExecutionUnit each : result.getExecutionUnits()) {
104101
log.debug("{}:{} {}", each.getDataSource(), each.getSql(), parameters);
@@ -124,4 +121,17 @@ public String apply(final Table input) {
124121
// TODO 可配置是否执行笛卡尔积
125122
return new MixedTablesRouter(shardingRule, logicTables, conditionContext, parsedResult.getRouteContext().getSqlStatementType()).route();
126123
}
124+
125+
private void amendSQLAccordingToRouteResult(final SQLParsedResult parsedResult, final List<Object> parameters, final SQLRouteResult result) {
126+
boolean isVarious = result.getExecutionUnits().size() > 1;
127+
Limit limit = result.getMergeContext().getLimit();
128+
SQLBuilder sqlBuilder = parsedResult.getRouteContext().getSqlBuilder();
129+
if (null != limit) {
130+
limit.replaceSQL(sqlBuilder, isVarious);
131+
limit.replaceParameters(parameters, isVarious);
132+
}
133+
if (!isVarious) {
134+
sqlBuilder.removeDerivedSQL();
135+
}
136+
}
127137
}

sharding-jdbc-core/src/test/java/com/dangdang/ddframe/rdb/sharding/router/SelectSingleTableTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
import static org.junit.Assert.assertThat;
3030

3131
public final class SelectSingleTableTest extends AbstractDynamicRouteSqlTest {
32+
33+
@Test
34+
public void assertGroupBy() throws SQLParserException {
35+
assertSingleTarget("select sum(qty) from order where order_id = 1 group by tenant_id", "ds_1",
36+
"SELECT SUM(qty) FROM order_1 WHERE order_id = 1 GROUP BY tenant_id");
37+
assertMultipleTargets("select sum(qty) from order group by tenant_id", 4, Arrays.asList("ds_0", "ds_1"),
38+
Arrays.asList("SELECT SUM(qty), tenant_id AS sharding_gen_1 FROM order_0 GROUP BY tenant_id"));
39+
}
3240

3341
@Test
3442
public void assertSingleSelect() throws SQLParserException {

0 commit comments

Comments
 (0)