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.distsql.handler.checker;
19  
20  import com.cedarsoftware.util.CaseInsensitiveSet;
21  import com.google.common.base.Splitter;
22  import lombok.AccessLevel;
23  import lombok.NoArgsConstructor;
24  import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
25  import org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
26  import org.apache.shardingsphere.infra.algorithm.core.exception.InvalidAlgorithmConfigurationException;
27  import org.apache.shardingsphere.infra.algorithm.keygen.core.KeyGenerateAlgorithm;
28  import org.apache.shardingsphere.infra.datanode.DataNode;
29  import org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
30  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.DuplicateRuleException;
31  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
32  import org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
33  import org.apache.shardingsphere.infra.exception.kernel.metadata.resource.storageunit.MissingRequiredStorageUnitsException;
34  import org.apache.shardingsphere.infra.expr.core.InlineExpressionParserFactory;
35  import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
36  import org.apache.shardingsphere.infra.rule.attribute.datasource.DataSourceMapperRuleAttribute;
37  import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
38  import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
39  import org.apache.shardingsphere.sharding.api.config.rule.ShardingAutoTableRuleConfiguration;
40  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableReferenceRuleConfiguration;
41  import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
42  import org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
43  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ComplexShardingStrategyConfiguration;
44  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.NoneShardingStrategyConfiguration;
45  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
46  import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
47  import org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
48  import org.apache.shardingsphere.sharding.distsql.handler.converter.ShardingTableRuleStatementConverter;
49  import org.apache.shardingsphere.sharding.distsql.handler.enums.ShardingStrategyType;
50  import org.apache.shardingsphere.sharding.distsql.segment.strategy.AuditStrategySegment;
51  import org.apache.shardingsphere.sharding.distsql.segment.strategy.KeyGenerateStrategySegment;
52  import org.apache.shardingsphere.sharding.distsql.segment.strategy.ShardingAuditorSegment;
53  import org.apache.shardingsphere.sharding.distsql.segment.strategy.ShardingStrategySegment;
54  import org.apache.shardingsphere.sharding.distsql.segment.table.AbstractTableRuleSegment;
55  import org.apache.shardingsphere.sharding.distsql.segment.table.AutoTableRuleSegment;
56  import org.apache.shardingsphere.sharding.distsql.segment.table.TableRuleSegment;
57  import org.apache.shardingsphere.sharding.exception.algorithm.ShardingAlgorithmClassImplementationException;
58  import org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
59  import org.apache.shardingsphere.sharding.exception.strategy.InvalidShardingStrategyConfigurationException;
60  import org.apache.shardingsphere.sharding.rule.BindingTableCheckedConfiguration;
61  import org.apache.shardingsphere.sharding.rule.ShardingTable;
62  import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
63  import org.apache.shardingsphere.sharding.spi.ShardingAuditAlgorithm;
64  
65  import java.util.Collection;
66  import java.util.Collections;
67  import java.util.HashMap;
68  import java.util.HashSet;
69  import java.util.Iterator;
70  import java.util.LinkedHashMap;
71  import java.util.LinkedHashSet;
72  import java.util.LinkedList;
73  import java.util.Map;
74  import java.util.Map.Entry;
75  import java.util.Objects;
76  import java.util.Optional;
77  import java.util.Set;
78  import java.util.function.Function;
79  import java.util.stream.Collectors;
80  
81  /**
82   * Sharding table rule checker.
83   */
84  @NoArgsConstructor(access = AccessLevel.PRIVATE)
85  public final class ShardingTableRuleStatementChecker {
86      
87      private static final String DELIMITER = ".";
88      
89      /**
90       * Check create sharing table rule statement.
91       *
92       * @param database database
93       * @param rules rules
94       * @param ifNotExists if not exists
95       * @param currentRuleConfig current rule configuration
96       */
97      public static void checkCreation(final ShardingSphereDatabase database, final Collection<AbstractTableRuleSegment> rules, final boolean ifNotExists,
98                                       final ShardingRuleConfiguration currentRuleConfig) {
99          check(database, rules, ifNotExists, currentRuleConfig, true);
100     }
101     
102     /**
103      * Check alter sharing table rule statement.
104      *
105      * @param database database
106      * @param rules rules
107      * @param currentRuleConfig current rule configuration
108      */
109     public static void checkAlteration(final ShardingSphereDatabase database, final Collection<AbstractTableRuleSegment> rules, final ShardingRuleConfiguration currentRuleConfig) {
110         check(database, rules, false, currentRuleConfig, false);
111     }
112     
113     /**
114      * Judge whether binding table groups are valid.
115      *
116      * @param bindingTableGroups binding table groups
117      * @param currentRuleConfig current rule configuration
118      * @return binding table groups are valid or not
119      */
120     public static boolean isValidBindingTableGroups(final Collection<ShardingTableReferenceRuleConfiguration> bindingTableGroups, final ShardingRuleConfiguration currentRuleConfig) {
121         ShardingRuleConfiguration toBeCheckedRuleConfig = createToBeCheckedShardingRuleConfiguration(currentRuleConfig);
122         toBeCheckedRuleConfig.setBindingTableGroups(bindingTableGroups);
123         Collection<String> dataSourceNames = getRequiredDataSources(toBeCheckedRuleConfig);
124         dataSourceNames.addAll(getRequiredDataSources(currentRuleConfig));
125         return check(toBeCheckedRuleConfig, dataSourceNames);
126     }
127     
128     private static ShardingRuleConfiguration createToBeCheckedShardingRuleConfiguration(final ShardingRuleConfiguration currentRuleConfig) {
129         ShardingRuleConfiguration result = new ShardingRuleConfiguration();
130         result.setTables(new LinkedList<>(currentRuleConfig.getTables()));
131         result.setAutoTables(new LinkedList<>(currentRuleConfig.getAutoTables()));
132         result.setBindingTableGroups(new LinkedList<>(currentRuleConfig.getBindingTableGroups()));
133         result.setDefaultTableShardingStrategy(currentRuleConfig.getDefaultTableShardingStrategy());
134         result.setDefaultDatabaseShardingStrategy(currentRuleConfig.getDefaultDatabaseShardingStrategy());
135         result.setDefaultKeyGenerateStrategy(currentRuleConfig.getDefaultKeyGenerateStrategy());
136         result.setDefaultShardingColumn(currentRuleConfig.getDefaultShardingColumn());
137         result.setShardingAlgorithms(new LinkedHashMap<>(currentRuleConfig.getShardingAlgorithms()));
138         result.setKeyGenerators(new LinkedHashMap<>(currentRuleConfig.getKeyGenerators()));
139         result.setAuditors(new LinkedHashMap<>(currentRuleConfig.getAuditors()));
140         return result;
141     }
142     
143     private static void check(final ShardingSphereDatabase database, final Collection<AbstractTableRuleSegment> rules, final boolean ifNotExists, final ShardingRuleConfiguration currentRuleConfig,
144                               final boolean isCreated) {
145         String databaseName = database.getName();
146         checkTables(databaseName, rules, currentRuleConfig, isCreated, ifNotExists);
147         checkDataSources(databaseName, rules, database);
148         checkKeyGenerators(rules);
149         checkAuditors(rules);
150         checkAutoTableRule(rules.stream().filter(AutoTableRuleSegment.class::isInstance).map(AutoTableRuleSegment.class::cast).collect(Collectors.toList()));
151         checkTableRule(rules.stream().filter(TableRuleSegment.class::isInstance).map(TableRuleSegment.class::cast).collect(Collectors.toList()));
152         if (!isCreated) {
153             checkBindingTableRules(rules, currentRuleConfig);
154         }
155     }
156     
157     private static boolean check(final ShardingRuleConfiguration checkedConfig, final Collection<String> dataSourceNames) {
158         Collection<String> allDataSourceNames = getDataSourceNames(checkedConfig.getTables(), checkedConfig.getAutoTables(), dataSourceNames);
159         Map<String, ShardingAlgorithm> shardingAlgorithms = new HashMap<>(checkedConfig.getShardingAlgorithms().size(), 1F);
160         Map<String, ShardingTable> shardingTables = new HashMap<>();
161         checkedConfig.getShardingAlgorithms().forEach((key, value) -> shardingAlgorithms.put(key, TypedSPILoader.getService(ShardingAlgorithm.class, value.getType(), value.getProps())));
162         shardingTables.putAll(createShardingTables(checkedConfig.getTables(), checkedConfig.getDefaultKeyGenerateStrategy(), allDataSourceNames));
163         shardingTables.putAll(createShardingAutoTables(checkedConfig.getAutoTables(), shardingAlgorithms, checkedConfig.getDefaultKeyGenerateStrategy(), allDataSourceNames));
164         ShardingStrategyConfiguration defaultDatabaseShardingStrategyConfig = null == checkedConfig.getDefaultDatabaseShardingStrategy()
165                 ? new NoneShardingStrategyConfiguration()
166                 : checkedConfig.getDefaultDatabaseShardingStrategy();
167         ShardingStrategyConfiguration defaultTableShardingStrategyConfig = null == checkedConfig.getDefaultTableShardingStrategy()
168                 ? new NoneShardingStrategyConfiguration()
169                 : checkedConfig.getDefaultTableShardingStrategy();
170         return isValidBindingTableConfiguration(shardingTables, new BindingTableCheckedConfiguration(allDataSourceNames, shardingAlgorithms, checkedConfig.getBindingTableGroups(),
171                 defaultDatabaseShardingStrategyConfig, defaultTableShardingStrategyConfig, checkedConfig.getDefaultShardingColumn()));
172     }
173     
174     private static Collection<String> getDataSourceNames(final Collection<ShardingTableRuleConfiguration> tableRuleConfigs,
175                                                          final Collection<ShardingAutoTableRuleConfiguration> autoTableRuleConfigs, final Collection<String> dataSourceNames) {
176         if (tableRuleConfigs.isEmpty() && autoTableRuleConfigs.isEmpty()) {
177             return dataSourceNames;
178         }
179         if (tableRuleConfigs.stream().map(ShardingTableRuleConfiguration::getActualDataNodes).anyMatch(each -> null == each || each.isEmpty())) {
180             return dataSourceNames;
181         }
182         Collection<String> result = new LinkedHashSet<>();
183         tableRuleConfigs.forEach(each -> result.addAll(getDataSourceNames(each)));
184         autoTableRuleConfigs.forEach(each -> result.addAll(InlineExpressionParserFactory.newInstance(each.getActualDataSources()).splitAndEvaluate()));
185         return result;
186     }
187     
188     private static Collection<String> getDataSourceNames(final ShardingTableRuleConfiguration shardingTableRuleConfig) {
189         return InlineExpressionParserFactory.newInstance(shardingTableRuleConfig.getActualDataNodes())
190                 .splitAndEvaluate().stream().map(each -> new DataNode(each).getDataSourceName()).collect(Collectors.toList());
191     }
192     
193     private static Collection<String> getDataSourceNames(final Collection<String> actualDataNodes) {
194         Collection<String> result = new LinkedHashSet<>();
195         for (String each : actualDataNodes) {
196             result.add(isValidDataNode(each) ? new DataNode(each).getDataSourceName() : each);
197         }
198         return result;
199     }
200     
201     private static boolean isValidDataNode(final String dataNodeStr) {
202         return dataNodeStr.contains(DELIMITER) && 2 == Splitter.on(DELIMITER).omitEmptyStrings().splitToList(dataNodeStr).size();
203     }
204     
205     private static Map<String, ShardingTable> createShardingTables(final Collection<ShardingTableRuleConfiguration> tableRuleConfigs,
206                                                                    final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig,
207                                                                    final Collection<String> dataSourceNames) {
208         return tableRuleConfigs.stream().map(each -> new ShardingTable(each, dataSourceNames, getDefaultGenerateKeyColumn(defaultKeyGenerateStrategyConfig)))
209                 .collect(Collectors.toMap(each -> each.getLogicTable().toLowerCase(), Function.identity(), (oldValue, currentValue) -> oldValue, LinkedHashMap::new));
210     }
211     
212     private static String getDefaultGenerateKeyColumn(final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig) {
213         return Optional.ofNullable(defaultKeyGenerateStrategyConfig).map(KeyGenerateStrategyConfiguration::getColumn).orElse(null);
214     }
215     
216     private static Map<String, ShardingTable> createShardingAutoTables(final Collection<ShardingAutoTableRuleConfiguration> autoTableRuleConfigs,
217                                                                        final Map<String, ShardingAlgorithm> shardingAlgorithms,
218                                                                        final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig, final Collection<String> dataSourceNames) {
219         return autoTableRuleConfigs.stream().map(each -> createShardingAutoTable(defaultKeyGenerateStrategyConfig, each, shardingAlgorithms, dataSourceNames))
220                 .collect(Collectors.toMap(each -> each.getLogicTable().toLowerCase(), Function.identity(), (oldValue, currentValue) -> oldValue, LinkedHashMap::new));
221     }
222     
223     private static ShardingTable createShardingAutoTable(final KeyGenerateStrategyConfiguration defaultKeyGenerateStrategyConfig, final ShardingAutoTableRuleConfiguration autoTableRuleConfig,
224                                                          final Map<String, ShardingAlgorithm> shardingAlgorithms, final Collection<String> dataSourceNames) {
225         ShardingAlgorithm shardingAlgorithm = shardingAlgorithms.get(autoTableRuleConfig.getShardingStrategy().getShardingAlgorithmName());
226         ShardingSpherePreconditions.checkState(shardingAlgorithm instanceof ShardingAutoTableAlgorithm,
227                 () -> new ShardingAlgorithmClassImplementationException(autoTableRuleConfig.getShardingStrategy().getShardingAlgorithmName(), ShardingAutoTableAlgorithm.class));
228         return new ShardingTable(autoTableRuleConfig, dataSourceNames, (ShardingAutoTableAlgorithm) shardingAlgorithm, getDefaultGenerateKeyColumn(defaultKeyGenerateStrategyConfig));
229     }
230     
231     private static boolean isValidBindingTableConfiguration(final Map<String, ShardingTable> shardingTables, final BindingTableCheckedConfiguration checkedConfig) {
232         for (ShardingTableReferenceRuleConfiguration each : checkedConfig.getBindingTableGroups()) {
233             Collection<String> bindingTables = Splitter.on(",").trimResults().splitToList(each.getReference().toLowerCase());
234             if (bindingTables.size() <= 1) {
235                 return false;
236             }
237             Iterator<String> iterator = bindingTables.iterator();
238             ShardingTable sampleShardingTable = getShardingTable(iterator.next(), shardingTables);
239             while (iterator.hasNext()) {
240                 ShardingTable shardingTable = getShardingTable(iterator.next(), shardingTables);
241                 if (!isValidActualDataSourceName(sampleShardingTable, shardingTable) || !isValidActualTableName(sampleShardingTable, shardingTable)) {
242                     return false;
243                 }
244                 if (isInvalidShardingAlgorithm(sampleShardingTable, shardingTable, true, checkedConfig) || isInvalidShardingAlgorithm(sampleShardingTable, shardingTable, false, checkedConfig)) {
245                     return false;
246                 }
247             }
248         }
249         return true;
250     }
251     
252     private static ShardingTable getShardingTable(final String logicTableName, final Map<String, ShardingTable> shardingTables) {
253         ShardingTable result = shardingTables.get(logicTableName);
254         if (null != result) {
255             return result;
256         }
257         throw new ShardingTableRuleNotFoundException(Collections.singleton(logicTableName));
258     }
259     
260     private static boolean isValidActualDataSourceName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
261         return sampleShardingTable.getActualDataSourceNames().equals(shardingTable.getActualDataSourceNames());
262     }
263     
264     private static boolean isValidActualTableName(final ShardingTable sampleShardingTable, final ShardingTable shardingTable) {
265         for (String each : sampleShardingTable.getActualDataSourceNames()) {
266             Collection<String> sampleActualTableNames =
267                     sampleShardingTable.getActualTableNames(each).stream().map(actualTableName -> actualTableName.replace(sampleShardingTable.getTableDataNode().getPrefix(), ""))
268                             .collect(Collectors.toSet());
269             Collection<String> actualTableNames =
270                     shardingTable.getActualTableNames(each).stream().map(optional -> optional.replace(shardingTable.getTableDataNode().getPrefix(), "")).collect(Collectors.toSet());
271             if (!sampleActualTableNames.equals(actualTableNames)) {
272                 return false;
273             }
274         }
275         return true;
276     }
277     
278     private static boolean isInvalidShardingAlgorithm(final ShardingTable sampleShardingTable, final ShardingTable shardingTable, final boolean databaseAlgorithm,
279                                                       final BindingTableCheckedConfiguration checkedConfig) {
280         return !getAlgorithmExpression(sampleShardingTable, databaseAlgorithm, checkedConfig).equals(getAlgorithmExpression(shardingTable, databaseAlgorithm, checkedConfig));
281     }
282     
283     private static Optional<String> getAlgorithmExpression(final ShardingTable shardingTable, final boolean databaseAlgorithm, final BindingTableCheckedConfiguration checkedConfig) {
284         ShardingStrategyConfiguration shardingStrategyConfig = databaseAlgorithm
285                 ? getDatabaseShardingStrategyConfiguration(shardingTable, checkedConfig)
286                 : getTableShardingStrategyConfiguration(shardingTable, checkedConfig);
287         ShardingAlgorithm shardingAlgorithm = checkedConfig.getShardingAlgorithms().get(shardingStrategyConfig.getShardingAlgorithmName());
288         String dataNodePrefix = databaseAlgorithm ? shardingTable.getDataSourceDataNode().getPrefix() : shardingTable.getTableDataNode().getPrefix();
289         String shardingColumn = getShardingColumn(shardingStrategyConfig, checkedConfig.getDefaultShardingColumn());
290         return null == shardingAlgorithm ? Optional.empty() : shardingAlgorithm.getAlgorithmStructure(dataNodePrefix, shardingColumn);
291     }
292     
293     private static ShardingStrategyConfiguration getDatabaseShardingStrategyConfiguration(final ShardingTable shardingTable, final BindingTableCheckedConfiguration checkedConfig) {
294         return null == shardingTable.getDatabaseShardingStrategyConfig() ? checkedConfig.getDefaultDatabaseShardingStrategyConfig() : shardingTable.getDatabaseShardingStrategyConfig();
295     }
296     
297     private static ShardingStrategyConfiguration getTableShardingStrategyConfiguration(final ShardingTable shardingTable, final BindingTableCheckedConfiguration checkedConfig) {
298         return null == shardingTable.getTableShardingStrategyConfig() ? checkedConfig.getDefaultTableShardingStrategyConfig() : shardingTable.getTableShardingStrategyConfig();
299     }
300     
301     private static String getShardingColumn(final ShardingStrategyConfiguration shardingStrategyConfig, final String defaultShardingColumn) {
302         String shardingColumn = defaultShardingColumn;
303         if (shardingStrategyConfig instanceof ComplexShardingStrategyConfiguration) {
304             shardingColumn = ((ComplexShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumns();
305         }
306         if (shardingStrategyConfig instanceof StandardShardingStrategyConfiguration) {
307             shardingColumn = ((StandardShardingStrategyConfiguration) shardingStrategyConfig).getShardingColumn();
308         }
309         return null == shardingColumn ? "" : shardingColumn;
310     }
311     
312     private static void checkDataSources(final String databaseName, final Collection<AbstractTableRuleSegment> rules, final ShardingSphereDatabase database) {
313         Collection<String> requiredDataSource = getRequiredDataSources(rules);
314         Collection<String> notExistedDataSources = database.getResourceMetaData().getNotExistedDataSources(requiredDataSource);
315         Collection<String> logicDataSources = getLogicDataSources(database);
316         notExistedDataSources.removeIf(logicDataSources::contains);
317         ShardingSpherePreconditions.checkMustEmpty(notExistedDataSources, () -> new MissingRequiredStorageUnitsException(databaseName, notExistedDataSources));
318     }
319     
320     private static Collection<String> getRequiredDataSources(final ShardingRuleConfiguration config) {
321         Collection<String> result = new LinkedHashSet<>();
322         result.addAll(config.getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getActualDataSources)
323                 .map(each -> Splitter.on(",").trimResults().splitToList(each)).flatMap(Collection::stream).collect(Collectors.toSet()));
324         result.addAll(config.getTables().stream().map(each -> InlineExpressionParserFactory.newInstance(each.getActualDataNodes()).splitAndEvaluate())
325                 .flatMap(Collection::stream).distinct().map(each -> new DataNode(each).getDataSourceName()).collect(Collectors.toSet()));
326         return result;
327     }
328     
329     private static <T extends AbstractTableRuleSegment> Collection<String> getRequiredDataSources(final Collection<T> rules) {
330         return rules.stream().map(AbstractTableRuleSegment::getDataSourceNodes).flatMap(Collection::stream)
331                 .map(ShardingTableRuleStatementChecker::parseDateSource).map(ShardingTableRuleStatementChecker::getDataSourceNames).flatMap(Collection::stream).collect(Collectors.toList());
332     }
333     
334     private static Collection<String> parseDateSource(final String dateSource) {
335         return InlineExpressionParserFactory.newInstance(dateSource).splitAndEvaluate();
336     }
337     
338     private static Collection<String> getLogicDataSources(final ShardingSphereDatabase database) {
339         Collection<String> result = new LinkedHashSet<>();
340         for (DataSourceMapperRuleAttribute each : database.getRuleMetaData().getAttributes(DataSourceMapperRuleAttribute.class)) {
341             result.addAll(each.getDataSourceMapper().keySet());
342         }
343         return result;
344     }
345     
346     private static void checkTables(final String databaseName, final Collection<AbstractTableRuleSegment> rules, final ShardingRuleConfiguration currentRuleConfig, final boolean isCreate,
347                                     final boolean ifNotExists) {
348         Collection<String> requiredTables = rules.stream().map(AbstractTableRuleSegment::getLogicTable).collect(Collectors.toList());
349         Collection<String> duplicatedRuleNames = getDuplicatedRuleNames(requiredTables);
350         ShardingSpherePreconditions.checkMustEmpty(duplicatedRuleNames, () -> new DuplicateRuleException("sharding", databaseName, duplicatedRuleNames));
351         Collection<String> currentShardingTables = null == currentRuleConfig ? Collections.emptyList() : getCurrentShardingTables(currentRuleConfig);
352         if (isCreate) {
353             if (!ifNotExists) {
354                 duplicatedRuleNames.addAll(getDuplicatedRuleNames(requiredTables, currentShardingTables));
355                 ShardingSpherePreconditions.checkMustEmpty(duplicatedRuleNames, () -> new DuplicateRuleException("sharding", databaseName, duplicatedRuleNames));
356             }
357         } else {
358             Collection<String> notExistedRules = getNotExistedRules(requiredTables, currentShardingTables);
359             ShardingSpherePreconditions.checkMustEmpty(notExistedRules, () -> new MissingRequiredRuleException("sharding", databaseName, notExistedRules));
360         }
361     }
362     
363     private static Collection<String> getDuplicatedRuleNames(final Collection<String> collection) {
364         Collection<String> duplicatedNames = collection.stream().collect(Collectors.groupingBy(String::toLowerCase, Collectors.counting())).entrySet().stream()
365                 .filter(each -> each.getValue() > 1).map(Entry::getKey).collect(Collectors.toCollection(CaseInsensitiveSet::new));
366         return collection.stream().filter(duplicatedNames::contains).collect(Collectors.toSet());
367     }
368     
369     private static Collection<String> getDuplicatedRuleNames(final Collection<String> requiredRuleNames, final Collection<String> currentRuleNames) {
370         return requiredRuleNames.stream().filter(currentRuleNames::contains).collect(Collectors.toSet());
371     }
372     
373     private static Set<String> getNotExistedRules(final Collection<String> requiredRuleNames, final Collection<String> currentRuleNames) {
374         return requiredRuleNames.stream().filter(each -> !currentRuleNames.contains(each)).collect(Collectors.toSet());
375     }
376     
377     private static Collection<String> getCurrentShardingTables(final ShardingRuleConfiguration currentRuleConfig) {
378         Collection<String> result = new CaseInsensitiveSet<>();
379         result.addAll(currentRuleConfig.getTables().stream().map(ShardingTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
380         result.addAll(currentRuleConfig.getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
381         return result;
382     }
383     
384     private static void checkKeyGenerators(final Collection<AbstractTableRuleSegment> rules) {
385         rules.stream().map(AbstractTableRuleSegment::getKeyGenerateStrategySegment).filter(Objects::nonNull)
386                 .map(KeyGenerateStrategySegment::getKeyGenerateAlgorithmSegment)
387                 .forEach(each -> TypedSPILoader.checkService(KeyGenerateAlgorithm.class, each.getName(), each.getProps()));
388     }
389     
390     private static void checkAuditors(final Collection<AbstractTableRuleSegment> rules) {
391         Collection<AuditStrategySegment> auditStrategySegments = rules.stream().map(AbstractTableRuleSegment::getAuditStrategySegment).filter(Objects::nonNull).collect(Collectors.toList());
392         Collection<AlgorithmSegment> requiredAuditors = new LinkedHashSet<>();
393         for (AuditStrategySegment each : auditStrategySegments) {
394             requiredAuditors.addAll(each.getAuditorSegments().stream().map(ShardingAuditorSegment::getAlgorithmSegment).collect(Collectors.toList()));
395         }
396         requiredAuditors.forEach(each -> TypedSPILoader.checkService(ShardingAuditAlgorithm.class, each.getName(), each.getProps()));
397     }
398     
399     private static void checkAutoTableRule(final Collection<AutoTableRuleSegment> autoTableRules) {
400         checkAutoTableShardingAlgorithms(autoTableRules);
401     }
402     
403     private static void checkAutoTableShardingAlgorithms(final Collection<AutoTableRuleSegment> autoTableRules) {
404         autoTableRules.forEach(each -> {
405             ShardingAlgorithm shardingAlgorithm = TypedSPILoader.getService(ShardingAlgorithm.class, each.getShardingAlgorithmSegment().getName(), each.getShardingAlgorithmSegment().getProps());
406             ShardingSpherePreconditions.checkState(shardingAlgorithm instanceof ShardingAutoTableAlgorithm,
407                     () -> new AlgorithmInitializationException(shardingAlgorithm, "Auto sharding algorithm is required for table '%s'", each.getLogicTable()));
408         });
409     }
410     
411     private static void checkTableRule(final Collection<TableRuleSegment> tableRules) {
412         checkStrategy(tableRules);
413     }
414     
415     private static void checkStrategy(final Collection<TableRuleSegment> rules) {
416         for (TableRuleSegment each : rules) {
417             Optional<ShardingStrategySegment> databaseStrategySegment = Optional.ofNullable(each.getDatabaseStrategySegment());
418             if (databaseStrategySegment.isPresent()) {
419                 if ("none".equalsIgnoreCase(databaseStrategySegment.get().getType())) {
420                     Collection<String> requiredDataSources = getRequiredDataSources(rules);
421                     ShardingSpherePreconditions.checkState(1 == requiredDataSources.size(),
422                             () -> new InvalidShardingStrategyConfigurationException("database", databaseStrategySegment.get().getType()));
423                 } else {
424                     AlgorithmSegment databaseShardingAlgorithm = databaseStrategySegment.get().getShardingAlgorithm();
425                     checkDatabaseShardingAlgorithm(each, databaseShardingAlgorithm);
426                 }
427             }
428             Optional<ShardingStrategySegment> tableStrategySegment = Optional.ofNullable(each.getTableStrategySegment());
429             if (tableStrategySegment.isPresent()) {
430                 if ("none".equalsIgnoreCase(tableStrategySegment.get().getType())) {
431                     Collection<String> requiredTables = getRequiredTables(rules);
432                     ShardingSpherePreconditions.checkState(1 == requiredTables.size(),
433                             () -> new InvalidShardingStrategyConfigurationException("table", tableStrategySegment.get().getType()));
434                 } else {
435                     AlgorithmSegment tableShardingAlgorithm = tableStrategySegment.get().getShardingAlgorithm();
436                     checkTableShardingAlgorithm(each, tableShardingAlgorithm);
437                 }
438             }
439         }
440     }
441     
442     private static void checkDatabaseShardingAlgorithm(final TableRuleSegment each, final AlgorithmSegment databaseShardingAlgorithm) {
443         if (null != databaseShardingAlgorithm) {
444             ShardingAlgorithm shardingAlgorithm = TypedSPILoader.getService(ShardingAlgorithm.class, databaseShardingAlgorithm.getName(), databaseShardingAlgorithm.getProps());
445             ShardingSpherePreconditions.checkState(!(shardingAlgorithm instanceof ShardingAutoTableAlgorithm),
446                     () -> new AlgorithmInitializationException(shardingAlgorithm, "Auto sharding algorithm can not be used to create a table in table '%s'", each.getLogicTable()));
447         }
448         ShardingSpherePreconditions.checkState(isValidStrategy(each.getDatabaseStrategySegment()),
449                 () -> new InvalidAlgorithmConfigurationException("sharding", null == databaseShardingAlgorithm ? null : databaseShardingAlgorithm.getName()));
450     }
451     
452     private static void checkTableShardingAlgorithm(final TableRuleSegment each, final AlgorithmSegment tableShardingAlgorithm) {
453         if (null != tableShardingAlgorithm) {
454             ShardingAlgorithm shardingAlgorithm = TypedSPILoader.getService(ShardingAlgorithm.class, tableShardingAlgorithm.getName(), tableShardingAlgorithm.getProps());
455             ShardingSpherePreconditions.checkState(!(shardingAlgorithm instanceof ShardingAutoTableAlgorithm),
456                     () -> new AlgorithmInitializationException(shardingAlgorithm, "Auto sharding algorithm can not be used to create a table in table '%s'", each.getLogicTable()));
457         }
458         ShardingSpherePreconditions.checkState(isValidStrategy(each.getTableStrategySegment()),
459                 () -> new InvalidAlgorithmConfigurationException("sharding", null == tableShardingAlgorithm ? null : tableShardingAlgorithm.getName()));
460     }
461     
462     private static boolean isValidStrategy(final ShardingStrategySegment shardingStrategySegment) {
463         return ShardingStrategyType.getValueOf(shardingStrategySegment.getType()).isValid(shardingStrategySegment.getShardingColumn()) && null != shardingStrategySegment.getShardingAlgorithm();
464     }
465     
466     private static Collection<String> getRequiredTables(final Collection<TableRuleSegment> rules) {
467         return rules.stream().map(TableRuleSegment::getDataSourceNodes).flatMap(Collection::stream)
468                 .map(ShardingTableRuleStatementChecker::parseDateSource).map(ShardingTableRuleStatementChecker::getTableNames).flatMap(Collection::stream).collect(Collectors.toList());
469     }
470     
471     private static Collection<String> getTableNames(final Collection<String> actualDataNodes) {
472         Collection<String> result = new HashSet<>();
473         for (String each : actualDataNodes) {
474             result.add(isValidDataNode(each) ? new DataNode(each).getTableName() : each);
475         }
476         return result;
477     }
478     
479     private static void checkBindingTableRules(final Collection<AbstractTableRuleSegment> rules, final ShardingRuleConfiguration currentRuleConfig) {
480         if (null == currentRuleConfig || currentRuleConfig.getBindingTableGroups().isEmpty()) {
481             return;
482         }
483         Collection<String> bindingTables = getCurrentBindingTables(currentRuleConfig);
484         if (bindingTables.size() <= 1) {
485             return;
486         }
487         ShardingRuleConfiguration toBeAlteredRuleConfig = ShardingTableRuleStatementConverter.convert(rules);
488         Collection<String> toBeAlteredLogicTableNames = getAlteredLogicalTableNames(toBeAlteredRuleConfig);
489         Collection<String> toBeAlteredBindingTableNames = toBeAlteredLogicTableNames.stream().filter(bindingTables::contains).collect(Collectors.toSet());
490         if (toBeAlteredBindingTableNames.isEmpty()) {
491             return;
492         }
493         ShardingRuleConfiguration toBeCheckedRuleConfig = createToBeCheckedShardingRuleConfiguration(currentRuleConfig);
494         removeRuleConfiguration(toBeCheckedRuleConfig, toBeAlteredRuleConfig);
495         addRuleConfiguration(toBeCheckedRuleConfig, toBeAlteredRuleConfig);
496         Collection<String> dataSourceNames = getRequiredDataSources(toBeCheckedRuleConfig);
497         dataSourceNames.addAll(getRequiredDataSources(toBeAlteredRuleConfig));
498         ShardingSpherePreconditions.checkState(check(toBeCheckedRuleConfig, dataSourceNames),
499                 () -> new InvalidRuleConfigurationException("sharding table", toBeAlteredLogicTableNames, Collections.singleton("invalid binding table configuration.")));
500     }
501     
502     private static Collection<String> getCurrentBindingTables(final ShardingRuleConfiguration currentRuleConfig) {
503         Collection<String> result = new LinkedHashSet<>();
504         currentRuleConfig.getBindingTableGroups().forEach(each -> result.addAll(Splitter.on(",").trimResults().splitToList(each.getReference())));
505         return result;
506     }
507     
508     private static void removeRuleConfiguration(final ShardingRuleConfiguration currentRuleConfig, final ShardingRuleConfiguration toBeAlteredRuleConfig) {
509         Collection<String> toBeAlteredLogicTableNames = getAlteredLogicalTableNames(toBeAlteredRuleConfig);
510         toBeAlteredLogicTableNames.forEach(each -> {
511             currentRuleConfig.getTables().removeIf(table -> table.getLogicTable().equalsIgnoreCase(each));
512             currentRuleConfig.getAutoTables().removeIf(table -> table.getLogicTable().equalsIgnoreCase(each));
513         });
514     }
515     
516     private static void addRuleConfiguration(final ShardingRuleConfiguration currentRuleConfig, final ShardingRuleConfiguration toBeAlteredRuleConfig) {
517         currentRuleConfig.getTables().addAll(toBeAlteredRuleConfig.getTables());
518         currentRuleConfig.getAutoTables().addAll(toBeAlteredRuleConfig.getAutoTables());
519         currentRuleConfig.getShardingAlgorithms().putAll(toBeAlteredRuleConfig.getShardingAlgorithms());
520         currentRuleConfig.getKeyGenerators().putAll(toBeAlteredRuleConfig.getKeyGenerators());
521     }
522     
523     private static Collection<String> getAlteredLogicalTableNames(final ShardingRuleConfiguration toBeAlteredRuleConfig) {
524         Collection<String> result = toBeAlteredRuleConfig.getTables().stream().map(ShardingTableRuleConfiguration::getLogicTable).collect(Collectors.toList());
525         result.addAll(toBeAlteredRuleConfig.getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toList()));
526         return result;
527     }
528 }