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