View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.shardingsphere.sharding.route.engine;
19  
20  import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
21  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
22  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
23  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
24  import org.apache.shardingsphere.infra.route.context.RouteContext;
25  import org.apache.shardingsphere.infra.route.lifecycle.EntranceSQLRouter;
26  import org.apache.shardingsphere.infra.session.query.QueryContext;
27  import org.apache.shardingsphere.sharding.cache.route.CachedShardingSQLRouter;
28  import org.apache.shardingsphere.sharding.constant.ShardingOrder;
29  import org.apache.shardingsphere.sharding.route.engine.checker.ShardingRouteContextCheckerFactory;
30  import org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
31  import org.apache.shardingsphere.sharding.route.engine.condition.ShardingConditions;
32  import org.apache.shardingsphere.sharding.route.engine.condition.engine.ShardingConditionEngine;
33  import org.apache.shardingsphere.sharding.route.engine.type.ShardingRouteEngineFactory;
34  import org.apache.shardingsphere.sharding.rule.ShardingRule;
35  import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
36  import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.CursorSQLStatementAttribute;
37  import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DMLStatement;
38  
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.List;
42  import java.util.Optional;
43  
44  /**
45   * Sharding SQL router.
46   */
47  @HighFrequencyInvocation
48  public final class ShardingSQLRouter implements EntranceSQLRouter<ShardingRule> {
49      
50      @Override
51      public RouteContext createRouteContext(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database,
52                                             final ShardingRule rule, final Collection<String> tableNames, final ConfigurationProperties props) {
53          if (rule.isShardingCacheEnabled()) {
54              Optional<RouteContext> result = new CachedShardingSQLRouter()
55                      .loadRouteContext(this::createRouteContext0, queryContext, globalRuleMetaData, database, rule.getShardingCache(), tableNames, props);
56              if (result.isPresent()) {
57                  return result.get();
58              }
59          }
60          return createRouteContext0(queryContext, globalRuleMetaData, database, rule, tableNames, props);
61      }
62      
63      private RouteContext createRouteContext0(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database, final ShardingRule rule,
64                                               final Collection<String> tableNames, final ConfigurationProperties props) {
65          Collection<String> logicTableNames = rule.getShardingLogicTableNames(tableNames);
66          if (logicTableNames.isEmpty()) {
67              return new RouteContext();
68          }
69          SQLStatement sqlStatement = queryContext.getSqlStatementContext().getSqlStatement();
70          ShardingConditions shardingConditions = createShardingConditions(queryContext, globalRuleMetaData, database, rule);
71          if (sqlStatement instanceof DMLStatement && shardingConditions.isNeedMerge()) {
72              shardingConditions.merge();
73          }
74          RouteContext result = ShardingRouteEngineFactory.newInstance(rule, database, queryContext, shardingConditions, logicTableNames, props).route(rule);
75          checkRouteContext(queryContext, database, rule, props, sqlStatement, shardingConditions, result);
76          return result;
77      }
78      
79      private ShardingConditions createShardingConditions(final QueryContext queryContext,
80                                                          final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database, final ShardingRule rule) {
81          List<ShardingCondition> shardingConditions;
82          if (queryContext.getSqlStatementContext().getSqlStatement() instanceof DMLStatement
83                  || queryContext.getSqlStatementContext().getSqlStatement().getAttributes().findAttribute(CursorSQLStatementAttribute.class).isPresent()) {
84              shardingConditions = new ShardingConditionEngine(globalRuleMetaData, database, rule).createShardingConditions(queryContext.getSqlStatementContext(), queryContext.getParameters());
85          } else {
86              shardingConditions = Collections.emptyList();
87          }
88          return new ShardingConditions(shardingConditions, queryContext.getSqlStatementContext(), rule);
89      }
90      
91      private void checkRouteContext(final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingRule rule, final ConfigurationProperties props,
92                                     final SQLStatement sqlStatement, final ShardingConditions shardingConditions, final RouteContext routeContext) {
93          ShardingRouteContextCheckerFactory.newInstance(sqlStatement, shardingConditions).ifPresent(optional -> optional.check(rule, queryContext, database, props, routeContext));
94      }
95      
96      @Override
97      public Type getType() {
98          return Type.DATA_NODE;
99      }
100     
101     @Override
102     public int getOrder() {
103         return ShardingOrder.ORDER;
104     }
105     
106     @Override
107     public Class<ShardingRule> getTypeClass() {
108         return ShardingRule.class;
109     }
110 }