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 05c87d6bbf7 Fix stale encryptors leaking when altering an encrypt rule 
(#39209)
05c87d6bbf7 is described below

commit 05c87d6bbf708f92438ee7d0a9333698e314a86c
Author: Eunbin Son <[email protected]>
AuthorDate: Tue Sep 8 19:16:06 2026 +0900

    Fix stale encryptors leaking when altering an encrypt rule (#39209)
    
    * Fix stale encryptors leaking when altering an encrypt rule
    
    * Match altered encrypt table names case-insensitively when building 
dropped rules
    
    EncryptRule keys its tables through CaseInsensitiveMap and ALTER validation
    uses that key set, but buildToBeDroppedRuleConfiguration excluded replaced
    tables with a case-sensitive list. Altering T_ENCRYPT for a persisted
    t_encrypt therefore kept the old definition alongside the new one, so
    UnusedAlgorithmFinder still saw the assisted and like encryptors as
    referenced and dropped none of them.
---
 RELEASE-NOTES.md                                   |  1 +
 .../handler/update/AlterEncryptRuleExecutor.java   |  8 ++-
 .../update/AlterEncryptRuleExecutorTest.java       | 65 ++++++++++++++++++++++
 3 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 9d27775493f..7b429a9443d 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -83,6 +83,7 @@
 1. Readwrite-splitting: Evaluate inline expressions in data source names of 
rule configuration checker - 
[#39374](https://github.com/apache/shardingsphere/pull/39374)
 1. SQL Federation: Fix SQL Federation pagination binding for long LIMIT 
parameters - [#39237](https://github.com/apache/shardingsphere/pull/39237)
 1. Broadcast: Fix case-sensitive table name lookup in broadcast data node rule 
attribute - [#39153](https://github.com/apache/shardingsphere/pull/39153)
+1. Encrypt: Fix stale encryptors leaking when altering an encrypt rule - 
[#39209](https://github.com/apache/shardingsphere/pull/39209)
 
 ### Enhancements
 
diff --git 
a/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutor.java
 
b/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutor.java
index 6d51c66181c..affd48c5199 100644
--- 
a/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutor.java
+++ 
b/features/encrypt/distsql/handler/src/main/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutor.java
@@ -17,11 +17,13 @@
 
 package org.apache.shardingsphere.encrypt.distsql.handler.update;
 
+import com.cedarsoftware.util.CaseInsensitiveSet;
 import lombok.Setter;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.rdl.rule.spi.database.type.DatabaseRuleAlterExecutor;
 import 
org.apache.shardingsphere.distsql.handler.required.DistSQLExecutorCurrentRuleRequired;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import org.apache.shardingsphere.encrypt.config.EncryptRuleConfiguration;
+import 
org.apache.shardingsphere.encrypt.config.rule.EncryptTableRuleConfiguration;
 import 
org.apache.shardingsphere.encrypt.distsql.handler.converter.EncryptRuleStatementConverter;
 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptRuleSegment;
 import 
org.apache.shardingsphere.encrypt.distsql.statement.AlterEncryptRuleStatement;
@@ -102,7 +104,11 @@ public final class AlterEncryptRuleExecutor implements 
DatabaseRuleAlterExecutor
     
     @Override
     public EncryptRuleConfiguration buildToBeDroppedRuleConfiguration(final 
EncryptRuleConfiguration toBeAlteredRuleConfig) {
-        Collection<String> unusedEncryptor = 
UnusedAlgorithmFinder.findUnusedEncryptor(rule.getConfiguration());
+        Collection<String> toBeAlteredTableNames = new 
CaseInsensitiveSet<>(toBeAlteredRuleConfig.getTables().stream().map(EncryptTableRuleConfiguration::getName).collect(Collectors.toList()));
+        Collection<EncryptTableRuleConfiguration> tables = 
rule.getConfiguration().getTables().stream().filter(each -> 
!toBeAlteredTableNames.contains(each.getName())).collect(Collectors.toList());
+        tables.addAll(toBeAlteredRuleConfig.getTables());
+        EncryptRuleConfiguration toBeCheckedRuleConfig = new 
EncryptRuleConfiguration(tables, rule.getConfiguration().getEncryptors());
+        Collection<String> unusedEncryptor = 
UnusedAlgorithmFinder.findUnusedEncryptor(toBeCheckedRuleConfig);
         Map<String, AlgorithmConfiguration> toBeDroppedEncryptors = new 
HashMap<>(unusedEncryptor.size(), 1F);
         unusedEncryptor.forEach(each -> toBeDroppedEncryptors.put(each, 
rule.getConfiguration().getEncryptors().get(each)));
         return new EncryptRuleConfiguration(Collections.emptyList(), 
toBeDroppedEncryptors);
diff --git 
a/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutorTest.java
 
b/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutorTest.java
index a6ac6fb2068..893f5a5c4a4 100644
--- 
a/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutorTest.java
+++ 
b/features/encrypt/distsql/handler/src/test/java/org/apache/shardingsphere/encrypt/distsql/handler/update/AlterEncryptRuleExecutorTest.java
@@ -21,12 +21,15 @@ import 
org.apache.shardingsphere.database.connector.core.type.DatabaseType;
 import 
org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecuteEngine;
 import org.apache.shardingsphere.distsql.segment.AlgorithmSegment;
 import org.apache.shardingsphere.encrypt.config.EncryptRuleConfiguration;
+import 
org.apache.shardingsphere.encrypt.config.rule.EncryptColumnItemRuleConfiguration;
+import 
org.apache.shardingsphere.encrypt.config.rule.EncryptColumnRuleConfiguration;
 import 
org.apache.shardingsphere.encrypt.config.rule.EncryptTableRuleConfiguration;
 import 
org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnItemSegment;
 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptColumnSegment;
 import org.apache.shardingsphere.encrypt.distsql.segment.EncryptRuleSegment;
 import 
org.apache.shardingsphere.encrypt.distsql.statement.AlterEncryptRuleStatement;
 import org.apache.shardingsphere.encrypt.rule.EncryptRule;
+import 
org.apache.shardingsphere.infra.algorithm.core.config.AlgorithmConfiguration;
 import org.apache.shardingsphere.infra.config.props.ConfigurationProperties;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.MissingRequiredRuleException;
@@ -39,7 +42,9 @@ import org.junit.jupiter.api.Test;
 
 import java.sql.SQLException;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 import java.util.Properties;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -111,6 +116,54 @@ class AlterEncryptRuleExecutorTest {
         assertDoesNotThrow(() -> 
metaDataManagerPersistService.alterRuleConfiguration(any(), 
argThat(this::assertToBeAlteredRuleConfiguration)));
     }
     
+    @Test
+    void 
assertBuildToBeDroppedRuleConfigurationWhenAssistedAndLikeQueriesRemoved() {
+        EncryptRule rule = mock(EncryptRule.class);
+        
when(rule.getConfiguration()).thenReturn(createCurrentRuleConfigurationWithGeneratedEncryptors());
+        AlterEncryptRuleExecutor executor = new AlterEncryptRuleExecutor();
+        executor.setRule(rule);
+        EncryptColumnRuleConfiguration alteredColumn = new 
EncryptColumnRuleConfiguration("user_id", new 
EncryptColumnItemRuleConfiguration("user_cipher", "foo_cipher"));
+        EncryptRuleConfiguration toBeAlteredRuleConfig = new 
EncryptRuleConfiguration(
+                Collections.singleton(new 
EncryptTableRuleConfiguration("t_encrypt", 
Collections.singleton(alteredColumn))), Collections.emptyMap());
+        EncryptRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(toBeAlteredRuleConfig);
+        assertTrue(actual.getTables().isEmpty());
+        assertThat(actual.getEncryptors().size(), is(2));
+        assertTrue(actual.getEncryptors().containsKey("foo_assisted"));
+        assertTrue(actual.getEncryptors().containsKey("foo_like"));
+    }
+    
+    @Test
+    void 
assertBuildToBeDroppedRuleConfigurationWhenAlteredTableNameCaseDiffers() {
+        EncryptRule rule = mock(EncryptRule.class);
+        
when(rule.getConfiguration()).thenReturn(createCurrentRuleConfigurationWithGeneratedEncryptors());
+        AlterEncryptRuleExecutor executor = new AlterEncryptRuleExecutor();
+        executor.setRule(rule);
+        EncryptColumnRuleConfiguration alteredColumn = new 
EncryptColumnRuleConfiguration("user_id", new 
EncryptColumnItemRuleConfiguration("user_cipher", "foo_cipher"));
+        EncryptRuleConfiguration toBeAlteredRuleConfig = new 
EncryptRuleConfiguration(
+                Collections.singleton(new 
EncryptTableRuleConfiguration("T_ENCRYPT", 
Collections.singleton(alteredColumn))), Collections.emptyMap());
+        EncryptRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(toBeAlteredRuleConfig);
+        assertTrue(actual.getTables().isEmpty());
+        assertThat(actual.getEncryptors().size(), is(2));
+        assertTrue(actual.getEncryptors().containsKey("foo_assisted"));
+        assertTrue(actual.getEncryptors().containsKey("foo_like"));
+    }
+    
+    @Test
+    void 
assertBuildToBeDroppedRuleConfigurationWhenColumnDefinitionUnchanged() {
+        EncryptRule rule = mock(EncryptRule.class);
+        
when(rule.getConfiguration()).thenReturn(createCurrentRuleConfigurationWithGeneratedEncryptors());
+        AlterEncryptRuleExecutor executor = new AlterEncryptRuleExecutor();
+        executor.setRule(rule);
+        EncryptColumnRuleConfiguration alteredColumn = new 
EncryptColumnRuleConfiguration("user_id", new 
EncryptColumnItemRuleConfiguration("user_cipher", "foo_cipher"));
+        alteredColumn.setAssistedQuery(new 
EncryptColumnItemRuleConfiguration("user_assisted", "foo_assisted"));
+        alteredColumn.setLikeQuery(new 
EncryptColumnItemRuleConfiguration("user_like", "foo_like"));
+        EncryptRuleConfiguration toBeAlteredRuleConfig = new 
EncryptRuleConfiguration(
+                Collections.singleton(new 
EncryptTableRuleConfiguration("t_encrypt", 
Collections.singleton(alteredColumn))), Collections.emptyMap());
+        EncryptRuleConfiguration actual = 
executor.buildToBeDroppedRuleConfiguration(toBeAlteredRuleConfig);
+        assertTrue(actual.getTables().isEmpty());
+        assertTrue(actual.getEncryptors().isEmpty());
+    }
+    
     private ContextManager mockContextManager(final EncryptRule rule) {
         DatabaseType databaseType = mock(DatabaseType.class);
         ResourceMetaData resourceMetaData = mock(ResourceMetaData.class);
@@ -142,6 +195,18 @@ class AlterEncryptRuleExecutorTest {
         return new EncryptRuleConfiguration(new 
LinkedList<>(Collections.singleton(tableRuleConfig)), Collections.emptyMap());
     }
     
+    private EncryptRuleConfiguration 
createCurrentRuleConfigurationWithGeneratedEncryptors() {
+        EncryptColumnRuleConfiguration columnRuleConfig = new 
EncryptColumnRuleConfiguration("user_id", new 
EncryptColumnItemRuleConfiguration("user_cipher", "foo_cipher"));
+        columnRuleConfig.setAssistedQuery(new 
EncryptColumnItemRuleConfiguration("user_assisted", "foo_assisted"));
+        columnRuleConfig.setLikeQuery(new 
EncryptColumnItemRuleConfiguration("user_like", "foo_like"));
+        Map<String, AlgorithmConfiguration> encryptors = new HashMap<>(3, 1F);
+        encryptors.put("foo_cipher", new AlgorithmConfiguration("MD5", new 
Properties()));
+        encryptors.put("foo_assisted", new AlgorithmConfiguration("MD5", new 
Properties()));
+        encryptors.put("foo_like", new AlgorithmConfiguration("MD5", new 
Properties()));
+        EncryptTableRuleConfiguration tableRuleConfig = new 
EncryptTableRuleConfiguration("t_encrypt", 
Collections.singleton(columnRuleConfig));
+        return new EncryptRuleConfiguration(new 
LinkedList<>(Collections.singleton(tableRuleConfig)), encryptors);
+    }
+    
     private boolean assertToBeDroppedRuleConfiguration(final 
EncryptRuleConfiguration actual) {
         assertTrue(actual.getTables().isEmpty());
         assertTrue(actual.getEncryptors().isEmpty());

Reply via email to