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