This is an automated email from the ASF dual-hosted git repository.

duanzhengqiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new e4325be0117 Check duplicate actual data nodes when create or alter 
sharding table rule (#33138)
e4325be0117 is described below

commit e4325be0117a939aa7de1a0f4c4f47ab4c62a438
Author: Raigor <[email protected]>
AuthorDate: Mon Oct 7 16:12:18 2024 +0800

    Check duplicate actual data nodes when create or alter sharding table rule 
(#33138)
    
    * Check duplicate actual data nodes when create or alter sharding table 
rule.
    
    * Fix AlterShardingTableRuleExecutorTest
    
    * Fix checkstyle
    
    * Fix CreateShardingTableRuleExecutorTest
---
 .../shardingsphere/sharding/rule/ShardingRule.java |  2 -
 .../sharding/rule/checker/ShardingRuleChecker.java | 33 +++++++++++----
 .../checker/ShardingTableRuleStatementChecker.java | 16 ++++++++
 .../ShardingTableRuleStatementConverter.java       | 47 ++++++++++++++++++++++
 .../update/AlterShardingTableRuleExecutor.java     |  7 +++-
 .../update/CreateShardingTableRuleExecutor.java    | 22 ++++++----
 .../update/AlterShardingTableRuleExecutorTest.java | 45 ++++++++++++++++-----
 .../CreateShardingTableRuleExecutorTest.java       | 27 +++++++++++--
 8 files changed, 168 insertions(+), 31 deletions(-)

diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
index 393caab4964..d6c0938ef5a 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/ShardingRule.java
@@ -84,8 +84,6 @@ import java.util.stream.Collectors;
 @Getter
 public final class ShardingRule implements DatabaseRule {
     
-    private static final String ALGORITHM_EXPRESSION_KEY = 
"algorithm-expression";
-    
     private final ShardingRuleConfiguration configuration;
     
     private final Collection<String> dataSourceNames;
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/checker/ShardingRuleChecker.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/checker/ShardingRuleChecker.java
index 41e55f1613a..4713cd900a6 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/checker/ShardingRuleChecker.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/rule/checker/ShardingRuleChecker.java
@@ -44,7 +44,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 @RequiredArgsConstructor
@@ -64,13 +63,14 @@ public class ShardingRuleChecker {
     }
     
     private void checkUniqueActualDataNodesInTableRules() {
-        Set<DataNode> uniqueActualDataNodes = new 
HashSet<>(shardingRule.getShardingTables().size(), 1F);
-        shardingRule.getShardingTables().forEach((key, value) -> {
-            DataNode sampleActualDataNode = 
value.getActualDataNodes().iterator().next();
-            
ShardingSpherePreconditions.checkNotContains(uniqueActualDataNodes, 
sampleActualDataNode,
-                    () -> new DuplicateShardingActualDataNodeException(key, 
sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
-            uniqueActualDataNodes.add(sampleActualDataNode);
-        });
+        Collection<DataNode> uniqueActualDataNodes = new 
HashSet<>(shardingRule.getShardingTables().size(), 1F);
+        shardingRule.getShardingTables().forEach((key, value) -> 
checkUniqueActualDataNodes(uniqueActualDataNodes, key, 
value.getActualDataNodes().iterator().next()));
+    }
+    
+    private void checkUniqueActualDataNodes(final Collection<DataNode> 
uniqueActualDataNodes, final String logicTable, final DataNode 
sampleActualDataNode) {
+        ShardingSpherePreconditions.checkNotContains(uniqueActualDataNodes, 
sampleActualDataNode,
+                () -> new DuplicateShardingActualDataNodeException(logicTable, 
sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
+        uniqueActualDataNodes.add(sampleActualDataNode);
     }
     
     private void checkBindingTableConfiguration(final 
ShardingRuleConfiguration ruleConfig) {
@@ -178,4 +178,21 @@ public class ShardingRuleChecker {
                             shardingStrategy.getShardingAlgorithmName(), 
shardingTable.getLogicTable()));
         }
     }
+    
+    /**
+     * Check to be added data nodes.
+     *
+     * @param toBeAddedDataNodes to be added data nodes
+     * @param isAlteration is alteration
+     */
+    public void checkToBeAddedDataNodes(final Map<String, 
Collection<DataNode>> toBeAddedDataNodes, final boolean isAlteration) {
+        Collection<DataNode> uniqueActualDataNodes = new 
HashSet<>(shardingRule.getShardingTables().size() + toBeAddedDataNodes.size(), 
1F);
+        shardingRule.getShardingTables().forEach((key, value) -> {
+            if (isAlteration && toBeAddedDataNodes.containsKey(key)) {
+                return;
+            }
+            checkUniqueActualDataNodes(uniqueActualDataNodes, key, 
value.getActualDataNodes().iterator().next());
+        });
+        toBeAddedDataNodes.forEach((key, value) -> 
checkUniqueActualDataNodes(uniqueActualDataNodes, key, 
value.iterator().next()));
+    }
 }
diff --git 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
index bf51ee86f33..eb5c7407e4e 100644
--- 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
+++ 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/checker/ShardingTableRuleStatementChecker.java
@@ -55,6 +55,7 @@ import 
org.apache.shardingsphere.sharding.distsql.segment.table.AbstractTableRul
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.AutoTableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.TableRuleSegment;
 import 
org.apache.shardingsphere.sharding.exception.algorithm.ShardingAlgorithmClassImplementationException;
+import 
org.apache.shardingsphere.sharding.exception.metadata.DuplicateShardingActualDataNodeException;
 import 
org.apache.shardingsphere.sharding.exception.metadata.ShardingTableRuleNotFoundException;
 import 
org.apache.shardingsphere.sharding.exception.strategy.InvalidShardingStrategyConfigurationException;
 import 
org.apache.shardingsphere.sharding.rule.BindingTableCheckedConfiguration;
@@ -525,4 +526,19 @@ public final class ShardingTableRuleStatementChecker {
         
result.addAll(toBeAlteredRuleConfig.getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toList()));
         return result;
     }
+    
+    /**
+     * Check to be added data nodes.
+     *
+     * @param toBeAddedDataNodes to be added data nodes
+     */
+    public static void checkToBeAddedDataNodes(final Map<String, 
Collection<DataNode>> toBeAddedDataNodes) {
+        Collection<DataNode> uniqueActualDataNodes = new 
HashSet<>(toBeAddedDataNodes.size(), 1F);
+        toBeAddedDataNodes.forEach((key, value) -> {
+            DataNode sampleActualDataNode = value.iterator().next();
+            
ShardingSpherePreconditions.checkNotContains(uniqueActualDataNodes, 
sampleActualDataNode,
+                    () -> new DuplicateShardingActualDataNodeException(key, 
sampleActualDataNode.getDataSourceName(), sampleActualDataNode.getTableName()));
+            uniqueActualDataNodes.add(sampleActualDataNode);
+        });
+    }
 }
diff --git 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/converter/ShardingTableRuleStatementConverter.java
 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/converter/ShardingTableRuleStatementConverter.java
index 89822c253a6..3a5502076a3 100644
--- 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/converter/ShardingTableRuleStatementConverter.java
+++ 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/converter/ShardingTableRuleStatementConverter.java
@@ -21,6 +21,12 @@ import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
+import 
org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
+import org.apache.shardingsphere.infra.datanode.DataNode;
+import org.apache.shardingsphere.infra.datanode.DataNodeUtils;
+import 
org.apache.shardingsphere.infra.exception.core.ShardingSpherePreconditions;
+import org.apache.shardingsphere.infra.expr.core.InlineExpressionParserFactory;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.rule.ShardingAutoTableRuleConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
@@ -28,6 +34,7 @@ import 
org.apache.shardingsphere.sharding.api.config.strategy.audit.ShardingAudi
 import 
org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.strategy.sharding.NoneShardingStrategyConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.strategy.sharding.ShardingStrategyConfiguration;
+import 
org.apache.shardingsphere.sharding.api.sharding.ShardingAutoTableAlgorithm;
 import 
org.apache.shardingsphere.sharding.distsql.handler.enums.ShardingStrategyLevelType;
 import 
org.apache.shardingsphere.sharding.distsql.handler.enums.ShardingStrategyType;
 import 
org.apache.shardingsphere.sharding.distsql.segment.strategy.AuditStrategySegment;
@@ -37,9 +44,12 @@ import 
org.apache.shardingsphere.sharding.distsql.segment.strategy.ShardingStrat
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.AbstractTableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.AutoTableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.TableRuleSegment;
+import org.apache.shardingsphere.sharding.spi.ShardingAlgorithm;
 
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.stream.Collectors;
@@ -195,4 +205,41 @@ public final class ShardingTableRuleStatementConverter {
     private static String getKeyGeneratorName(final String tableName, final 
String algorithmType) {
         return String.format("%s_%s", tableName, algorithmType).toLowerCase();
     }
+    
+    /**
+     * Convert rule segments to data nodes.
+     *
+     * @param segments sharding table rule segments
+     * @return data nodes map
+     */
+    public static Map<String, Collection<DataNode>> convertDataNodes(final 
Collection<AbstractTableRuleSegment> segments) {
+        Map<String, Collection<DataNode>> result = new 
HashMap<>(segments.size(), 1F);
+        for (AbstractTableRuleSegment each : segments) {
+            if (each instanceof TableRuleSegment) {
+                result.put(each.getLogicTable(), 
getActualDataNodes((TableRuleSegment) each));
+                continue;
+            }
+            result.put(each.getLogicTable(), 
getActualDataNodes((AutoTableRuleSegment) each));
+        }
+        return result;
+    }
+    
+    private static Collection<DataNode> getActualDataNodes(final 
TableRuleSegment ruleSegment) {
+        Collection<DataNode> result = new LinkedList<>();
+        for (String each : ruleSegment.getDataSourceNodes()) {
+            List<String> dataNodes = 
InlineExpressionParserFactory.newInstance(each).splitAndEvaluate();
+            
result.addAll(dataNodes.stream().map(DataNode::new).collect(Collectors.toList()));
+        }
+        return result;
+    }
+    
+    private static Collection<DataNode> getActualDataNodes(final 
AutoTableRuleSegment ruleSegment) {
+        ShardingAlgorithm shardingAlgorithm =
+                TypedSPILoader.getService(ShardingAlgorithm.class, 
ruleSegment.getShardingAlgorithmSegment().getName(), 
ruleSegment.getShardingAlgorithmSegment().getProps());
+        ShardingSpherePreconditions.checkState(shardingAlgorithm instanceof 
ShardingAutoTableAlgorithm,
+                () -> new AlgorithmInitializationException(shardingAlgorithm, 
"Auto sharding algorithm is required for table '%s'", 
ruleSegment.getLogicTable()));
+        List<String> dataNodes = 
DataNodeUtils.getFormatDataNodes(((ShardingAutoTableAlgorithm) 
shardingAlgorithm).getAutoTablesAmount(),
+                ruleSegment.getLogicTable(), ruleSegment.getDataSourceNodes());
+        return 
dataNodes.stream().map(DataNode::new).collect(Collectors.toList());
+    }
 }
diff --git 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/AlterShardingTableRuleExecutor.java
 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/AlterShardingTableRuleExecutor.java
index 3263560a1a8..49080b33a00 100644
--- 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/AlterShardingTableRuleExecutor.java
+++ 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/AlterShardingTableRuleExecutor.java
@@ -18,8 +18,8 @@
 package org.apache.shardingsphere.sharding.distsql.handler.update;
 
 import lombok.Setter;
-import 
org.apache.shardingsphere.distsql.handler.required.DistSQLExecutorCurrentRuleRequired;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleAlterExecutor;
+import 
org.apache.shardingsphere.distsql.handler.required.DistSQLExecutorCurrentRuleRequired;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.rule.ShardingAutoTableRuleConfiguration;
@@ -46,6 +46,11 @@ public final class AlterShardingTableRuleExecutor implements 
DatabaseRuleAlterEx
     @Override
     public void checkBeforeUpdate(final AlterShardingTableRuleStatement 
sqlStatement) {
         ShardingTableRuleStatementChecker.checkAlteration(database, 
sqlStatement.getRules(), rule.getConfiguration());
+        checkUniqueActualDataNodes(sqlStatement);
+    }
+    
+    private void checkUniqueActualDataNodes(final 
AlterShardingTableRuleStatement sqlStatement) {
+        
rule.getShardingRuleChecker().checkToBeAddedDataNodes(ShardingTableRuleStatementConverter.convertDataNodes(sqlStatement.getRules()),
 true);
     }
     
     @Override
diff --git 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/CreateShardingTableRuleExecutor.java
 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/CreateShardingTableRuleExecutor.java
index 7dbcdf6ceb8..d842b3bd78b 100644
--- 
a/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/CreateShardingTableRuleExecutor.java
+++ 
b/features/sharding/distsql/handler/src/main/java/org/apache/shardingsphere/sharding/distsql/handler/update/CreateShardingTableRuleExecutor.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.sharding.distsql.handler.update;
 
+import com.cedarsoftware.util.CaseInsensitiveSet;
 import lombok.Setter;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.DatabaseRuleCreateExecutor;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
@@ -31,7 +32,6 @@ import org.apache.shardingsphere.sharding.rule.ShardingRule;
 
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.stream.Collectors;
 
 /**
@@ -47,16 +47,24 @@ public final class CreateShardingTableRuleExecutor 
implements DatabaseRuleCreate
     @Override
     public void checkBeforeUpdate(final CreateShardingTableRuleStatement 
sqlStatement) {
         ShardingTableRuleStatementChecker.checkCreation(database, 
sqlStatement.getRules(), sqlStatement.isIfNotExists(), null == rule ? null : 
rule.getConfiguration());
+        checkUniqueActualDataNodes(sqlStatement);
     }
     
-    @Override
-    public ShardingRuleConfiguration buildToBeCreatedRuleConfiguration(final 
CreateShardingTableRuleStatement sqlStatement) {
-        Collection<AbstractTableRuleSegment> segments = 
sqlStatement.getRules();
+    private void checkUniqueActualDataNodes(final 
CreateShardingTableRuleStatement sqlStatement) {
+        if (null == rule) {
+            
ShardingTableRuleStatementChecker.checkToBeAddedDataNodes(ShardingTableRuleStatementConverter.convertDataNodes(sqlStatement.getRules()));
+            return;
+        }
         if (sqlStatement.isIfNotExists()) {
             Collection<String> duplicatedRuleNames = 
getDuplicatedRuleNames(sqlStatement);
-            segments.removeIf(each -> 
duplicatedRuleNames.contains(each.getLogicTable()));
+            sqlStatement.getRules().removeIf(each -> 
duplicatedRuleNames.contains(each.getLogicTable()));
         }
-        return ShardingTableRuleStatementConverter.convert(segments);
+        
rule.getShardingRuleChecker().checkToBeAddedDataNodes(ShardingTableRuleStatementConverter.convertDataNodes(sqlStatement.getRules()),
 false);
+    }
+    
+    @Override
+    public ShardingRuleConfiguration buildToBeCreatedRuleConfiguration(final 
CreateShardingTableRuleStatement sqlStatement) {
+        return 
ShardingTableRuleStatementConverter.convert(sqlStatement.getRules());
     }
     
     private Collection<String> getDuplicatedRuleNames(final 
CreateShardingTableRuleStatement sqlStatement) {
@@ -65,7 +73,7 @@ public final class CreateShardingTableRuleExecutor implements 
DatabaseRuleCreate
     }
     
     private Collection<String> getCurrentShardingTables() {
-        Collection<String> result = new LinkedList<>();
+        Collection<String> result = new CaseInsensitiveSet<>();
         
result.addAll(rule.getConfiguration().getTables().stream().map(ShardingTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
         
result.addAll(rule.getConfiguration().getAutoTables().stream().map(ShardingAutoTableRuleConfiguration::getLogicTable).collect(Collectors.toSet()));
         return result;
diff --git 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/AlterShardingTableRuleExecutorTest.java
 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/AlterShardingTableRuleExecutorTest.java
index 47714e66b55..44d2bb2800e 100644
--- 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/AlterShardingTableRuleExecutorTest.java
+++ 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/AlterShardingTableRuleExecutorTest.java
@@ -17,7 +17,9 @@
 
 package org.apache.shardingsphere.sharding.distsql.update;
 
+import lombok.SneakyThrows;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
+import org.apache.shardingsphere.distsql.statement.DistSQLStatement;
 import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import 
org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import 
org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData;
@@ -28,12 +30,18 @@ import 
org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfi
 import 
org.apache.shardingsphere.sharding.api.config.strategy.keygen.KeyGenerateStrategyConfiguration;
 import 
org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
 import 
org.apache.shardingsphere.sharding.distsql.handler.update.AlterShardingTableRuleExecutor;
+import 
org.apache.shardingsphere.sharding.distsql.parser.facade.ShardingDistSQLParserFacade;
 import 
org.apache.shardingsphere.sharding.distsql.segment.strategy.KeyGenerateStrategySegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.strategy.ShardingStrategySegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.AutoTableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.TableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.statement.AlterShardingTableRuleStatement;
+import 
org.apache.shardingsphere.sharding.exception.metadata.DuplicateShardingActualDataNodeException;
 import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.rule.checker.ShardingRuleChecker;
+import org.apache.shardingsphere.sql.parser.api.visitor.SQLVisitor;
+import org.apache.shardingsphere.sql.parser.core.ParseASTNode;
+import org.apache.shardingsphere.sql.parser.core.SQLParserFactory;
 import org.apache.shardingsphere.test.fixture.jdbc.MockedDataSource;
 import org.apache.shardingsphere.test.util.PropertiesBuilder;
 import org.apache.shardingsphere.test.util.PropertiesBuilder.Property;
@@ -50,6 +58,7 @@ import java.util.Properties;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -69,14 +78,29 @@ class AlterShardingTableRuleExecutorTest {
         when(database.getResourceMetaData()).thenReturn(resourceMetaData);
         when(database.getRuleMetaData()).thenReturn(new 
RuleMetaData(Collections.emptyList()));
         executor.setDatabase(database);
+        ShardingRule rule = mock(ShardingRule.class);
+        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
+        ShardingRuleChecker checker = new ShardingRuleChecker(rule);
+        when(rule.getShardingRuleChecker()).thenReturn(checker);
+        executor.setRule(rule);
+    }
+    
+    @Test
+    void assertCheckWithDuplicateDataNodes() {
+        String sql = "ALTER SHARDING TABLE RULE t_order("
+                + "DATANODES('ds_${0..1}.t_order'),"
+                + 
"DATABASE_STRATEGY(TYPE='standard',SHARDING_COLUMN=user_id,SHARDING_ALGORITHM(TYPE(NAME='inline',PROPERTIES('algorithm-expression'='ds_${user_id
 % 2}'))))"
+                + "), t_order_item("
+                + "DATANODES('ds_${0..1}.t_order'),"
+                + 
"DATABASE_STRATEGY(TYPE='standard',SHARDING_COLUMN=user_id,SHARDING_ALGORITHM(TYPE(NAME='inline',PROPERTIES('algorithm-expression'='ds_${user_id
 % 2}'))))"
+                + ");";
+        AlterShardingTableRuleStatement sqlStatement = 
(AlterShardingTableRuleStatement) getDistSQLStatement(sql);
+        assertThrows(DuplicateShardingActualDataNodeException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
     }
     
     @Test
     void assertUpdate() {
         AlterShardingTableRuleStatement sqlStatement = new 
AlterShardingTableRuleStatement(Arrays.asList(createCompleteAutoTableRule("t_order_item"),
 createCompleteTableRule("t_order")));
-        ShardingRule rule = mock(ShardingRule.class);
-        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
-        executor.setRule(rule);
         executor.checkBeforeUpdate(sqlStatement);
         ShardingRuleConfiguration toBeAlteredRuleConfig = 
executor.buildToBeAlteredRuleConfiguration(sqlStatement);
         assertThat(toBeAlteredRuleConfig.getTables().size(), is(1));
@@ -101,9 +125,6 @@ class AlterShardingTableRuleExecutorTest {
     @Test
     void assertUpdateWithDifferentCase() {
         AlterShardingTableRuleStatement sqlStatement = new 
AlterShardingTableRuleStatement(Arrays.asList(createCompleteAutoTableRule("T_ORDER_ITEM"),
 createCompleteTableRule("T_ORDER")));
-        ShardingRule rule = mock(ShardingRule.class);
-        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
-        executor.setRule(rule);
         executor.checkBeforeUpdate(sqlStatement);
         ShardingRuleConfiguration toBeAlteredRuleConfig = 
executor.buildToBeAlteredRuleConfiguration(sqlStatement);
         assertThat(toBeAlteredRuleConfig.getTables().size(), is(1));
@@ -128,9 +149,6 @@ class AlterShardingTableRuleExecutorTest {
     @Test
     void assertUpdateTableType() {
         AlterShardingTableRuleStatement sqlStatement = new 
AlterShardingTableRuleStatement(Arrays.asList(createCompleteAutoTableRule("t_order"),
 createCompleteTableRule("t_order_item")));
-        ShardingRule rule = mock(ShardingRule.class);
-        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
-        executor.setRule(rule);
         executor.checkBeforeUpdate(sqlStatement);
         ShardingRuleConfiguration toBeAlteredRuleConfig = 
executor.buildToBeAlteredRuleConfiguration(sqlStatement);
         assertThat(toBeAlteredRuleConfig.getTables().size(), is(1));
@@ -197,4 +215,13 @@ class AlterShardingTableRuleExecutorTest {
         result.put("ds_1", new MockedDataSource());
         return result;
     }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    @SuppressWarnings("rawtypes")
+    private DistSQLStatement getDistSQLStatement(final String sql) {
+        ShardingDistSQLParserFacade facade = new ShardingDistSQLParserFacade();
+        ParseASTNode parseASTNode = (ParseASTNode) 
SQLParserFactory.newInstance(sql, facade.getLexerClass(), 
facade.getParserClass()).parse();
+        SQLVisitor visitor = 
facade.getVisitorClass().getDeclaredConstructor().newInstance();
+        return (DistSQLStatement) visitor.visit(parseASTNode.getRootNode());
+    }
 }
diff --git 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/CreateShardingTableRuleExecutorTest.java
 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/CreateShardingTableRuleExecutorTest.java
index 4479ae23d63..2bba05b577f 100644
--- 
a/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/CreateShardingTableRuleExecutorTest.java
+++ 
b/features/sharding/distsql/handler/src/test/java/org/apache/shardingsphere/sharding/distsql/update/CreateShardingTableRuleExecutorTest.java
@@ -41,8 +41,10 @@ import 
org.apache.shardingsphere.sharding.distsql.segment.table.AbstractTableRul
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.AutoTableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.segment.table.TableRuleSegment;
 import 
org.apache.shardingsphere.sharding.distsql.statement.CreateShardingTableRuleStatement;
+import 
org.apache.shardingsphere.sharding.exception.metadata.DuplicateShardingActualDataNodeException;
 import 
org.apache.shardingsphere.sharding.exception.strategy.InvalidShardingStrategyConfigurationException;
 import org.apache.shardingsphere.sharding.rule.ShardingRule;
+import org.apache.shardingsphere.sharding.rule.checker.ShardingRuleChecker;
 import org.apache.shardingsphere.sql.parser.api.visitor.SQLVisitor;
 import org.apache.shardingsphere.sql.parser.core.ParseASTNode;
 import org.apache.shardingsphere.sql.parser.core.SQLParserFactory;
@@ -92,10 +94,12 @@ class CreateShardingTableRuleExecutorTest {
     
     @Test
     void assertBuildToBeCreatedRuleConfiguration() {
-        CreateShardingTableRuleStatement sqlStatement = new 
CreateShardingTableRuleStatement(false, 
Arrays.asList(createCompleteAutoTableRule(), createCompleteTableRule()));
         ShardingRule rule = mock(ShardingRule.class);
         when(rule.getConfiguration()).thenReturn(currentRuleConfig);
+        ShardingRuleChecker checker = new ShardingRuleChecker(rule);
+        when(rule.getShardingRuleChecker()).thenReturn(checker);
         executor.setRule(rule);
+        CreateShardingTableRuleStatement sqlStatement = new 
CreateShardingTableRuleStatement(false, 
Arrays.asList(createCompleteAutoTableRule(), createCompleteTableRule()));
         executor.checkBeforeUpdate(sqlStatement);
         ShardingRuleConfiguration actual = 
executor.buildToBeCreatedRuleConfiguration(sqlStatement);
         assertThat(actual.getTables().size(), is(1));
@@ -185,15 +189,30 @@ class CreateShardingTableRuleExecutorTest {
         assertThrows(InvalidShardingStrategyConfigurationException.class, () 
-> executor.checkBeforeUpdate(distSQLStatement));
     }
     
+    @Test
+    void assertCheckWithDuplicateDataNodes() {
+        String sql = "CREATE SHARDING TABLE RULE t_order("
+                + "DATANODES('ds_${0..1}.t_order'),"
+                + 
"DATABASE_STRATEGY(TYPE='standard',SHARDING_COLUMN=user_id,SHARDING_ALGORITHM(TYPE(NAME='inline',PROPERTIES('algorithm-expression'='ds_${user_id
 % 2}'))))"
+                + "), t_order_item("
+                + "DATANODES('ds_${0..1}.t_order'),"
+                + 
"DATABASE_STRATEGY(TYPE='standard',SHARDING_COLUMN=user_id,SHARDING_ALGORITHM(TYPE(NAME='inline',PROPERTIES('algorithm-expression'='ds_${user_id
 % 2}'))))"
+                + ");";
+        CreateShardingTableRuleStatement sqlStatement = 
(CreateShardingTableRuleStatement) getDistSQLStatement(sql);
+        assertThrows(DuplicateShardingActualDataNodeException.class, () -> 
executor.checkBeforeUpdate(sqlStatement));
+    }
+    
     @Test
     void assertUpdateWithIfNotExistsStatement() {
+        ShardingRule rule = mock(ShardingRule.class);
+        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
+        ShardingRuleChecker checker = new ShardingRuleChecker(rule);
+        when(rule.getShardingRuleChecker()).thenReturn(checker);
+        executor.setRule(rule);
         Collection<AbstractTableRuleSegment> segments = new LinkedList<>();
         segments.add(createCompleteAutoTableRule());
         segments.add(createCompleteTableRule());
         CreateShardingTableRuleStatement statementWithIfNotExists = new 
CreateShardingTableRuleStatement(true, segments);
-        ShardingRule rule = mock(ShardingRule.class);
-        when(rule.getConfiguration()).thenReturn(currentRuleConfig);
-        executor.setRule(rule);
         executor.checkBeforeUpdate(statementWithIfNotExists);
         ShardingRuleConfiguration actual = 
executor.buildToBeCreatedRuleConfiguration(statementWithIfNotExists);
         assertThat(actual.getTables().size(), is(1));

Reply via email to