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]