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.rule;
19  
20  import com.cedarsoftware.util.CaseInsensitiveMap;
21  import com.cedarsoftware.util.CaseInsensitiveSet;
22  import com.google.common.base.Splitter;
23  import com.google.common.base.Strings;
24  import lombok.Getter;
25  import org.apache.shardingsphere.infra.algorithm.core.context.AlgorithmSQLContext;
26  import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
27  import org.apache.shardingsphere.infra.algorithm.keygen.core.KeyGenerateAlgorithm;
28  import org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
29  import org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
30  import org.apache.shardingsphere.infra.datanode.DataNode;
31  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
32  import org.apache.shardingsphere.infra.expr.core.InlineExpressionParserFactory;
33  import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContext;
34  import org.apache.shardingsphere.infra.instance.ComputeNodeInstanceContextAware;
35  import org.apache.shardingsphere.infra.metadata.database.resource.PhysicalDataSourceAggregator;
36  import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData;
37  import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
38  import org.apache.shardingsphere.infra.rule.attribute.RuleAttributes;
39  import org.apache.shardingsphere.infra.rule.attribute.datasource.aggregate.AggregatedDataSourceRuleAttribute;
40  import org.apache.shardingsphere.infra.rule.scope.DatabaseRule;
41  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
42  import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
43  import org.apache.shardingsphere.sharding.api.config.rule.ShardingAutoTableRuleConfiguration;
44  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
45  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
46  import org.apache.shardingsphere.sharding.api.config.strategy.audit.ShardingAuditStrategyConfiguration;
47  import org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
48  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ComplexShardingStrategyConfiguration;
49  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.NoneShardingStrategyConfiguration;
50  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
51  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
52  import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
53  import org.apache.shardingsphere.sharding.cache.ShardingCache;
54  import org.apache.shardingsphere.sharding.constant.ShardingOrder;
55  import org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
56  import org.apache.shardingsphere.sharding.rule.attribute.ShardingDataNodeRuleAttribute;
57  import org.apache.shardingsphere.sharding.rule.attribute.ShardingTableNamesRuleAttribute;
58  import org.apache.shardingsphere.sharding.rule.checker.ShardingRuleChecker;
59  import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
60  import org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm;
61  import org.apache.shardingsphere.sql.parser.statement.core.extractor.ExpressionExtractor;
62  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
63  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
64  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
65  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.AndPredicate;
66  import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.predicate.WhereSegment;
67  
68  import javax.sql.DataSource;
69  import java.util.Collection;
70  import java.util.Collections;
71  import java.util.HashSet;
72  import java.util.LinkedHashMap;
73  import java.util.LinkedHashSet;
74  import java.util.LinkedList;
75  import java.util.List;
76  import java.util.Map;
77  import java.util.Objects;
78  import java.util.Optional;
79  import java.util.function.Function;
80  import java.util.stream.Collectors;
81  
82  /**
83   * Sharding rule.
84   */
85  @Getter
86  public final class ShardingRule implements DatabaseRule {
87      
88      private final ShardingRuleConfiguration configuration;
89      
90      private final Collection<String> dataSourceNames;
91      
92      private final Map<String, ShardingAlgorithm> shardingAlgorithms = new CaseInsensitiveMap<>();
93      
94      private final Map<String, KeyGenerateAlgorithm> keyGenerators = new CaseInsensitiveMap<>();
95      
96      private final Map<String, ShardingAuditAlgorithm> auditors = new CaseInsensitiveMap<>();
97      
98      private final Map<String, ShardingTable> shardingTables = new CaseInsensitiveMap<>();
99      
100     private final Map<String, BindingTableRule> bindingTableRules = new CaseInsensitiveMap<>();
101     
102     private final ShardingStrategyConfiguration defaultDatabaseShardingStrategyConfig;
103     
104     private final ShardingStrategyConfiguration defaultTableShardingStrategyConfig;
105     
106     private final ShardingAuditStrategyConfiguration defaultAuditStrategy;
107     
108     private final KeyGenerateAlgorithm defaultKeyGenerateAlgorithm;
109     
110     private final String defaultShardingColumn;
111     
112     private final ShardingCache shardingCache;
113     
114     private final RuleAttributes attributes;
115     
116     private final ShardingRuleChecker shardingRuleChecker = new ShardingRuleChecker(this);
117     
118     public ShardingRule(final ShardingRuleConfiguration ruleConfig, final Map<String, DataSource> dataSources, final ComputeNodeInstanceContext computeNodeInstanceContext,
119                         final Collection<ShardingSphereRule> builtRules) {
120         configuration = ruleConfig;
121         dataSourceNames = getDataSourceNames(ruleConfig.getTables(), ruleConfig.getAutoTables(), dataSources.keySet());
122         ruleConfig.getShardingAlgorithms().forEach((key, value) -> shardingAlgorithms.put(key, TypedSPILoader.getService(ShardingAlgorithm.class, value.getType(), value.getProps())));
123         ruleConfig.getKeyGenerators().forEach((key, value) -> keyGenerators.put(key, TypedSPILoader.getService(KeyGenerateAlgorithm.class, value.getType(), value.getProps())));
124         ruleConfig.getAuditors().forEach((key, value) -> auditors.put(key, TypedSPILoader.getService(ShardingAuditAlgorithm.class, value.getType(), value.getProps())));
125         shardingTables.putAll(createShardingTables(ruleConfig.getTables(), ruleConfig.getDefaultKeyGenerateStrategy()));
126         shardingTables.putAll(createShardingAutoTables(ruleConfig.getAutoTables(), ruleConfig.getDefaultKeyGenerateStrategy()));
127         bindingTableRules.putAll(createBindingTableRules(ruleConfig.getBindingTableGroups()));
128         defaultDatabaseShardingStrategyConfig = createDefaultDatabaseShardingStrategyConfiguration(ruleConfig);
129         defaultTableShardingStrategyConfig = createDefaultTableShardingStrategyConfiguration(ruleConfig);
130         defaultAuditStrategy = null == ruleConfig.getDefaultAuditStrategy() ? new ShardingAuditStrategyConfiguration(Collections.emptyList(), true) : ruleConfig.getDefaultAuditStrategy();
131         defaultKeyGenerateAlgorithm = null == ruleConfig.getDefaultKeyGenerateStrategy()
132                 ? TypedSPILoader.getService(KeyGenerateAlgorithm.class, null)
133                 : keyGenerators.get(ruleConfig.getDefaultKeyGenerateStrategy().getKeyGeneratorName());
134         defaultShardingColumn = ruleConfig.getDefaultShardingColumn();
135         keyGenerators.values().stream().filter(ComputeNodeInstanceContextAware.class::isInstance)
136                 .forEach(each -> ((ComputeNodeInstanceContextAware) each).setComputeNodeInstanceContext(computeNodeInstanceContext));
137         if (defaultKeyGenerateAlgorithm instanceof ComputeNodeInstanceContextAware && -1 == computeNodeInstanceContext.getWorkerId()) {
138             ((ComputeNodeInstanceContextAware) defaultKeyGenerateAlgorithm).setComputeNodeInstanceContext(computeNodeInstanceContext);
139         }
140         shardingCache = null == ruleConfig.getShardingCache() ? null : new ShardingCache(ruleConfig.getShardingCache(), this);
141         // TODO check sharding rule configuration according to aggregated data sources
142         Map<String, DataSource> aggregatedDataSources = new RuleMetaData(builtRules).findAttribute(AggregatedDataSourceRuleAttribute.class)
143                 .map(AggregatedDataSourceRuleAttribute::getAggregatedDataSources).orElseGet(() -> PhysicalDataSourceAggregator.getAggregatedDataSources(dataSources, builtRules));
144         attributes = new RuleAttributes(new ShardingDataNodeRuleAttribute(shardingTables), new ShardingTableNamesRuleAttribute(shardingTables.values()),
145                 new AggregatedDataSourceRuleAttribute(aggregatedDataSources));
146         shardingRuleChecker.check(ruleConfig);
147     }
148     
149     private ShardingStrategyConfiguration createDefaultDatabaseShardingStrategyConfiguration(final ShardingRuleConfiguration ruleConfig) {
150         Optional.ofNullable(ruleConfig.getDefaultDatabaseShardingStrategy()).ifPresent(optional -> checkManualShardingAlgorithm(optional.getShardingAlgorithmName(), "default"));
151         return null == ruleConfig.getDefaultDatabaseShardingStrategy() ? new NoneShardingStrategyConfiguration() : ruleConfig.getDefaultDatabaseShardingStrategy();
152     }
153     
154     private ShardingStrategyConfiguration createDefaultTableShardingStrategyConfiguration(final ShardingRuleConfiguration ruleConfig) {
155         Optional.ofNullable(ruleConfig.getDefaultTableShardingStrategy()).ifPresent(optional -> checkManualShardingAlgorithm(optional.getShardingAlgorithmName(), "default"));
156         return null == ruleConfig.getDefaultTableShardingStrategy() ? new NoneShardingStrategyConfiguration() : ruleConfig.getDefaultTableShardingStrategy();
157     }
158     
159     private Collection<String> getDataSourceNames(final Collection<ShardingTableRuleConfiguration> tableRuleConfigs,
160                                                   final Collection<ShardingAutoTableRuleConfiguration> autoTableRuleConfigs, final Collection<String> dataSourceNames) {
161         if (tableRuleConfigs.isEmpty() && autoTableRuleConfigs.isEmpty()) {
162             return dataSourceNames;
163         }
164         if (tableRuleConfigs.stream().map(ShardingTableRuleConfiguration::getActualDataNodes).anyMatch(each -> null == each || each.isEmpty())) {
165             return dataSourceNames;
166         }
167         Collection<String> result = new LinkedHashSet<>();
168         tableRuleConfigs.forEach(each -> result.addAll(getDataSourceNames(each)));
169         autoTableRuleConfigs.forEach(each -> result.addAll(getDataSourceNames(each)));
170         return result;
171     }
172     
173     private Collection<String> getDataSourceNames(final ShardingAutoTableRuleConfiguration shardingAutoTableRuleConfig) {
174         List<String> actualDataSources = InlineExpressionParserFactory.newInstance(shardingAutoTableRuleConfig.getActualDataSources()).splitAndEvaluate();
175         return new HashSet<>(actualDataSources);
176     }
177     
178     private Collection<String> getDataSourceNames(final ShardingTableRuleConfiguration shardingTableRuleConfig) {
179         List<String> actualDataNodes = InlineExpressionParserFactory.newInstance(shardingTableRuleConfig.getActualDataNodes()).splitAndEvaluate();
180         return actualDataNodes.stream().map(each -> new DataNode(each).getDataSourceName()).collect(Collectors.toList());
181     }
182     
183     private Map<String, ShardingTable> createShardingTables(final Collection<ShardingTableRuleConfiguration> tableRuleConfigs,
184                                                             final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig) {
185         return tableRuleConfigs.stream().map(each -> createShardingTable(each, defaultKeyGenerateStrategyConfig))
186                 .collect(Collectors.toMap(ShardingTable::getLogicTable, Function.identity(), (oldValue, currentValue) -> oldValue, CaseInsensitiveMap::new));
187     }
188     
189     private ShardingTable createShardingTable(final ShardingTableRuleConfiguration tableRuleConfig, final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig) {
190         Optional.ofNullable(tableRuleConfig.getDatabaseShardingStrategy()).ifPresent(optional -> checkManualShardingAlgorithm(optional.getShardingAlgorithmName(), tableRuleConfig.getLogicTable()));
191         Optional.ofNullable(tableRuleConfig.getTableShardingStrategy()).ifPresent(optional -> checkManualShardingAlgorithm(optional.getShardingAlgorithmName(), tableRuleConfig.getLogicTable()));
192         return new ShardingTable(tableRuleConfig, dataSourceNames, getDefaultGenerateKeyColumn(defaultKeyGenerateStrategyConfig));
193     }
194     
195     private void checkManualShardingAlgorithm(final String shardingAlgorithmName, final String logicTable) {
196         ShardingAlgorithm shardingAlgorithm = shardingAlgorithms.get(shardingAlgorithmName);
197         ShardingSpherePreconditions.checkState(!(shardingAlgorithm instanceof ShardingAutoTableAlgorithm),
198                 () -> new AlgorithmInitializationException(shardingAlgorithm, "`%s` tables sharding configuration can not use auto sharding algorithm.", logicTable));
199     }
200     
201     private Map<String, ShardingTable> createShardingAutoTables(final Collection<ShardingAutoTableRuleConfiguration> autoTableRuleConfigs,
202                                                                 final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig) {
203         return autoTableRuleConfigs.stream().map(each -> createShardingAutoTable(defaultKeyGenerateStrategyConfig, each))
204                 .collect(Collectors.toMap(ShardingTable::getLogicTable, Function.identity(), (oldValue, currentValue) -> oldValue, CaseInsensitiveMap::new));
205     }
206     
207     private ShardingTable createShardingAutoTable(final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig, final ShardingAutoTableRuleConfiguration autoTableRuleConfig) {
208         checkAutoShardingAlgorithm(autoTableRuleConfig.getShardingStrategy().getShardingAlgorithmName(), autoTableRuleConfig.getLogicTable());
209         ShardingAlgorithm shardingAlgorithm = shardingAlgorithms.get(autoTableRuleConfig.getShardingStrategy().getShardingAlgorithmName());
210         return new ShardingTable(autoTableRuleConfig, dataSourceNames, (ShardingAutoTableAlgorithm) shardingAlgorithm, getDefaultGenerateKeyColumn(defaultKeyGenerateStrategyConfig));
211     }
212     
213     private void checkAutoShardingAlgorithm(final String shardingAlgorithmName, final String logicTable) {
214         ShardingAlgorithm shardingAlgorithm = shardingAlgorithms.get(shardingAlgorithmName);
215         ShardingSpherePreconditions.checkState(shardingAlgorithm instanceof ShardingAutoTableAlgorithm,
216                 () -> new AlgorithmInitializationException(shardingAlgorithm, "`%s` autoTables sharding configuration must use auto sharding algorithm.", logicTable));
217     }
218     
219     private String getDefaultGenerateKeyColumn(final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig) {
220         return Optional.ofNullable(defaultKeyGenerateStrategyConfig).map(KeyGenerateStrategyConfiguration::getColumn).orElse(null);
221     }
222     
223     private Map<String, BindingTableRule> createBindingTableRules(final Collection<ShardingTableReferenceRuleConfiguration> bindingTableGroups) {
224         Map<String, BindingTableRule> result = new LinkedHashMap<>();
225         for (ShardingTableReferenceRuleConfiguration each : bindingTableGroups) {
226             BindingTableRule bindingTableRule = createBindingTableRule(each.getReference());
227             for (String logicTable : bindingTableRule.getAllLogicTables()) {
228                 result.put(logicTable, bindingTableRule);
229             }
230         }
231         return result;
232     }
233     
234     private BindingTableRule createBindingTableRule(final String bindingTableGroup) {
235         Map<String, ShardingTable> shardingTables = Splitter.on(",").trimResults().splitToList(bindingTableGroup).stream()
236                 .map(this::getShardingTable).collect(Collectors.toMap(ShardingTable::getLogicTable, Function.identity(), (oldValue, currentValue) -> oldValue, LinkedHashMap::new));
237         BindingTableRule result = new BindingTableRule();
238         result.getShardingTables().putAll(shardingTables);
239         return result;
240     }
241     
242     /**
243      * Get database sharding strategy configuration.
244      *
245      * @param shardingTable sharding table
246      * @return database sharding strategy configuration
247      */
248     public ShardingStrategyConfiguration getDatabaseShardingStrategyConfiguration(final ShardingTable shardingTable) {
249         return getDatabaseShardingStrategyConfiguration(shardingTable, defaultDatabaseShardingStrategyConfig);
250     }
251     
252     private ShardingStrategyConfiguration getDatabaseShardingStrategyConfiguration(final ShardingTable shardingTable, final ShardingStrategyConfiguration defaultDatabaseShardingStrategyConfig) {
253         return null == shardingTable.getDatabaseShardingStrategyConfig() ? defaultDatabaseShardingStrategyConfig : shardingTable.getDatabaseShardingStrategyConfig();
254     }
255     
256     /**
257      * Get table sharding strategy configuration.
258      *
259      * @param shardingTable sharding table
260      * @return table sharding strategy configuration
261      */
262     public ShardingStrategyConfiguration getTableShardingStrategyConfiguration(final ShardingTable shardingTable) {
263         return getTableShardingStrategyConfiguration(shardingTable, defaultTableShardingStrategyConfig);
264     }
265     
266     private ShardingStrategyConfiguration getTableShardingStrategyConfiguration(final ShardingTable shardingTable, final ShardingStrategyConfiguration defaultTableShardingStrategyConfig) {
267         return null == shardingTable.getTableShardingStrategyConfig() ? defaultTableShardingStrategyConfig : shardingTable.getTableShardingStrategyConfig();
268     }
269     
270     /**
271      * Get audit strategy configuration.
272      *
273      * @param shardingTable sharding table
274      * @return audit strategy configuration
275      */
276     public ShardingAuditStrategyConfiguration getAuditStrategyConfiguration(final ShardingTable shardingTable) {
277         return null == shardingTable.getAuditStrategyConfig() ? defaultAuditStrategy : shardingTable.getAuditStrategyConfig();
278     }
279     
280     /**
281      * Find sharding table.
282      *
283      * @param logicTableName logic table name
284      * @return sharding table
285      */
286     public Optional<ShardingTable> findShardingTable(final String logicTableName) {
287         if (Strings.isNullOrEmpty(logicTableName) || !shardingTables.containsKey(logicTableName)) {
288             return Optional.empty();
289         }
290         return Optional.of(shardingTables.get(logicTableName));
291     }
292     
293     /**
294      * Find sharding table via actual table name.
295      *
296      * @param actualTableName actual table name
297      * @return sharding table
298      */
299     public Optional<ShardingTable> findShardingTableByActualTable(final String actualTableName) {
300         for (ShardingTable each : shardingTables.values()) {
301             if (each.isExisted(actualTableName)) {
302                 return Optional.of(each);
303             }
304         }
305         return Optional.empty();
306     }
307     
308     /**
309      * Get sharding table.
310      *
311      * @param logicTableName logic table name
312      * @return sharding table
313      * @throws ShardingTableRuleNotFoundException sharding table rule not found exception
314      */
315     public ShardingTable getShardingTable(final String logicTableName) {
316         return findShardingTable(logicTableName).orElseThrow(() -> new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName)));
317     }
318     
319     /**
320      * Judge whether logic table is all config binding tables or not.
321      *
322      * @param logicTableNames logic table names
323      * @return whether logic table is all config binding tables or not
324      */
325     public boolean isAllConfigBindingTables(final Collection<String> logicTableNames) {
326         if (logicTableNames.isEmpty()) {
327             return false;
328         }
329         Optional<BindingTableRule> bindingTableRule = findBindingTableRule(logicTableNames);
330         if (!bindingTableRule.isPresent()) {
331             return false;
332         }
333         Collection<String> result = new CaseInsensitiveSet<>(bindingTableRule.get().getAllLogicTables());
334         return !result.isEmpty() && result.containsAll(logicTableNames);
335     }
336     
337     /**
338      * Judge whether logic table is all config binding tables and use sharding columns join.
339      *
340      * @param sqlStatementContext sqlStatementContext
341      * @param logicTableNames logic table names
342      * @return whether logic table is all config binding tables and use sharding columns join
343      */
344     public boolean isBindingTablesUseShardingColumnsJoin(final SQLStatementContext sqlStatementContext, final Collection<String> logicTableNames) {
345         if (!(sqlStatementContext instanceof SelectStatementContext && ((SelectStatementContext) sqlStatementContext).isContainsJoinQuery())) {
346             return isAllConfigBindingTables(logicTableNames);
347         }
348         if (!isAllConfigBindingTables(logicTableNames)) {
349             return false;
350         }
351         SelectStatementContext select = (SelectStatementContext) sqlStatementContext;
352         return isJoinConditionContainsShardingColumns(logicTableNames, select.getWhereSegments());
353     }
354     
355     private Optional<BindingTableRule> findBindingTableRule(final Collection<String> logicTableNames) {
356         for (String each : logicTableNames) {
357             Optional<BindingTableRule> result = findBindingTableRule(each);
358             if (result.isPresent()) {
359                 return result;
360             }
361         }
362         return Optional.empty();
363     }
364     
365     /**
366      * Find binding table rule via logic table name.
367      *
368      * @param logicTableName logic table name
369      * @return binding table rule
370      */
371     public Optional<BindingTableRule> findBindingTableRule(final String logicTableName) {
372         return Optional.ofNullable(bindingTableRules.get(logicTableName));
373     }
374     
375     /**
376      * Judge whether logic table is all sharding table or not.
377      *
378      * @param logicTableNames logic table names
379      * @return whether logic table is all sharding table or not
380      */
381     public boolean isAllShardingTables(final Collection<String> logicTableNames) {
382         if (logicTableNames.isEmpty()) {
383             return false;
384         }
385         for (String each : logicTableNames) {
386             if (!isShardingTable(each)) {
387                 return false;
388             }
389         }
390         return true;
391     }
392     
393     /**
394      * Judge whether logic table is sharding table or not.
395      *
396      * @param logicTableName logic table name
397      * @return whether logic table is sharding table or not
398      */
399     public boolean isShardingTable(final String logicTableName) {
400         return shardingTables.containsKey(logicTableName);
401     }
402     
403     /**
404      * Judge whether all tables are in same data source or not.
405      *
406      * @param logicTableNames logic table names
407      * @return whether all tables are in same data source or not
408      */
409     public boolean isAllTablesInSameDataSource(final Collection<String> logicTableNames) {
410         Collection<String> dataSourceNames = logicTableNames.stream().map(shardingTables::get)
411                 .filter(Objects::nonNull).flatMap(each -> each.getActualDataSourceNames().stream()).collect(Collectors.toSet());
412         return 1 == dataSourceNames.size();
413     }
414     
415     /**
416      * Judge whether contains sharding table or not.
417      *
418      * @param logicTableNames logic table names
419      * @return whether contains sharding table or not
420      */
421     public boolean containsShardingTable(final Collection<String> logicTableNames) {
422         for (String each : logicTableNames) {
423             if (isShardingTable(each)) {
424                 return true;
425             }
426         }
427         return false;
428     }
429     
430     /**
431      * Find sharding column.
432      *
433      * @param columnName column name
434      * @param tableName table name
435      * @return sharding column
436      */
437     public Optional<String> findShardingColumn(final String columnName, final String tableName) {
438         return Optional.ofNullable(shardingTables.get(tableName)).flatMap(optional -> findShardingColumn(optional, columnName));
439     }
440     
441     private Optional<String> findShardingColumn(final ShardingTable shardingTable, final String columnName) {
442         Optional<String> databaseShardingColumn = findShardingColumn(getDatabaseShardingStrategyConfiguration(shardingTable), columnName);
443         if (databaseShardingColumn.isPresent()) {
444             return databaseShardingColumn;
445         }
446         return findShardingColumn(getTableShardingStrategyConfiguration(shardingTable), columnName);
447     }
448     
449     private Optional<String> findShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String columnName) {
450         if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
451             String shardingColumn = null == ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn()
452                     ? defaultShardingColumn
453                     : ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
454             return shardingColumn.equalsIgnoreCase(columnName) ? Optional.of(shardingColumn) : Optional.empty();
455         }
456         if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
457             List<String> shardingColumns = Splitter.on(",").trimResults().splitToList(((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns());
458             for (String each : shardingColumns) {
459                 if (each.equalsIgnoreCase(columnName)) {
460                     return Optional.of(each);
461                 }
462             }
463         }
464         return Optional.empty();
465     }
466     
467     /**
468      * Judge whether given logic table column is key generated column or not.
469      *
470      * @param columnName column name
471      * @param tableName table name
472      * @return whether given logic table column is key generated column or not
473      */
474     public boolean isGenerateKeyColumn(final String columnName, final String tableName) {
475         return Optional.ofNullable(shardingTables.get(tableName)).filter(each -> isGenerateKeyColumn(each, columnName)).isPresent();
476     }
477     
478     private boolean isGenerateKeyColumn(final ShardingTable shardingTable, final String columnName) {
479         Optional<String> generateKeyColumn = shardingTable.getGenerateKeyColumn();
480         return generateKeyColumn.isPresent() && generateKeyColumn.get().equalsIgnoreCase(columnName);
481     }
482     
483     /**
484      * Find column name of generated key.
485      *
486      * @param logicTableName logic table name
487      * @return column name of generated key
488      */
489     public Optional<String> findGenerateKeyColumnName(final String logicTableName) {
490         return Optional.ofNullable(shardingTables.get(logicTableName)).filter(each -> each.getGenerateKeyColumn().isPresent()).flatMap(ShardingTable::getGenerateKeyColumn);
491     }
492     
493     /**
494      * Find the generated keys of logic table.
495      *
496      * @param algorithmSQLContext key generate context 
497      * @param keyGenerateCount key generate count
498      * @return generated keys
499      */
500     public Collection<? extends Comparable<?>> generateKeys(final AlgorithmSQLContext algorithmSQLContext, final int keyGenerateCount) {
501         return getKeyGenerateAlgorithm(algorithmSQLContext.getTableName()).generateKeys(algorithmSQLContext, keyGenerateCount);
502     }
503     
504     /**
505      * Judge whether support auto increment or not.
506      *
507      * @param logicTableName logic table name
508      * @return whether support auto increment or not
509      */
510     public boolean isSupportAutoIncrement(final String logicTableName) {
511         return getKeyGenerateAlgorithm(logicTableName).isSupportAutoIncrement();
512     }
513     
514     private KeyGenerateAlgorithm getKeyGenerateAlgorithm(final String logicTableName) {
515         ShardingTable shardingTable = getShardingTable(logicTableName);
516         return null == shardingTable.getKeyGeneratorName() ? defaultKeyGenerateAlgorithm : keyGenerators.get(shardingTable.getKeyGeneratorName());
517     }
518     
519     /**
520      * Find data node by logic table name.
521      *
522      * @param logicTableName logic table name
523      * @return data node
524      */
525     public DataNode getDataNode(final String logicTableName) {
526         ShardingTable shardingTable = getShardingTable(logicTableName);
527         return shardingTable.getActualDataNodes().get(0);
528     }
529     
530     /**
531      * Get sharding logic table names.
532      *
533      * @param logicTableNames logic table names
534      * @return sharding logic table names
535      */
536     public Collection<String> getShardingLogicTableNames(final Collection<String> logicTableNames) {
537         Collection<String> result = new LinkedList<>();
538         for (String each : logicTableNames) {
539             if (isShardingTable(each)) {
540                 result.add(each);
541             }
542         }
543         return result;
544     }
545     
546     /**
547      * Get logic and actual binding tables.
548      *
549      * @param dataSourceName data source name
550      * @param logicTable logic table name
551      * @param actualTable actual table name
552      * @param availableLogicBindingTables available logic binding table names
553      * @return logic and actual binding tables
554      */
555     public Map<String, String> getLogicAndActualTablesFromBindingTable(final String dataSourceName,
556                                                                        final String logicTable, final String actualTable, final Collection<String> availableLogicBindingTables) {
557         return findBindingTableRule(logicTable).map(optional -> optional.getLogicAndActualTables(dataSourceName, logicTable, actualTable, availableLogicBindingTables))
558                 .orElseGet(Collections::emptyMap);
559     }
560     
561     /**
562      * Is sharding cache enabled.
563      *
564      * @return is sharding cache enabled
565      */
566     public boolean isShardingCacheEnabled() {
567         return null != shardingCache;
568     }
569     
570     private boolean isJoinConditionContainsShardingColumns(final Collection<String> tableNames, final Collection<WhereSegment> whereSegments) {
571         Collection<String> databaseJoinConditionTables = new CaseInsensitiveSet<>(tableNames.size(), 1F);
572         Collection<String> tableJoinConditionTables = new CaseInsensitiveSet<>(tableNames.size(), 1F);
573         for (WhereSegment each : whereSegments) {
574             Collection<AndPredicate> andPredicates = ExpressionExtractor.extractAndPredicates(each.getExpr());
575             if (andPredicates.size() > 1) {
576                 return false;
577             }
578             for (AndPredicate andPredicate : andPredicates) {
579                 databaseJoinConditionTables.addAll(getJoinConditionTables(andPredicate.getPredicates(), true));
580                 tableJoinConditionTables.addAll(getJoinConditionTables(andPredicate.getPredicates(), false));
581             }
582         }
583         ShardingTable shardingTable = getShardingTable(tableNames.iterator().next());
584         boolean containsDatabaseShardingColumns = !(getDatabaseShardingStrategyConfiguration(shardingTable) instanceof StandardShardingStrategyConfiguration)
585                 || databaseJoinConditionTables.containsAll(tableNames);
586         boolean containsTableShardingColumns =
587                 !(getTableShardingStrategyConfiguration(shardingTable) instanceof StandardShardingStrategyConfiguration) || tableJoinConditionTables.containsAll(tableNames);
588         return containsDatabaseShardingColumns && containsTableShardingColumns;
589     }
590     
591     private Collection<String> getJoinConditionTables(final Collection<ExpressionSegment> predicates, final boolean isDatabaseJoinCondition) {
592         Collection<String> result = new LinkedList<>();
593         for (ExpressionSegment each : predicates) {
594             if (!isJoinConditionExpression(each)) {
595                 continue;
596             }
597             ColumnSegment leftColumn = (ColumnSegment) ((BinaryOperationExpression) each).getLeft();
598             ColumnSegment rightColumn = (ColumnSegment) ((BinaryOperationExpression) each).getRight();
599             Optional<ShardingTable> leftShardingTable = findShardingTable(leftColumn.getColumnBoundInfo().getOriginalTable().getValue());
600             Optional<ShardingTable> rightShardingTable = findShardingTable(rightColumn.getColumnBoundInfo().getOriginalTable().getValue());
601             if (!leftShardingTable.isPresent() || !rightShardingTable.isPresent()) {
602                 continue;
603             }
604             ShardingStrategyConfiguration leftConfig =
605                     isDatabaseJoinCondition ? getDatabaseShardingStrategyConfiguration(leftShardingTable.get()) : getTableShardingStrategyConfiguration(leftShardingTable.get());
606             ShardingStrategyConfiguration rightConfig =
607                     isDatabaseJoinCondition ? getDatabaseShardingStrategyConfiguration(rightShardingTable.get()) : getTableShardingStrategyConfiguration(rightShardingTable.get());
608             if (findShardingColumn(leftConfig, leftColumn.getIdentifier().getValue()).isPresent() && findShardingColumn(rightConfig, rightColumn.getIdentifier().getValue()).isPresent()) {
609                 result.add(leftColumn.getColumnBoundInfo().getOriginalTable().getValue());
610                 result.add(rightColumn.getColumnBoundInfo().getOriginalTable().getValue());
611             }
612         }
613         return result;
614     }
615     
616     private boolean isJoinConditionExpression(final ExpressionSegment expression) {
617         if (!(expression instanceof BinaryOperationExpression)) {
618             return false;
619         }
620         BinaryOperationExpression binaryExpression = (BinaryOperationExpression) expression;
621         return binaryExpression.getLeft() instanceof ColumnSegment && binaryExpression.getRight() instanceof ColumnSegment && "=".equals(binaryExpression.getOperator());
622     }
623     
624     @Override
625     public int getOrder() {
626         return ShardingOrder.ORDER;
627     }
628 }