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

Gabriel39 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new ccf23fa479d [fix](fe) Preserve legacy HA catalogs during ALTER (#68697)
ccf23fa479d is described below

commit ccf23fa479d64d47e6050b249652a1e428cd31d5
Author: Oliveira <[email protected]>
AuthorDate: Fri Oct 9 09:41:58 2026 +0800

    [fix](fe) Preserve legacy HA catalogs during ALTER (#68697)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Related PR: #68585
    
    Problem Summary: A legacy HMS catalog can contain an empty HDFS
    nameservice list, such as `dfs.nameservices=,`. Runtime binding
    tolerates this persisted value, but ALTER validation checked the merged
    catalog properties and rejected even an unrelated statement such as
    `ALTER CATALOG ... SET PROPERTIES ("test_connection"="false")`.
    
    Validate empty nameservice values against the properties submitted by
    the current statement. CREATE and ALTER still reject explicitly
    submitted empty values, while unrelated ALTERs preserve legacy values.
    The complete merged configuration continues through storage binding and
    HA validation.
    
    ### Release note
    
    Allow unrelated property changes on legacy Hive catalogs containing an
    empty HDFS nameservice list.
    
    ### Check List (For Author)
    
    - Test
        - [x] Unit Test
    - Added `PluginDrivenExternalCatalogConcurrencyTest` coverage for legacy
    comma-only, whitespace, and empty-string nameservice values during
    unrelated ALTERs, and explicit CREATE/ALTER rejection of these values.
    - Community FE UT and COMPILE passed on commit
    `2fcc2ef6e0c93582414a50037394f094012f34f9`.
    - Local focused FE UT compiled and reached execution, but all 18 tests
    failed during Mockito initialization because the inline mock maker could
    not self-attach. This local run is not counted as passing.
        - [x] Regression test
    - Community External, P0, NonConcurrent, Cloud P0, and Vault P0 checks
    passed on the same commit. No new regression suite was added; the legacy
    persisted-property case is covered by FE unit tests.
    
    - Behavior changed:
        - [ ] No.
    - [x] Yes. Unrelated ALTERs accept legacy empty nameservice values;
    explicitly submitted empty values remain rejected.
    
    - Does this need documentation?
        - [x] No.
        - [ ] Yes.
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label
---
 .../plugin/PluginDrivenExternalCatalog.java        | 12 ++++----
 ...PluginDrivenExternalCatalogConcurrencyTest.java | 33 ++++++++++++++++++++++
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
index 2a877d26b20..11e13d25969 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalog.java
@@ -232,7 +232,7 @@ public class PluginDrivenExternalCatalog extends 
ExternalCatalog {
         } catch (IllegalArgumentException e) {
             throw new DdlException(e.getMessage());
         }
-        validateStorageProperties(catalogProperty);
+        validateStorageProperties(catalogProperty, 
catalogProperty.getProperties());
         // Validate function_rules JSON if present (shared across all 
connector types).
         String functionRules = catalogProperty.getOrDefault("function_rules", 
null);
         ExternalFunctionRules.check(functionRules);
@@ -256,7 +256,7 @@ public class PluginDrivenExternalCatalog extends 
ExternalCatalog {
         } catch (IllegalArgumentException e) {
             throw new DdlException(e.getMessage(), e);
         }
-        validateStorageProperties(candidateProperty);
+        validateStorageProperties(candidateProperty, updatedProperties);
         checkDriverUrlsAgainstOperatorGate(candidate, updatedProperties);
         
ExternalFunctionRules.check(candidateProperty.getOrDefault("function_rules", 
null));
         return true;
@@ -266,13 +266,15 @@ public class PluginDrivenExternalCatalog extends 
ExternalCatalog {
      * Bind Hive catalog storage properties during DDL validation so HDFS 
configuration errors are
      * reported by CREATE/ALTER instead of being deferred until the first 
table access.
      */
-    private void validateStorageProperties(CatalogProperty property) throws 
DdlException {
+    private void validateStorageProperties(CatalogProperty property, 
Map<String, String> submittedProperties)
+            throws DdlException {
         if (!"hms".equalsIgnoreCase(getType())) {
             return;
         }
-        String nameservices = property.getProperties().get("dfs.nameservices");
+        // Reject newly submitted empty values without blocking unrelated 
ALTERs of legacy catalogs.
+        String nameservices = submittedProperties.get("dfs.nameservices");
         if (nameservices != null
-                && java.util.Arrays.stream(nameservices.split(","))
+                && Arrays.stream(nameservices.split(","))
                 .map(String::trim).noneMatch(value -> !value.isEmpty())) {
             throw new DdlException("Property dfs.nameservices must contain a 
nameservice");
         }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
index 2896ac58f58..18a0e80c899 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/plugin/PluginDrivenExternalCatalogConcurrencyTest.java
@@ -123,6 +123,39 @@ public class PluginDrivenExternalCatalogConcurrencyTest {
         
Assertions.assertTrue(exception.getMessage().contains("dfs.ha.namenodes.ns1"), 
exception.getMessage());
     }
 
+    @Test
+    public void testAlterPreservesLegacyEmptyNameservices() throws Exception {
+        for (String nameservices : new String[] {",", " ", ""}) {
+            Map<String, String> properties = hiveCatalogProperties();
+            properties.put("dfs.nameservices", nameservices);
+            PluginDrivenExternalCatalog catalog = new 
PluginDrivenExternalCatalog(
+                    1L, "test-catalog", null, properties, "", null);
+
+            
Assertions.assertTrue(catalog.validatePropertiesBeforeUpdate(properties,
+                    Collections.singletonMap("test_connection", "false")));
+            Assertions.assertEquals(nameservices, 
catalog.getProperties().get("dfs.nameservices"));
+        }
+    }
+
+    @Test
+    public void testDdlRejectsSubmittedEmptyNameservices() {
+        for (String nameservices : new String[] {",", " ", ""}) {
+            Map<String, String> properties = hiveCatalogProperties();
+            PluginDrivenExternalCatalog catalog = new 
PluginDrivenExternalCatalog(
+                    1L, "test-catalog", null, properties, "", null);
+            DdlException alterException = 
Assertions.assertThrows(DdlException.class,
+                    () -> catalog.validatePropertiesBeforeUpdate(properties,
+                            Collections.singletonMap("dfs.nameservices", 
nameservices)));
+            
Assertions.assertTrue(alterException.getMessage().contains("dfs.nameservices"));
+
+            properties.put("dfs.nameservices", nameservices);
+            PluginDrivenExternalCatalog createCatalog = new 
PluginDrivenExternalCatalog(
+                    2L, "create-catalog", null, properties, "", null);
+            DdlException createException = 
Assertions.assertThrows(DdlException.class, createCatalog::checkProperties);
+            
Assertions.assertTrue(createException.getMessage().contains("dfs.nameservices"));
+        }
+    }
+
     private static Map<String, String> hiveCatalogProperties() {
         Map<String, String> properties = new HashMap<>();
         properties.put("type", "hms");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to