1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.sharding.route.engine.type;
19
20 import lombok.AccessLevel;
21 import lombok.NoArgsConstructor;
22 import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
23 import org.apache.shardingsphere.infra.binder.context.statement.ddl.CloseStatementContext;
24 import org.apache.shardingsphere.infra.binder.context.type.CursorAvailable;
25 import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
26 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
27 import org.apache.shardingsphere.infra.hint.HintValueContext;
28 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
29 import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
30 import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
31 import org.apache.shardingsphere.infra.session.query.QueryContext;
32 import org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
33 import org.apache.shardingsphere.sharding.route.engine.condition.ShardingConditions;
34 import org.apache.shardingsphere.sharding.route.engine.type.broadcast.ShardingDataSourceGroupBroadcastRoutingEngine;
35 import org.apache.shardingsphere.sharding.route.engine.type.broadcast.ShardingDatabaseBroadcastRoutingEngine;
36 import org.apache.shardingsphere.sharding.route.engine.type.broadcast.ShardingInstanceBroadcastRoutingEngine;
37 import org.apache.shardingsphere.sharding.route.engine.type.broadcast.ShardingTableBroadcastRoutingEngine;
38 import org.apache.shardingsphere.sharding.route.engine.type.complex.ShardingComplexRoutingEngine;
39 import org.apache.shardingsphere.sharding.route.engine.type.ignore.ShardingIgnoreRoutingEngine;
40 import org.apache.shardingsphere.sharding.route.engine.type.standard.ShardingStandardRoutingEngine;
41 import org.apache.shardingsphere.sharding.route.engine.type.unicast.ShardingUnicastRoutingEngine;
42 import org.apache.shardingsphere.sharding.rule.ShardingRule;
43 import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
44 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.AnalyzeTableStatement;
45 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.DALStatement;
46 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.LoadStatement;
47 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.ResetParameterStatement;
48 import org.apache.shardingsphere.sql.parser.sql.common.statement.dal.SetStatement;
49 import org.apache.shardingsphere.sql.parser.sql.common.statement.dcl.DCLStatement;
50 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.AlterFunctionStatement;
51 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.AlterProcedureStatement;
52 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.AlterTablespaceStatement;
53 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.AlterViewStatement;
54 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateFunctionStatement;
55 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateProcedureStatement;
56 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateTablespaceStatement;
57 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.CreateViewStatement;
58 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DDLStatement;
59 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropFunctionStatement;
60 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropProcedureStatement;
61 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropTablespaceStatement;
62 import org.apache.shardingsphere.sql.parser.sql.common.statement.ddl.DropViewStatement;
63 import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DMLStatement;
64 import org.apache.shardingsphere.sql.parser.sql.common.statement.tcl.TCLStatement;
65 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLCreateResourceGroupStatement;
66 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLOptimizeTableStatement;
67 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLSetResourceGroupStatement;
68 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLShowDatabasesStatement;
69 import org.apache.shardingsphere.sql.parser.sql.dialect.statement.mysql.dal.MySQLUseStatement;
70 import org.apache.shardingsphere.sqlfederation.rule.SQLFederationRule;
71
72 import java.util.Collection;
73 import java.util.stream.Collectors;
74
75
76
77
78 @NoArgsConstructor(access = AccessLevel.PRIVATE)
79 public final class ShardingRouteEngineFactory {
80
81
82
83
84
85
86
87
88
89
90
91
92
93 public static ShardingRouteEngine newInstance(final ShardingRule shardingRule, final ShardingSphereDatabase database, final QueryContext queryContext,
94 final ShardingConditions shardingConditions, final ConfigurationProperties props, final ConnectionContext connectionContext,
95 final RuleMetaData globalRuleMetaData) {
96 SQLStatementContext sqlStatementContext = queryContext.getSqlStatementContext();
97 SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
98 if (sqlStatement instanceof TCLStatement) {
99 return new ShardingDatabaseBroadcastRoutingEngine();
100 }
101 if (sqlStatement instanceof DDLStatement) {
102 if (sqlStatementContext instanceof CursorAvailable) {
103 return getCursorRouteEngine(shardingRule, database, sqlStatementContext, queryContext.getHintValueContext(), shardingConditions, props);
104 }
105 return getDDLRoutingEngine(shardingRule, database, sqlStatementContext, connectionContext, globalRuleMetaData);
106 }
107 if (sqlStatement instanceof DALStatement) {
108 return getDALRoutingEngine(shardingRule, database, sqlStatementContext, connectionContext);
109 }
110 if (sqlStatement instanceof DCLStatement) {
111 return getDCLRoutingEngine(shardingRule, database, sqlStatementContext);
112 }
113 return getDQLRoutingEngine(shardingRule, database, sqlStatementContext, queryContext.getHintValueContext(), shardingConditions, props, connectionContext);
114 }
115
116 private static ShardingRouteEngine getDDLRoutingEngine(final ShardingRule shardingRule, final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext,
117 final ConnectionContext connectionContext, final RuleMetaData globalRuleMetaData) {
118 SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
119 boolean functionStatement = sqlStatement instanceof CreateFunctionStatement || sqlStatement instanceof AlterFunctionStatement || sqlStatement instanceof DropFunctionStatement;
120 boolean procedureStatement = sqlStatement instanceof CreateProcedureStatement || sqlStatement instanceof AlterProcedureStatement || sqlStatement instanceof DropProcedureStatement;
121 if (functionStatement || procedureStatement) {
122 return new ShardingDatabaseBroadcastRoutingEngine();
123 }
124 if (sqlStatement instanceof CreateTablespaceStatement || sqlStatement instanceof AlterTablespaceStatement || sqlStatement instanceof DropTablespaceStatement) {
125 return new ShardingInstanceBroadcastRoutingEngine(database.getResourceMetaData());
126 }
127 Collection<String> tableNames = sqlStatementContext instanceof TableAvailable
128 ? ((TableAvailable) sqlStatementContext).getAllTables().stream().map(each -> each.getTableName().getIdentifier().getValue()).collect(Collectors.toSet())
129 : sqlStatementContext.getTablesContext().getTableNames();
130 Collection<String> shardingRuleTableNames = shardingRule.getShardingRuleTableNames(tableNames);
131
132 boolean sqlFederationEnabled = globalRuleMetaData.getSingleRule(SQLFederationRule.class).getConfiguration().isSqlFederationEnabled();
133 if (sqlFederationEnabled && (sqlStatement instanceof CreateViewStatement || sqlStatement instanceof AlterViewStatement || sqlStatement instanceof DropViewStatement)) {
134 return new ShardingUnicastRoutingEngine(sqlStatementContext, shardingRuleTableNames, connectionContext);
135 }
136 if (!tableNames.isEmpty() && shardingRuleTableNames.isEmpty()) {
137 return new ShardingIgnoreRoutingEngine();
138 }
139 return new ShardingTableBroadcastRoutingEngine(database, sqlStatementContext, shardingRuleTableNames);
140 }
141
142 private static ShardingRouteEngine getCursorRouteEngine(final ShardingRule shardingRule, final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext,
143 final HintValueContext hintValueContext, final ShardingConditions shardingConditions, final ConfigurationProperties props) {
144 if (sqlStatementContext instanceof CloseStatementContext && ((CloseStatementContext) sqlStatementContext).getSqlStatement().isCloseAll()) {
145 return new ShardingDatabaseBroadcastRoutingEngine();
146 }
147 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
148 Collection<String> logicTableNames = shardingRule.getShardingLogicTableNames(tableNames);
149 boolean allBindingTables = logicTableNames.size() > 1 && shardingRule.isAllBindingTables(database, sqlStatementContext, logicTableNames);
150 if (isShardingStandardQuery(shardingRule, logicTableNames, allBindingTables)) {
151 return new ShardingStandardRoutingEngine(getLogicTableName(shardingConditions, logicTableNames), shardingConditions, sqlStatementContext, hintValueContext, props);
152 }
153 return new ShardingIgnoreRoutingEngine();
154 }
155
156 private static ShardingRouteEngine getDALRoutingEngine(final ShardingRule shardingRule, final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext,
157 final ConnectionContext connectionContext) {
158 SQLStatement sqlStatement = sqlStatementContext.getSqlStatement();
159 if (sqlStatement instanceof MySQLUseStatement) {
160 return new ShardingIgnoreRoutingEngine();
161 }
162 if (sqlStatement instanceof SetStatement || sqlStatement instanceof ResetParameterStatement
163 || sqlStatement instanceof MySQLShowDatabasesStatement || sqlStatement instanceof LoadStatement) {
164 return new ShardingDatabaseBroadcastRoutingEngine();
165 }
166 if (isResourceGroupStatement(sqlStatement)) {
167 return new ShardingInstanceBroadcastRoutingEngine(database.getResourceMetaData());
168 }
169 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
170 Collection<String> shardingRuleTableNames = shardingRule.getShardingRuleTableNames(tableNames);
171 if (!tableNames.isEmpty() && shardingRuleTableNames.isEmpty()) {
172 return new ShardingIgnoreRoutingEngine();
173 }
174 if (sqlStatement instanceof MySQLOptimizeTableStatement) {
175 return new ShardingTableBroadcastRoutingEngine(database, sqlStatementContext, shardingRuleTableNames);
176 }
177 if (sqlStatement instanceof AnalyzeTableStatement) {
178 return shardingRuleTableNames.isEmpty() ? new ShardingDatabaseBroadcastRoutingEngine()
179 : new ShardingTableBroadcastRoutingEngine(database, sqlStatementContext, shardingRuleTableNames);
180 }
181 if (!shardingRuleTableNames.isEmpty()) {
182 return new ShardingUnicastRoutingEngine(sqlStatementContext, shardingRuleTableNames, connectionContext);
183 }
184 return new ShardingDataSourceGroupBroadcastRoutingEngine();
185 }
186
187 private static boolean isResourceGroupStatement(final SQLStatement sqlStatement) {
188
189 return sqlStatement instanceof MySQLCreateResourceGroupStatement || sqlStatement instanceof MySQLSetResourceGroupStatement;
190 }
191
192 private static ShardingRouteEngine getDCLRoutingEngine(final ShardingRule shardingRule, final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext) {
193 if (isDCLForSingleTable(sqlStatementContext)) {
194 Collection<String> shardingRuleTableNames = shardingRule.getShardingRuleTableNames(sqlStatementContext.getTablesContext().getTableNames());
195 return shardingRuleTableNames.isEmpty() ? new ShardingIgnoreRoutingEngine() : new ShardingTableBroadcastRoutingEngine(database, sqlStatementContext, shardingRuleTableNames);
196 }
197 return new ShardingInstanceBroadcastRoutingEngine(database.getResourceMetaData());
198 }
199
200 private static boolean isDCLForSingleTable(final SQLStatementContext sqlStatementContext) {
201 if (sqlStatementContext instanceof TableAvailable) {
202 TableAvailable tableSegmentsAvailable = (TableAvailable) sqlStatementContext;
203 return 1 == tableSegmentsAvailable.getAllTables().size() && !"*".equals(tableSegmentsAvailable.getAllTables().iterator().next().getTableName().getIdentifier().getValue());
204 }
205 return false;
206 }
207
208 private static ShardingRouteEngine getDQLRoutingEngine(final ShardingRule shardingRule, final ShardingSphereDatabase database, final SQLStatementContext sqlStatementContext,
209 final HintValueContext hintValueContext, final ShardingConditions shardingConditions, final ConfigurationProperties props,
210 final ConnectionContext connectionContext) {
211 Collection<String> tableNames = sqlStatementContext.getTablesContext().getTableNames();
212 if (sqlStatementContext.getSqlStatement() instanceof DMLStatement && shardingConditions.isAlwaysFalse() || tableNames.isEmpty()) {
213 return new ShardingUnicastRoutingEngine(sqlStatementContext, tableNames, connectionContext);
214 }
215 Collection<String> shardingLogicTableNames = shardingRule.getShardingLogicTableNames(tableNames);
216 if (shardingLogicTableNames.isEmpty()) {
217 return new ShardingIgnoreRoutingEngine();
218 }
219 return getDQLRouteEngineForShardingTable(shardingRule, database, sqlStatementContext, hintValueContext, shardingConditions, props, shardingLogicTableNames);
220 }
221
222 private static ShardingRouteEngine getDQLRouteEngineForShardingTable(final ShardingRule shardingRule, final ShardingSphereDatabase database,
223 final SQLStatementContext sqlStatementContext, final HintValueContext hintValueContext,
224 final ShardingConditions shardingConditions, final ConfigurationProperties props, final Collection<String> tableNames) {
225 boolean allBindingTables = tableNames.size() > 1 && shardingRule.isAllBindingTables(database, sqlStatementContext, tableNames);
226 if (isShardingStandardQuery(shardingRule, tableNames, allBindingTables)) {
227 return new ShardingStandardRoutingEngine(getLogicTableName(shardingConditions, tableNames), shardingConditions, sqlStatementContext, hintValueContext, props);
228 }
229
230 return new ShardingComplexRoutingEngine(shardingConditions, sqlStatementContext, hintValueContext, props, tableNames);
231 }
232
233 private static String getLogicTableName(final ShardingConditions shardingConditions, final Collection<String> tableNames) {
234 if (shardingConditions.getConditions().isEmpty()) {
235 return tableNames.iterator().next();
236 }
237 ShardingCondition shardingCondition = shardingConditions.getConditions().iterator().next();
238 return shardingCondition.getValues().isEmpty() ? tableNames.iterator().next() : shardingCondition.getValues().iterator().next().getTableName();
239 }
240
241 private static boolean isShardingStandardQuery(final ShardingRule shardingRule, final Collection<String> tableNames, final boolean allBindingTables) {
242 return 1 == tableNames.size() && shardingRule.isAllShardingTables(tableNames) || allBindingTables;
243 }
244 }