1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
83
84 @NoArgsConstructor(access = AccessLevel.PRIVATE)
85 public final class ShardingTableRuleStatementChecker {
86
87 private static final String DELIMITER = ".";
88
89
90
91
92
93
94
95
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
104
105
106
107
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
115
116
117
118
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 }