1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.single.route.engine;
19
20 import lombok.RequiredArgsConstructor;
21 import org.apache.shardingsphere.infra.exception.dialect.exception.syntax.table.TableExistsException;
22 import org.apache.shardingsphere.infra.datanode.DataNode;
23 import org.apache.shardingsphere.infra.metadata.database.schema.QualifiedTable;
24 import org.apache.shardingsphere.infra.route.context.RouteContext;
25 import org.apache.shardingsphere.infra.route.context.RouteMapper;
26 import org.apache.shardingsphere.infra.route.context.RouteUnit;
27 import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
28 import org.apache.shardingsphere.infra.exception.generic.UnsupportedSQLOperationException;
29 import org.apache.shardingsphere.infra.rule.attribute.datanode.MutableDataNodeRuleAttribute;
30 import org.apache.shardingsphere.single.exception.SingleTableNotFoundException;
31 import org.apache.shardingsphere.single.rule.SingleRule;
32 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
33 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateTableStatement;
34 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DDLStatement;
35 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.SelectStatement;
36 import org.apache.shardingsphere.sql.parser.sql.dialect.handler.ddl.CreateTableStatementHandler;
37
38 import java.util.Collection;
39 import java.util.Collections;
40 import java.util.LinkedList;
41 import java.util.Map;
42 import java.util.Map.Entry;
43 import java.util.Optional;
44 import java.util.function.Function;
45 import java.util.stream.Collectors;
46
47
48
49
50 @RequiredArgsConstructor
51 public final class SingleStandardRouteEngine implements SingleRouteEngine {
52
53 private final Collection<QualifiedTable> singleTables;
54
55 private final SQLStatement sqlStatement;
56
57 @Override
58 public void route(final RouteContext routeContext, final SingleRule singleRule) {
59 if (routeContext.getRouteUnits().isEmpty() || sqlStatement instanceof SelectStatement) {
60 routeStatement(routeContext, singleRule);
61 } else {
62 RouteContext newRouteContext = new RouteContext();
63 routeStatement(newRouteContext, singleRule);
64 combineRouteContext(routeContext, newRouteContext);
65 }
66 }
67
68 private void routeStatement(final RouteContext routeContext, final SingleRule rule) {
69 if (sqlStatement instanceof DDLStatement) {
70 routeDDLStatement(routeContext, rule);
71 } else {
72 boolean allTablesInSameComputeNode = rule.isAllTablesInSameComputeNode(getDataNodes(routeContext), singleTables);
73 ShardingSpherePreconditions.checkState(allTablesInSameComputeNode, () -> new UnsupportedSQLOperationException("all tables must be in the same compute node"));
74 fillRouteContext(rule, routeContext, singleTables);
75 }
76 }
77
78 private Collection<DataNode> getDataNodes(final RouteContext routeContext) {
79 Collection<DataNode> result = new LinkedList<>();
80 for (Collection<DataNode> each : routeContext.getOriginalDataNodes()) {
81 result.addAll(each);
82 }
83 return result;
84 }
85
86 private void routeDDLStatement(final RouteContext routeContext, final SingleRule rule) {
87 if (sqlStatement instanceof CreateTableStatement) {
88 QualifiedTable table = singleTables.iterator().next();
89 Optional<DataNode> dataNode = rule.getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).findTableDataNode(table.getSchemaName(), table.getTableName());
90 boolean containsIfNotExists = CreateTableStatementHandler.ifNotExists((CreateTableStatement) sqlStatement);
91 if (dataNode.isPresent() && containsIfNotExists) {
92 String dataSourceName = dataNode.map(DataNode::getDataSourceName).orElse(null);
93 routeContext.getRouteUnits().add(new RouteUnit(new RouteMapper(dataSourceName, dataSourceName), Collections.singleton(new RouteMapper(table.getTableName(), table.getTableName()))));
94 } else if (dataNode.isPresent()) {
95 throw new TableExistsException(table.getTableName());
96 } else {
97 String dataSourceName = rule.assignNewDataSourceName();
98 routeContext.getRouteUnits().add(new RouteUnit(new RouteMapper(dataSourceName, dataSourceName), Collections.singleton(new RouteMapper(table.getTableName(), table.getTableName()))));
99 }
100 } else {
101 fillRouteContext(rule, routeContext, singleTables);
102 }
103 }
104
105 private void fillRouteContext(final SingleRule singleRule, final RouteContext routeContext, final Collection<QualifiedTable> logicTables) {
106 for (QualifiedTable each : logicTables) {
107 String tableName = each.getTableName();
108 Optional<DataNode> dataNode = singleRule.getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).findTableDataNode(each.getSchemaName(), tableName);
109 ShardingSpherePreconditions.checkState(dataNode.isPresent(), () -> new SingleTableNotFoundException(tableName));
110 String dataSource = dataNode.get().getDataSourceName();
111 routeContext.putRouteUnit(new RouteMapper(dataSource, dataSource), Collections.singletonList(new RouteMapper(tableName, tableName)));
112 }
113 }
114
115 private void combineRouteContext(final RouteContext routeContext, final RouteContext newRouteContext) {
116 Map<String, RouteUnit> dataSourceRouteUnits = getDataSourceRouteUnits(newRouteContext);
117 routeContext.getRouteUnits().removeIf(each -> !dataSourceRouteUnits.containsKey(each.getDataSourceMapper().getLogicName()));
118 for (Entry<String, RouteUnit> entry : dataSourceRouteUnits.entrySet()) {
119 routeContext.putRouteUnit(entry.getValue().getDataSourceMapper(), entry.getValue().getTableMappers());
120 }
121 }
122
123 private Map<String, RouteUnit> getDataSourceRouteUnits(final RouteContext newRouteContext) {
124 return newRouteContext.getRouteUnits().stream().collect(Collectors.toMap(each -> each.getDataSourceMapper().getLogicName(), Function.identity()));
125 }
126 }