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

chengzhang 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 13691f4da93 Support like concat nested concat statement rewrite with 
encrypt feature (#32970)
13691f4da93 is described below

commit 13691f4da93a68aa205991432dc37f8c2f61aaf0
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Tue Sep 24 13:40:43 2024 +0800

    Support like concat nested concat statement rewrite with encrypt feature 
(#32970)
---
 .../EncryptPredicateRightValueTokenGenerator.java  |  4 +-
 .../EncryptPredicateFunctionRightValueToken.java   | 50 ++++++++++++++++------
 ...ncryptPredicateFunctionRightValueTokenTest.java | 26 ++++++++++-
 .../cases/dql/e2e-dql-select-aggregate.xml         |  4 ++
 .../query-with-cipher/dml/select/select-where.xml  | 23 ++++++++--
 5 files changed, 86 insertions(+), 21 deletions(-)

diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGenerator.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGenerator.java
index 5963c2d5b7c..bf45039948e 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGenerator.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/predicate/EncryptPredicateRightValueTokenGenerator.java
@@ -87,8 +87,8 @@ public final class EncryptPredicateRightValueTokenGenerator 
implements Collectio
                 encryptCondition.getPositionValueMap().keySet(), 
getEncryptedValues(schemaName, encryptTable, encryptCondition, 
encryptCondition.getValues(parameters)));
         Collection<Integer> parameterMarkerIndexes = 
encryptCondition.getPositionIndexMap().keySet();
         if (encryptCondition instanceof EncryptBinaryCondition && 
((EncryptBinaryCondition) encryptCondition).getExpressionSegment() instanceof 
FunctionSegment) {
-            return new EncryptPredicateFunctionRightValueToken(startIndex, 
stopIndex,
-                    ((FunctionSegment) ((EncryptBinaryCondition) 
encryptCondition).getExpressionSegment()).getFunctionName(), indexValues, 
parameterMarkerIndexes);
+            FunctionSegment functionSegment = (FunctionSegment) 
((EncryptBinaryCondition) encryptCondition).getExpressionSegment();
+            return new EncryptPredicateFunctionRightValueToken(startIndex, 
stopIndex, functionSegment.getFunctionName(), functionSegment.getParameters(), 
indexValues, parameterMarkerIndexes);
         }
         return encryptCondition instanceof EncryptInCondition
                 ? new EncryptPredicateInRightValueToken(startIndex, stopIndex, 
indexValues, parameterMarkerIndexes)
diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/pojo/EncryptPredicateFunctionRightValueToken.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/pojo/EncryptPredicateFunctionRightValueToken.java
index 322d6e18189..399dee059f6 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/pojo/EncryptPredicateFunctionRightValueToken.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/pojo/EncryptPredicateFunctionRightValueToken.java
@@ -20,30 +20,38 @@ package 
org.apache.shardingsphere.encrypt.rewrite.token.pojo;
 import lombok.Getter;
 import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken;
 import 
org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.Substitutable;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
 
 import java.util.Collection;
 import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Predicate in right value token for encrypt.
  */
 public final class EncryptPredicateFunctionRightValueToken extends SQLToken 
implements Substitutable {
     
+    private static final String COMMA_SEPARATOR = ", ";
+    
     @Getter
     private final int stopIndex;
     
     private final String functionName;
     
+    private final Collection<ExpressionSegment> parameters;
+    
     private final Map<Integer, Object> indexValues;
     
     private final Collection<Integer> paramMarkerIndexes;
     
-    public EncryptPredicateFunctionRightValueToken(final int startIndex, final 
int stopIndex, final String functionName,
+    public EncryptPredicateFunctionRightValueToken(final int startIndex, final 
int stopIndex, final String functionName, final Collection<ExpressionSegment> 
parameters,
                                                    final Map<Integer, Object> 
indexValues, final Collection<Integer> paramMarkerIndexes) {
         super(startIndex);
         this.stopIndex = stopIndex;
         this.functionName = functionName;
+        this.parameters = parameters;
         this.indexValues = indexValues;
         this.paramMarkerIndexes = paramMarkerIndexes;
     }
@@ -51,21 +59,37 @@ public final class EncryptPredicateFunctionRightValueToken 
extends SQLToken impl
     @Override
     public String toString() {
         StringBuilder result = new StringBuilder();
-        result.append(functionName).append(" (");
-        for (int i = 0; i < indexValues.size() + paramMarkerIndexes.size(); 
i++) {
-            if (paramMarkerIndexes.contains(i)) {
-                result.append('?');
+        AtomicInteger parameterIndex = new AtomicInteger();
+        appendFunctionSegment(functionName, parameters, result, 
parameterIndex);
+        return result.toString();
+    }
+    
+    private void appendFunctionSegment(final String functionName, final 
Collection<ExpressionSegment> parameters, final StringBuilder builder, final 
AtomicInteger parameterIndex) {
+        builder.append(functionName).append(" (");
+        for (ExpressionSegment each : parameters) {
+            if (each instanceof FunctionSegment) {
+                appendFunctionSegment(((FunctionSegment) 
each).getFunctionName(), ((FunctionSegment) each).getParameters(), builder, 
parameterIndex);
             } else {
-                if (indexValues.get(i) instanceof String) {
-                    
result.append('\'').append(indexValues.get(i)).append('\'');
-                } else {
-                    result.append(indexValues.get(i));
-                }
+                appendRewrittenParameters(builder, 
parameterIndex.getAndIncrement());
             }
-            result.append(", ");
         }
-        result.delete(result.length() - 2, result.length()).append(')');
-        return result.toString();
+        if (builder.toString().endsWith(COMMA_SEPARATOR)) {
+            builder.delete(builder.length() - 2, builder.length());
+        }
+        builder.append(')');
+    }
+    
+    private void appendRewrittenParameters(final StringBuilder builder, final 
int parameterIndex) {
+        if (paramMarkerIndexes.contains(parameterIndex)) {
+            builder.append('?');
+        } else {
+            if (indexValues.get(parameterIndex) instanceof String) {
+                
builder.append('\'').append(indexValues.get(parameterIndex)).append('\'');
+            } else {
+                builder.append(indexValues.get(parameterIndex));
+            }
+        }
+        builder.append(COMMA_SEPARATOR);
     }
     
     @Override
diff --git 
a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/pojo/EncryptPredicateFunctionRightValueTokenTest.java
 
b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/pojo/EncryptPredicateFunctionRightValueTokenTest.java
index e80ad66d888..70c8e4a3ce9 100644
--- 
a/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/pojo/EncryptPredicateFunctionRightValueTokenTest.java
+++ 
b/features/encrypt/core/src/test/java/org/apache/shardingsphere/encrypt/rewrite/pojo/EncryptPredicateFunctionRightValueTokenTest.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.encrypt.rewrite.pojo;
 
 import 
org.apache.shardingsphere.encrypt.rewrite.token.pojo.EncryptPredicateFunctionRightValueToken;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
 import org.junit.jupiter.api.Test;
 
 import java.util.Collections;
@@ -31,13 +32,34 @@ import static org.hamcrest.MatcherAssert.assertThat;
 class EncryptPredicateFunctionRightValueTokenTest {
     
     @Test
-    void assertToStringWithoutPlaceholderWithoutTableOwnerWithFunction() {
+    void assertToStringWithSimpleFunction() {
         Map<Integer, Object> indexValues = new LinkedHashMap<>(3, 1F);
         indexValues.put(0, "%");
         indexValues.put(1, "abc");
         indexValues.put(2, "%");
         FunctionSegment functionSegment = new FunctionSegment(0, 0, "CONCAT", 
"('%','abc','%')");
-        EncryptPredicateFunctionRightValueToken actual = new 
EncryptPredicateFunctionRightValueToken(0, 0, 
functionSegment.getFunctionName(), indexValues, Collections.emptyList());
+        functionSegment.getParameters().add(new LiteralExpressionSegment(0, 0, 
"%"));
+        functionSegment.getParameters().add(new LiteralExpressionSegment(0, 0, 
"abc"));
+        functionSegment.getParameters().add(new LiteralExpressionSegment(0, 0, 
"%"));
+        EncryptPredicateFunctionRightValueToken actual =
+                new EncryptPredicateFunctionRightValueToken(0, 0, 
functionSegment.getFunctionName(), functionSegment.getParameters(), 
indexValues, Collections.emptyList());
         assertThat(actual.toString(), is("CONCAT ('%', 'abc', '%')"));
     }
+    
+    @Test
+    void assertToStringWithNestedFunction() {
+        Map<Integer, Object> indexValues = new LinkedHashMap<>(3, 1F);
+        indexValues.put(0, "%");
+        indexValues.put(1, "abc");
+        indexValues.put(2, "%");
+        FunctionSegment functionSegment = new FunctionSegment(0, 0, "CONCAT", 
"('%',CONCAT('abc','%'))");
+        functionSegment.getParameters().add(new LiteralExpressionSegment(0, 0, 
"%"));
+        FunctionSegment nestedFunctionSegment = new FunctionSegment(0, 0, 
"CONCAT", "('abc','%')");
+        nestedFunctionSegment.getParameters().add(new 
LiteralExpressionSegment(0, 0, "abc"));
+        nestedFunctionSegment.getParameters().add(new 
LiteralExpressionSegment(0, 0, "%"));
+        functionSegment.getParameters().add(nestedFunctionSegment);
+        EncryptPredicateFunctionRightValueToken actual =
+                new EncryptPredicateFunctionRightValueToken(0, 0, 
functionSegment.getFunctionName(), functionSegment.getParameters(), 
indexValues, Collections.emptyList());
+        assertThat(actual.toString(), is("CONCAT ('%', CONCAT ('abc', '%'))"));
+    }
 }
diff --git 
a/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-aggregate.xml 
b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-aggregate.xml
index b3f7569d779..f8c39535f1f 100644
--- a/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-aggregate.xml
+++ b/test/e2e/sql/src/test/resources/cases/dql/e2e-dql-select-aggregate.xml
@@ -140,4 +140,8 @@
     <test-case sql="SELECT * FROM t_merchant WHERE business_code LIKE 
CONCAT('%', ?, '%')" db-types="MySQL,PostgreSQL,openGauss" 
scenario-types="encrypt">
         <assertion parameters="abc:String" 
expected-data-source-name="read_dataset" />
     </test-case>
+
+    <test-case sql="SELECT * FROM t_merchant WHERE business_code LIKE 
CONCAT('%', CONCAT(?, '%'))" db-types="MySQL,PostgreSQL,openGauss" 
scenario-types="encrypt">
+        <assertion parameters="abc:String" 
expected-data-source-name="read_dataset" />
+    </test-case>
 </e2e-test-cases>
diff --git 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-where.xml
 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-where.xml
index 0deb537d050..3fab9aa6254 100644
--- 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-where.xml
+++ 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-where.xml
@@ -73,10 +73,25 @@
         <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak AS a WHERE a.amount in (?, ?)" parameters="1000, 2000" 
/>
         <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak AS a WHERE 
a.cipher_amount in (?, ?)" parameters="encrypt_1000, encrypt_2000" />
     </rewrite-assertion>
-    
-    <rewrite-assertion 
id="select_where_with_cipher_column_like_concat_for_literals" 
db-types="PostgreSQL,openGauss">
-        <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak AS a WHERE a.account_id = 1 AND a.certificate_number 
like concat('%','abc','%')" />
-        <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak AS a WHERE a.account_id 
= 1 AND a.like_query_certificate_number like concat ('like_query_%', 
'like_query_abc', 'like_query_%')" />
+
+    <rewrite-assertion 
id="select_where_with_cipher_column_like_concat_for_parameters" 
db-types="MySQL,PostgreSQL,openGauss">
+        <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak a WHERE a.account_id = 1 AND a.certificate_number like 
concat ('%', ? ,'%')" parameters="abc" />
+        <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak a WHERE a.account_id = 1 
AND a.like_query_certificate_number like concat ('like_query_%', ?, 
'like_query_%')" parameters="like_query_abc" />
+    </rewrite-assertion>
+
+    <rewrite-assertion 
id="select_where_with_cipher_column_like_concat_for_literals" 
db-types="MySQL,PostgreSQL,openGauss">
+        <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak a WHERE a.account_id = 1 AND a.certificate_number like 
concat ('%','abc','%')" />
+        <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak a WHERE a.account_id = 1 
AND a.like_query_certificate_number like concat ('like_query_%', 
'like_query_abc', 'like_query_%')" />
+    </rewrite-assertion>
+
+    <rewrite-assertion 
id="select_where_with_cipher_column_like_nested_concat_for_parameters" 
db-types="MySQL,PostgreSQL,openGauss">
+        <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak a WHERE a.account_id = 1 AND a.certificate_number like 
concat ('%', concat(?, '%'))" parameters="abc" />
+        <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak a WHERE a.account_id = 1 
AND a.like_query_certificate_number like concat ('like_query_%', concat (?, 
'like_query_%'))" parameters="like_query_abc" />
+    </rewrite-assertion>
+
+    <rewrite-assertion 
id="select_where_with_cipher_column_like_nested_concat_for_literals" 
db-types="MySQL,PostgreSQL,openGauss">
+        <input sql="SELECT a.account_id, a.password, a.amount AS a, a.status 
AS s FROM t_account_bak a WHERE a.account_id = 1 AND a.certificate_number like 
concat ('%', concat('abc','%'))" />
+        <output sql="SELECT a.account_id, a.cipher_password AS password, 
a.cipher_amount AS a, a.status AS s FROM t_account_bak a WHERE a.account_id = 1 
AND a.like_query_certificate_number like concat ('like_query_%', concat 
('like_query_abc', 'like_query_%'))" />
     </rewrite-assertion>
 
     <rewrite-assertion id="select_from_user_with_column_alias" 
db-types="SQLServer">

Reply via email to