You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/06/24 13:06:12 UTC
(shardingsphere) branch master updated: Support SqlServer update statement for Specifying a view as the target object when use encrypt feature (#38896)
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 <cl...@163.com>
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 > 300" />
<output sql="UPDATE ScrapReason AS sr SET Name = Name || ' - tool malfunction', "remark_cipher" = 'encrypt_tool malfunction' FROM WorkOrder AS wo WHERE sr.ScrapReasonID = wo.ScrapReasonID AND wo.ScrappedQty > 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