You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by ji...@apache.org on 2022/12/29 00:24:38 UTC

[shardingsphere] branch master updated: Add `IF NOT EXISTS` to `create encrypt rule` (#23124)

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

jianglongtao 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 bbae7b79895 Add `IF NOT EXISTS` to `create encrypt rule` (#23124)
bbae7b79895 is described below

commit bbae7b798955d62470b22d43fbd387be2b6746e8
Author: Zichao <57...@users.noreply.github.com>
AuthorDate: Thu Dec 29 13:24:30 2022 +1300

    Add `IF NOT EXISTS` to `create encrypt rule` (#23124)
    
    * Add `IF NOT EXISTS` to `create encrypt rule`
    
    * Add `IF NOT EXISTS` to `create encrypt rule`
    
    * Add `IF NOT EXISTS` to `create encrypt rule`
    
    * Add `IF NOT EXISTS` to `create encrypt rule`
    
    * Add `IF NOT EXISTS` to `create encrypt rule`
---
 .../update/CreateEncryptRuleStatementUpdater.java  | 42 +++++++++++++++---
 .../CreateEncryptRuleStatementUpdaterTest.java     | 51 +++++++++++++++++-----
 .../src/main/antlr4/imports/encrypt/Keyword.g4     |  4 ++
 .../main/antlr4/imports/encrypt/RDLStatement.g4    |  6 ++-
 .../core/EncryptDistSQLStatementVisitor.java       |  2 +-
 .../statement/CreateEncryptRuleStatement.java      |  9 ++--
 6 files changed, 92 insertions(+), 22 deletions(-)

diff --git a/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdater.java b/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdater.java
index bfd5809db67..5134ed3acd0 100644
--- a/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdater.java
+++ b/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdater.java
@@ -17,24 +17,26 @@
 
 package org.apache.shardingsphere.encrypt.distsql.handler.update;
 
+import org.apache.shardingsphere.distsql.handler.exception.algorithm.InvalidAlgorithmConfigurationException;
+import org.apache.shardingsphere.distsql.handler.exception.rule.DuplicateRuleException;
+import org.apache.shardingsphere.distsql.handler.exception.rule.InvalidRuleConfigurationException;
+import org.apache.shardingsphere.distsql.handler.exception.storageunit.EmptyStorageUnitException;
+import org.apache.shardingsphere.distsql.handler.update.RuleDefinitionCreateUpdater;
 import org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration;
+import org.apache.shardingsphere.encrypt.api.config.rule.EncryptColumnRuleConfiguration;
 import org.apache.shardingsphere.encrypt.api.config.rule.EncryptTableRuleConfiguration;
 import org.apache.shardingsphere.encrypt.distsql.handler.converter.EncryptRuleStatementConverter;
 import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptColumnSegment;
 import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptRuleSegment;
 import org.apache.shardingsphere.encrypt.distsql.parser.statement.CreateEncryptRuleStatement;
 import org.apache.shardingsphere.encrypt.factory.EncryptAlgorithmFactory;
-import org.apache.shardingsphere.distsql.handler.exception.storageunit.EmptyStorageUnitException;
-import org.apache.shardingsphere.distsql.handler.exception.rule.DuplicateRuleException;
-import org.apache.shardingsphere.distsql.handler.exception.algorithm.InvalidAlgorithmConfigurationException;
-import org.apache.shardingsphere.distsql.handler.exception.rule.InvalidRuleConfigurationException;
-import org.apache.shardingsphere.distsql.handler.update.RuleDefinitionCreateUpdater;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.apache.shardingsphere.infra.util.exception.ShardingSpherePreconditions;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashSet;
+import java.util.LinkedList;
 import java.util.stream.Collectors;
 
 /**
@@ -42,9 +44,14 @@ import java.util.stream.Collectors;
  */
 public final class CreateEncryptRuleStatementUpdater implements RuleDefinitionCreateUpdater<CreateEncryptRuleStatement, EncryptRuleConfiguration> {
     
+    private boolean ifNotExists;
+    
     @Override
     public void checkSQLStatement(final ShardingSphereDatabase database, final CreateEncryptRuleStatement sqlStatement, final EncryptRuleConfiguration currentRuleConfig) {
-        checkDuplicateRuleNames(database.getName(), sqlStatement, currentRuleConfig);
+        ifNotExists = sqlStatement.isIfNotExists();
+        if (!ifNotExists) {
+            checkDuplicateRuleNames(database.getName(), sqlStatement, currentRuleConfig);
+        }
         checkDataType(sqlStatement);
         checkToBeCreatedEncryptors(sqlStatement);
         checkDataSources(database);
@@ -87,11 +94,34 @@ public final class CreateEncryptRuleStatementUpdater implements RuleDefinitionCr
     @Override
     public void updateCurrentRuleConfiguration(final EncryptRuleConfiguration currentRuleConfig, final EncryptRuleConfiguration toBeCreatedRuleConfig) {
         if (null != currentRuleConfig) {
+            if (ifNotExists) {
+                removeDuplicatedRules(currentRuleConfig, toBeCreatedRuleConfig);
+            }
+            if (toBeCreatedRuleConfig.getTables().isEmpty()) {
+                return;
+            }
             currentRuleConfig.getTables().addAll(toBeCreatedRuleConfig.getTables());
             currentRuleConfig.getEncryptors().putAll(toBeCreatedRuleConfig.getEncryptors());
         }
     }
     
+    private void removeDuplicatedRules(final EncryptRuleConfiguration currentRuleConfig, final EncryptRuleConfiguration toBeCreatedRuleConfig) {
+        Collection<String> currentTables = new LinkedList<>();
+        Collection<String> toBeRemovedEncryptors = new LinkedList<>();
+        Collection<String> toBeRemovedTables = new LinkedList<>();
+        currentRuleConfig.getTables().forEach(each -> currentTables.add(each.getName()));
+        toBeCreatedRuleConfig.getTables().forEach(each -> {
+            if (currentTables.contains(each.getName())) {
+                toBeRemovedEncryptors.addAll(each.getColumns().stream().map(EncryptColumnRuleConfiguration::getEncryptorName).collect(Collectors.toList()));
+                toBeRemovedEncryptors.addAll(each.getColumns().stream().map(EncryptColumnRuleConfiguration::getAssistedQueryEncryptorName).collect(Collectors.toList()));
+                toBeRemovedEncryptors.addAll(each.getColumns().stream().map(EncryptColumnRuleConfiguration::getLikeQueryEncryptorName).collect(Collectors.toList()));
+                toBeRemovedTables.add(each.getName());
+            }
+        });
+        toBeCreatedRuleConfig.getTables().removeIf(each -> toBeRemovedTables.contains(each.getName()));
+        toBeCreatedRuleConfig.getEncryptors().keySet().removeIf(toBeRemovedEncryptors::contains);
+    }
+    
     @Override
     public Class<EncryptRuleConfiguration> getRuleConfigurationClass() {
         return EncryptRuleConfiguration.class;
diff --git a/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdaterTest.java b/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdaterTest.java
index 34414d358fc..1752a369ef6 100644
--- a/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdaterTest.java
+++ b/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/CreateEncryptRuleStatementUpdaterTest.java
@@ -17,15 +17,15 @@
 
 package org.apache.shardingsphere.encrypt.distsql.handler.update;
 
+import org.apache.shardingsphere.distsql.handler.exception.algorithm.InvalidAlgorithmConfigurationException;
+import org.apache.shardingsphere.distsql.handler.exception.rule.DuplicateRuleException;
+import org.apache.shardingsphere.distsql.handler.exception.rule.InvalidRuleConfigurationException;
 import org.apache.shardingsphere.distsql.parser.segment.AlgorithmSegment;
 import org.apache.shardingsphere.encrypt.api.config.EncryptRuleConfiguration;
 import org.apache.shardingsphere.encrypt.api.config.rule.EncryptTableRuleConfiguration;
 import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptColumnSegment;
 import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptRuleSegment;
 import org.apache.shardingsphere.encrypt.distsql.parser.statement.CreateEncryptRuleStatement;
-import org.apache.shardingsphere.distsql.handler.exception.rule.DuplicateRuleException;
-import org.apache.shardingsphere.distsql.handler.exception.algorithm.InvalidAlgorithmConfigurationException;
-import org.apache.shardingsphere.distsql.handler.exception.rule.InvalidRuleConfigurationException;
 import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -33,9 +33,16 @@ import org.mockito.Answers;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.Properties;
 
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
 @RunWith(MockitoJUnitRunner.class)
 public final class CreateEncryptRuleStatementUpdaterTest {
     
@@ -46,12 +53,12 @@ public final class CreateEncryptRuleStatementUpdaterTest {
     
     @Test(expected = DuplicateRuleException.class)
     public void assertCheckSQLStatementWithDuplicateEncryptRule() {
-        updater.checkSQLStatement(database, createSQLStatement("MD5"), getCurrentRuleConfig());
+        updater.checkSQLStatement(database, createSQLStatement(false, "MD5"), getCurrentRuleConfig());
     }
     
     @Test(expected = InvalidAlgorithmConfigurationException.class)
     public void assertCheckSQLStatementWithoutToBeCreatedEncryptors() {
-        updater.checkSQLStatement(database, createSQLStatement("INVALID_TYPE"), null);
+        updater.checkSQLStatement(database, createSQLStatement(false, "INVALID_TYPE"), null);
     }
     
     @Test(expected = InvalidRuleConfigurationException.class)
@@ -61,20 +68,42 @@ public final class CreateEncryptRuleStatementUpdaterTest {
                 new AlgorithmSegment("test", new Properties()),
                 new AlgorithmSegment("CHAR_DIGEST_LIKE", new Properties()), null);
         EncryptRuleSegment ruleSegment = new EncryptRuleSegment("t_encrypt", Collections.singleton(columnSegment), null);
-        CreateEncryptRuleStatement statement = new CreateEncryptRuleStatement(Collections.singleton(ruleSegment));
+        CreateEncryptRuleStatement statement = new CreateEncryptRuleStatement(false, Collections.singleton(ruleSegment));
         updater.checkSQLStatement(database, statement, null);
     }
     
-    private CreateEncryptRuleStatement createSQLStatement(final String encryptorName) {
-        EncryptColumnSegment columnSegment = new EncryptColumnSegment("user_id", "user_cipher", "user_plain", "assisted_column", "like_column",
+    @Test
+    public void assertCreateEncryptRuleWithIfNotExists() {
+        EncryptRuleConfiguration currentRuleConfig = getCurrentRuleConfig();
+        CreateEncryptRuleStatement sqlStatement = createSQLStatement(true, "AES");
+        updater.checkSQLStatement(database, sqlStatement, currentRuleConfig);
+        EncryptRuleConfiguration toBeCreatedRuleConfig = updater.buildToBeCreatedRuleConfiguration(sqlStatement);
+        updater.updateCurrentRuleConfiguration(currentRuleConfig, toBeCreatedRuleConfig);
+        assertThat(currentRuleConfig.getTables().size(), is(2));
+        assertTrue(currentRuleConfig.getEncryptors().isEmpty());
+    }
+    
+    private CreateEncryptRuleStatement createSQLStatement(final boolean ifNotExists, final String encryptorName) {
+        EncryptColumnSegment tEncryptColumnSegment = new EncryptColumnSegment("user_id", "user_cipher", "user_plain", "assisted_column", "like_column",
                 new AlgorithmSegment(encryptorName, new Properties()),
                 new AlgorithmSegment(encryptorName, new Properties()),
                 new AlgorithmSegment(encryptorName, new Properties()), null);
-        EncryptRuleSegment ruleSegment = new EncryptRuleSegment("t_encrypt", Collections.singleton(columnSegment), null);
-        return new CreateEncryptRuleStatement(Collections.singleton(ruleSegment));
+        EncryptColumnSegment tOrderColumnSegment = new EncryptColumnSegment("order_id", "order_cipher", "order_plain", "assisted_column", "like_column",
+                new AlgorithmSegment(encryptorName, new Properties()),
+                new AlgorithmSegment(encryptorName, new Properties()),
+                new AlgorithmSegment(encryptorName, new Properties()), null);
+        EncryptRuleSegment tEncryptRuleSegment = new EncryptRuleSegment("t_encrypt", Collections.singleton(tEncryptColumnSegment), null);
+        EncryptRuleSegment tOrderRuleSegment = new EncryptRuleSegment("t_order", Collections.singleton(tOrderColumnSegment), null);
+        Collection<EncryptRuleSegment> rules = new LinkedList<>();
+        rules.add(tEncryptRuleSegment);
+        rules.add(tOrderRuleSegment);
+        return new CreateEncryptRuleStatement(ifNotExists, rules);
     }
     
     private EncryptRuleConfiguration getCurrentRuleConfig() {
-        return new EncryptRuleConfiguration(Collections.singleton(new EncryptTableRuleConfiguration("t_encrypt", Collections.emptyList(), null)), Collections.emptyMap());
+        Collection<EncryptTableRuleConfiguration> rules = new LinkedList<>();
+        rules.add(new EncryptTableRuleConfiguration("t_encrypt", Collections.emptyList(), null));
+        rules.add(new EncryptTableRuleConfiguration("t_order", Collections.emptyList(), null));
+        return new EncryptRuleConfiguration(rules, new HashMap<>());
     }
 }
diff --git a/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/Keyword.g4 b/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/Keyword.g4
index aba744a3034..1f437610b45 100644
--- a/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/Keyword.g4
+++ b/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/Keyword.g4
@@ -178,3 +178,7 @@ SM4
 CHAR_DIGEST_LIKE
     : C H A R UL_ D I G E S T UL_ L I K E
     ;
+
+NOT
+    : N O T
+    ;
diff --git a/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/RDLStatement.g4 b/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/RDLStatement.g4
index c78e2b1170d..bd3f5aa71f9 100644
--- a/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/RDLStatement.g4
+++ b/features/encrypt/distsql/parser/src/main/antlr4/imports/encrypt/RDLStatement.g4
@@ -20,7 +20,7 @@ grammar RDLStatement;
 import BaseRule;
 
 createEncryptRule
-    : CREATE ENCRYPT RULE encryptRuleDefinition (COMMA_ encryptRuleDefinition)*
+    : CREATE ENCRYPT RULE ifNotExists? encryptRuleDefinition (COMMA_ encryptRuleDefinition)*
     ;
 
 alterEncryptRule
@@ -110,3 +110,7 @@ queryWithCipherColumn
 ifExists
     : IF EXISTS
     ;
+
+ifNotExists
+    : IF NOT EXISTS
+    ;
diff --git a/features/encrypt/distsql/parser/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/core/EncryptDistSQLStatementVisitor.java b/features/encrypt/distsql/parser/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/core/EncryptDistSQLStatementVisitor.java
index d5efe890bba..d8a77a9ff3b 100644
--- a/features/encrypt/distsql/parser/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/core/EncryptDistSQLStatementVisitor.java
+++ b/features/encrypt/distsql/parser/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/core/EncryptDistSQLStatementVisitor.java
@@ -56,7 +56,7 @@ public final class EncryptDistSQLStatementVisitor extends EncryptDistSQLStatemen
     
     @Override
     public ASTNode visitCreateEncryptRule(final CreateEncryptRuleContext ctx) {
-        return new CreateEncryptRuleStatement(ctx.encryptRuleDefinition().stream().map(each -> (EncryptRuleSegment) visit(each)).collect(Collectors.toList()));
+        return new CreateEncryptRuleStatement(null != ctx.ifNotExists(), ctx.encryptRuleDefinition().stream().map(each -> (EncryptRuleSegment) visit(each)).collect(Collectors.toList()));
     }
     
     @Override
diff --git a/features/encrypt/distsql/statement/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/statement/CreateEncryptRuleStatement.java b/features/encrypt/distsql/statement/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/statement/CreateEncryptRuleStatement.java
index 8f98adeed80..25ab6e9df4f 100644
--- a/features/encrypt/distsql/statement/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/statement/CreateEncryptRuleStatement.java
+++ b/features/encrypt/distsql/statement/src/main/java/org/apache/shardingsphere/encrypt/distsql/parser/statement/CreateEncryptRuleStatement.java
@@ -18,18 +18,21 @@
 package org.apache.shardingsphere.encrypt.distsql.parser.statement;
 
 import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptRuleSegment;
 import org.apache.shardingsphere.distsql.parser.statement.rdl.create.CreateRuleStatement;
+import org.apache.shardingsphere.encrypt.distsql.parser.segment.EncryptRuleSegment;
 
 import java.util.Collection;
 
 /**
  * Create encrypt rule statement.
  */
-@RequiredArgsConstructor
 @Getter
 public final class CreateEncryptRuleStatement extends CreateRuleStatement {
     
     private final Collection<EncryptRuleSegment> rules;
+    
+    public CreateEncryptRuleStatement(final boolean ifNotExists, final Collection<EncryptRuleSegment> rules) {
+        super(ifNotExists);
+        this.rules = rules;
+    }
 }