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

terrymanu 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 3b26fb77d1b Support SqlServer update statement for Specifying a view 
as the target object when use encrypt feature (#38896)
3b26fb77d1b is described below

commit 3b26fb77d1bf0d871829242a3d8d695c268512e5
Author: Claire <[email protected]>
AuthorDate: Wed Jun 24 21:06:04 2026 +0800

    Support SqlServer update statement for Specifying a view as the target 
object when use encrypt feature (#38896)
    
    * support Specifying a view as the target object
    
    * update release
    
    * add test
    
    * update RELEASE-NOTES.md
    
    * update
---
 RELEASE-NOTES.md                                   |  1 +
 .../EncryptProjectionTokenGenerator.java           | 11 +++++++++
 .../EncryptSelectProjectionTokenGenerator.java     | 27 ++++++++++++++++++----
 .../engine/scenario/EncryptSQLRewriterIT.java      |  9 ++++++++
 .../query-with-cipher/ddl/alter/alter-view.xml     | 24 +++++++++++++++++++
 .../query-with-cipher/ddl/create/create-view.xml   | 24 +++++++++++++++++++
 .../case/query-with-cipher/dml/update/update.xml   |  5 ++++
 .../scenario/encrypt/config/query-with-cipher.yaml | 12 ++++++++++
 8 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index de91e5a4e71..cbba7ce1784 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -62,6 +62,7 @@
 1. Proxy: Support Firebird prepared statement cache reuse for held connections 
- [#38644](https://github.com/apache/shardingsphere/pull/38644)
 1. JDBC & Proxy: Add a check to verify database name naming conventions. - 
[#38883](https://github.com/apache/shardingsphere/pull/38883)
 1. Encrypt: Support SqlServer update statement for Specifying a table alias as 
the target object when use encrypt feature - 
[#38733](https://github.com/apache/shardingsphere/pull/38733)
+1. Encrypt: Support SqlServer update statement for Specifying a view as the 
target object when use encrypt feature - 
[#38896](https://github.com/apache/shardingsphere/pull/38896)
 1. Sharding: Fix HASH_MOD routing mismatch for same negative numeric values 
across numeric Java types with compatibility switch 
`normalize-numeric-int-range` - 
[#38327](https://github.com/apache/shardingsphere/pull/38327)
 1. Proxy Native: Support building Proxy Native via GraalVM CE for JDK 25 - 
[#38682](https://github.com/apache/shardingsphere/pull/38682)
 
diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
index 4401420576d..cd2217843d2 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
@@ -255,6 +255,9 @@ public final class EncryptProjectionTokenGenerator {
         if (null == subqueryType || SubqueryType.PROJECTION == subqueryType) {
             return Collections.singleton(generateProjection(encryptColumn, 
columnProjection));
         }
+        if (SubqueryType.VIEW_DEFINITION == subqueryType) {
+            return 
Collections.singleton(generateViewDefinitionProjection(encryptColumn, 
columnProjection));
+        }
         if (SubqueryType.TABLE == subqueryType || SubqueryType.JOIN == 
subqueryType || SubqueryType.WITH == subqueryType) {
             return generateProjectionsInTableSegmentSubquery(encryptColumn, 
columnProjection);
         }
@@ -277,6 +280,14 @@ public final class EncryptProjectionTokenGenerator {
                 databaseType, 
columnProjection.getLeftParentheses().orElse(null), 
columnProjection.getRightParentheses().orElse(null));
     }
     
+    private ColumnProjection generateViewDefinitionProjection(final 
EncryptColumn encryptColumn, final ColumnProjection columnProjection) {
+        String encryptColumnName = getEncryptColumnName(columnProjection, 
encryptColumn);
+        QuoteCharacter quoteCharacter = getQuoteCharacter(columnProjection);
+        IdentifierValue cipherColumnName = new 
IdentifierValue(encryptColumnName, quoteCharacter);
+        return new ColumnProjection(columnProjection.getOwner().orElse(null), 
cipherColumnName, null,
+                databaseType, 
columnProjection.getLeftParentheses().orElse(null), 
columnProjection.getRightParentheses().orElse(null));
+    }
+    
     private QuoteCharacter getQuoteCharacter(final ColumnProjection 
columnProjection) {
         return TableSourceType.PHYSICAL_TABLE == 
columnProjection.getColumnBoundInfo().getTableSourceType()
                 ? dialectDatabaseMetaData.getQuoteCharacter()
diff --git 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java
 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java
index dd228f77ead..e35330b0f86 100644
--- 
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java
+++ 
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptSelectProjectionTokenGenerator.java
@@ -22,13 +22,17 @@ import lombok.Setter;
 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
 import org.apache.shardingsphere.infra.annotation.HighFrequencyInvocation;
 import 
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
+import 
org.apache.shardingsphere.infra.binder.context.statement.type.ddl.AlterViewStatementContext;
+import 
org.apache.shardingsphere.infra.binder.context.statement.type.ddl.CreateViewStatementContext;
 import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectStatementContext;
 import 
org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.CollectionSQLTokenGenerator;
 import 
org.apache.shardingsphere.infra.rewrite.sql.token.common.generator.aware.PreviousSQLTokensAware;
 import org.apache.shardingsphere.infra.rewrite.sql.token.common.pojo.SQLToken;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * Select projection token generator for encrypt.
@@ -36,7 +40,7 @@ import java.util.List;
 @HighFrequencyInvocation
 @RequiredArgsConstructor
 @Setter
-public final class EncryptSelectProjectionTokenGenerator implements 
CollectionSQLTokenGenerator<SelectStatementContext>, PreviousSQLTokensAware {
+public final class EncryptSelectProjectionTokenGenerator implements 
CollectionSQLTokenGenerator<SQLStatementContext>, PreviousSQLTokensAware {
     
     private final EncryptRule rule;
     
@@ -44,11 +48,26 @@ public final class EncryptSelectProjectionTokenGenerator 
implements CollectionSQ
     
     @Override
     public boolean isGenerateSQLToken(final SQLStatementContext 
sqlStatementContext) {
-        return sqlStatementContext instanceof SelectStatementContext && 
!sqlStatementContext.getTablesContext().getSimpleTables().isEmpty();
+        return extractSelectStatementContext(sqlStatementContext).map(each -> 
!each.getTablesContext().getSimpleTables().isEmpty()).orElse(false);
     }
     
     @Override
-    public Collection<SQLToken> generateSQLTokens(final SelectStatementContext 
sqlStatementContext) {
-        return new EncryptProjectionTokenGenerator(previousSQLTokens, 
sqlStatementContext.getSqlStatement().getDatabaseType(), 
rule).generateSQLTokens(sqlStatementContext);
+    public Collection<SQLToken> generateSQLTokens(final SQLStatementContext 
sqlStatementContext) {
+        return extractSelectStatementContext(sqlStatementContext)
+                .map(each -> new 
EncryptProjectionTokenGenerator(previousSQLTokens, 
each.getSqlStatement().getDatabaseType(), rule).generateSQLTokens(each))
+                .orElse(Collections.emptyList());
+    }
+    
+    private Optional<SelectStatementContext> 
extractSelectStatementContext(final SQLStatementContext sqlStatementContext) {
+        if (sqlStatementContext instanceof SelectStatementContext) {
+            return Optional.of((SelectStatementContext) sqlStatementContext);
+        }
+        if (sqlStatementContext instanceof CreateViewStatementContext) {
+            return Optional.of(((CreateViewStatementContext) 
sqlStatementContext).getSelectStatementContext());
+        }
+        if (sqlStatementContext instanceof AlterViewStatementContext) {
+            return ((AlterViewStatementContext) 
sqlStatementContext).getSelectStatementContext();
+        }
+        return Optional.empty();
     }
 }
diff --git 
a/test/it/rewriter/src/test/java/org/apache/shardingsphere/test/it/rewriter/engine/scenario/EncryptSQLRewriterIT.java
 
b/test/it/rewriter/src/test/java/org/apache/shardingsphere/test/it/rewriter/engine/scenario/EncryptSQLRewriterIT.java
index e323e87eeb1..578272e7b8b 100644
--- 
a/test/it/rewriter/src/test/java/org/apache/shardingsphere/test/it/rewriter/engine/scenario/EncryptSQLRewriterIT.java
+++ 
b/test/it/rewriter/src/test/java/org/apache/shardingsphere/test/it/rewriter/engine/scenario/EncryptSQLRewriterIT.java
@@ -17,6 +17,7 @@
 
 package org.apache.shardingsphere.test.it.rewriter.engine.scenario;
 
+import 
org.apache.shardingsphere.database.connector.core.metadata.database.enums.TableType;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereColumn;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
@@ -82,6 +83,12 @@ class EncryptSQLRewriterIT extends SQLRewriterIT {
                 new ShardingSphereColumn("WorkOrderID", Types.INTEGER, false, 
false, false, true, false, false),
                 new ShardingSphereColumn("ScrapReasonID", Types.INTEGER, 
false, false, false, true, false, false),
                 new ShardingSphereColumn("ScrappedQty", Types.INTEGER, false, 
false, false, true, false, false)), Collections.emptyList(), 
Collections.emptyList()));
+        tables.add(new ShardingSphereTable("StateRegion", Arrays.asList(
+                new ShardingSphereColumn("StateCode", Types.INTEGER, false, 
false, false, true, false, false),
+                new ShardingSphereColumn("CountryRegionName", Types.VARCHAR, 
false, false, false, true, false, false)), Collections.emptyList(), 
Collections.emptyList()));
+        tables.add(new ShardingSphereTable("vStateProvinceCountryRegion", 
Arrays.asList(
+                new ShardingSphereColumn("StateCode", Types.INTEGER, false, 
false, false, true, false, false),
+                new ShardingSphereColumn("CountryRegionName", Types.VARCHAR, 
false, false, false, true, false, false)), Collections.emptyList(), 
Collections.emptyList(), TableType.VIEW));
         return Collections.singleton(new ShardingSphereSchema(schemaName, 
mock(DatabaseType.class), tables, Collections.emptyList()));
     }
     
@@ -96,6 +103,8 @@ class EncryptSQLRewriterIT extends SQLRewriterIT {
             
singleRule.get().getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).put("encrypt_ds",
 schemaName, "t_user");
             
singleRule.get().getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).put("encrypt_ds",
 schemaName, "ScrapReason");
             
singleRule.get().getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).put("encrypt_ds",
 schemaName, "WorkOrder");
+            
singleRule.get().getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).put("encrypt_ds",
 schemaName, "StateRegion");
+            
singleRule.get().getAttributes().getAttribute(MutableDataNodeRuleAttribute.class).put("encrypt_ds",
 schemaName, "vStateProvinceCountryRegion");
         }
     }
 }
diff --git 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/alter/alter-view.xml
 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/alter/alter-view.xml
new file mode 100644
index 00000000000..2901799857f
--- /dev/null
+++ 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/alter/alter-view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<rewrite-assertions yaml-rule="scenario/encrypt/config/query-with-cipher.yaml">
+    <rewrite-assertion 
id="alter_view_state_province_country_region_for_literals" db-types="SQLServer">
+        <input sql="ALTER VIEW dbo.vStateProvinceCountryRegion AS SELECT 
StateCode, CountryRegionName FROM dbo.StateRegion" />
+        <output sql="ALTER VIEW dbo.vStateProvinceCountryRegion AS SELECT 
StateCode, [country_region_name_cipher] FROM dbo.StateRegion" />
+    </rewrite-assertion>
+</rewrite-assertions>
diff --git 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/create/create-view.xml
 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/create/create-view.xml
new file mode 100644
index 00000000000..d6c02711913
--- /dev/null
+++ 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/ddl/create/create-view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<rewrite-assertions yaml-rule="scenario/encrypt/config/query-with-cipher.yaml">
+    <rewrite-assertion 
id="create_view_state_province_country_region_for_literals" 
db-types="SQLServer">
+        <input sql="/* SHARDINGSPHERE_HINT: SKIP_METADATA_VALIDATE=true */ 
CREATE VIEW dbo.vStateProvinceCountryRegion AS SELECT StateCode, 
CountryRegionName FROM dbo.StateRegion" />
+        <output sql="CREATE VIEW dbo.vStateProvinceCountryRegion AS SELECT 
StateCode, [country_region_name_cipher] FROM dbo.StateRegion" />
+    </rewrite-assertion>
+</rewrite-assertions>
diff --git 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/update/update.xml
 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/update/update.xml
index 161e1d6ca7d..58b3a11388b 100644
--- 
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/update/update.xml
+++ 
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/update/update.xml
@@ -104,4 +104,9 @@
         <input sql="UPDATE ScrapReason AS sr SET Name = Name || ' - tool 
malfunction', Remark = 'tool malfunction' FROM WorkOrder AS wo WHERE 
sr.ScrapReasonID = wo.ScrapReasonID AND wo.ScrappedQty &gt; 300" />
         <output sql="UPDATE ScrapReason AS sr SET Name = Name || ' - tool 
malfunction', &quot;remark_cipher&quot; = 'encrypt_tool malfunction' FROM 
WorkOrder AS wo WHERE sr.ScrapReasonID = wo.ScrapReasonID AND wo.ScrappedQty 
&gt; 300" />
     </rewrite-assertion>
+
+    <rewrite-assertion 
id="update_state_province_country_region_view_for_literals" 
db-types="SQLServer">
+        <input sql="UPDATE dbo.vStateProvinceCountryRegion SET 
CountryRegionName = 'United States of America' WHERE CountryRegionName = 
'United States'" />
+        <output sql="UPDATE dbo.vStateProvinceCountryRegion SET 
[country_region_name_cipher] = 'encrypt_United States of America' WHERE 
[country_region_name_cipher] = 'encrypt_United States'" />
+    </rewrite-assertion>
 </rewrite-assertions>
diff --git 
a/test/it/rewriter/src/test/resources/scenario/encrypt/config/query-with-cipher.yaml
 
b/test/it/rewriter/src/test/resources/scenario/encrypt/config/query-with-cipher.yaml
index 5c047405ec9..ee2b6060f50 100644
--- 
a/test/it/rewriter/src/test/resources/scenario/encrypt/config/query-with-cipher.yaml
+++ 
b/test/it/rewriter/src/test/resources/scenario/encrypt/config/query-with-cipher.yaml
@@ -158,6 +158,18 @@ rules:
           cipher:
             name: remark_cipher
             encryptorName: rewrite_normal_fixture
+    StateRegion:
+      columns:
+        CountryRegionName:
+          cipher:
+            name: country_region_name_cipher
+            encryptorName: rewrite_normal_fixture
+    vStateProvinceCountryRegion:
+      columns:
+        CountryRegionName:
+          cipher:
+            name: country_region_name_cipher
+            encryptorName: rewrite_normal_fixture
   encryptors:
     rewrite_normal_fixture:
       type: REWRITE.NORMAL.FIXTURE

Reply via email to