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.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
89
90 @NoArgsConstructor(access = AccessLevel.PRIVATE)
91 public final class ShardingTableRuleStatementChecker {
92
93 private static final String DELIMITER = ".";
94
95
96
97
98
99
100
101
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
110
111
112
113
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
121
122
123
124
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
545
546
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
574
575
576
577
578
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
585 } catch (final Exception ignored) {
586
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 }