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.binder.context.type.CursorAvailable;
22  import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
23  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
24  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
25  import org.apache.shardingsphere.infra.route.SQLRouter;
26  import org.apache.shardingsphere.infra.route.context.RouteContext;
27  import org.apache.shardingsphere.infra.session.connection.ConnectionContext;
28  import org.apache.shardingsphere.infra.session.query.QueryContext;
29  import org.apache.shardingsphere.sharding.cache.route.CachedShardingSQLRouter;
30  import org.apache.shardingsphere.sharding.constant.ShardingOrder;
31  import org.apache.shardingsphere.sharding.route.engine.condition.ShardingCondition;
32  import org.apache.shardingsphere.sharding.route.engine.condition.ShardingConditions;
33  import org.apache.shardingsphere.sharding.route.engine.condition.engine.ShardingConditionEngine;
34  import org.apache.shardingsphere.sharding.route.engine.type.ShardingRouteEngineFactory;
35  import org.apache.shardingsphere.sharding.route.engine.validator.ShardingStatementValidator;
36  import org.apache.shardingsphere.sharding.route.engine.validator.ShardingStatementValidatorFactory;
37  import org.apache.shardingsphere.sharding.rule.ShardingRule;
38  import org.apache.shardingsphere.sql.parser.sql.common.statement.SQLStatement;
39  import org.apache.shardingsphere.sql.parser.sql.common.statement.dml.DMLStatement;
40  
41  import java.util.Collections;
42  import java.util.List;
43  import java.util.Optional;
44  
45  /**
46   * Sharding SQL router.
47   */
48  @HighFrequencyInvocation
49  public final class ShardingSQLRouter implements SQLRouter<ShardingRule> {
50      
51      @Override
52      public RouteContext createRouteContext(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database, final ShardingRule rule,
53                                             final ConfigurationProperties props, final ConnectionContext connectionContext) {
54          if (rule.isShardingCacheEnabled()) {
55              Optional<RouteContext> result = new CachedShardingSQLRouter()
56                      .loadRouteContext(this::createRouteContext0, queryContext, globalRuleMetaData, database, rule.getShardingCache(), props, connectionContext);
57              if (result.isPresent()) {
58                  return result.get();
59              }
60          }
61          return createRouteContext0(queryContext, globalRuleMetaData, database, rule, props, connectionContext);
62      }
63      
64      private RouteContext createRouteContext0(final QueryContext queryContext, final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database, final ShardingRule rule,
65                                               final ConfigurationProperties props, final ConnectionContext connectionContext) {
66          SQLStatement sqlStatement = queryContext.getSqlStatementContext().getSqlStatement();
67          ShardingConditions shardingConditions = createShardingConditions(queryContext, globalRuleMetaData, database, rule);
68          Optional<ShardingStatementValidator> validator = ShardingStatementValidatorFactory.newInstance(sqlStatement, shardingConditions, globalRuleMetaData);
69          validator.ifPresent(optional -> optional.preValidate(rule, queryContext.getSqlStatementContext(), queryContext.getParameters(), database, props));
70          if (sqlStatement instanceof DMLStatement && shardingConditions.isNeedMerge()) {
71              shardingConditions.merge();
72          }
73          RouteContext result = ShardingRouteEngineFactory.newInstance(rule, database, queryContext, shardingConditions, props, connectionContext, globalRuleMetaData).route(rule);
74          validator.ifPresent(optional -> optional.postValidate(rule, queryContext.getSqlStatementContext(), queryContext.getHintValueContext(), queryContext.getParameters(), database, props, result));
75          return result;
76      }
77      
78      private ShardingConditions createShardingConditions(final QueryContext queryContext,
79                                                          final RuleMetaData globalRuleMetaData, final ShardingSphereDatabase database, final ShardingRule rule) {
80          List<ShardingCondition> shardingConditions;
81          if (queryContext.getSqlStatementContext().getSqlStatement() instanceof DMLStatement || queryContext.getSqlStatementContext() instanceof CursorAvailable) {
82              shardingConditions = new ShardingConditionEngine(globalRuleMetaData, database, rule).createShardingConditions(queryContext.getSqlStatementContext(), queryContext.getParameters());
83          } else {
84              shardingConditions = Collections.emptyList();
85          }
86          return new ShardingConditions(shardingConditions, queryContext.getSqlStatementContext(), rule);
87      }
88      
89      @Override
90      public void decorateRouteContext(final RouteContext routeContext, final QueryContext queryContext, final ShardingSphereDatabase database, final ShardingRule rule,
91                                       final ConfigurationProperties props, final ConnectionContext connectionContext) {
92          // TODO
93      }
94      
95      @Override
96      public int getOrder() {
97          return ShardingOrder.ORDER;
98      }
99      
100     @Override
101     public Class<ShardingRule> getTypeClass() {
102         return ShardingRule.class;
103     }
104 }