This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 79d975d1ccd branch-4.1: [fix](iceberg) Allow disabling REST catalog
view operations (#63320)
79d975d1ccd is described below
commit 79d975d1ccda77745dafbbfe795504809abc7221
Author: Chenjunwei <[email protected]>
AuthorDate: Wed Jun 24 10:55:45 2026 +0800
branch-4.1: [fix](iceberg) Allow disabling REST catalog view operations
(#63320)
### What problem does this PR solve?
Issue Number: None
Related PR: #62986
Problem Summary: Backport #62986 to branch-4.1. This allows Iceberg REST
catalog users to disable view operations with
`iceberg.rest.view-enabled=false` when the REST catalog does not support
view endpoints. The default remains enabled.
### Release note
Add `iceberg.rest.view-enabled` for Iceberg REST catalog. It defaults to
true and can be set to false to skip view operations.
### Check List (For Author)
- Test <!-- At least one of them must be included. -->
- [ ] Regression test
- [x] Unit Test
- [ ] Manual test (add detailed scripts or steps below)
- [ ] No need to test or manual test. Explain why:
- [ ] This is a refactor/code format and no logic has been changed.
- [ ] Previous test can cover this change.
- [ ] No code files have been changed.
- [ ] Other reason <!-- Add your reason? -->
- Behavior changed:
- [ ] No.
- [x] Yes. Add an opt-out switch for Iceberg REST catalog view
operations; default behavior is unchanged.
- Does this need documentation?
- [x] No.
- [ ] Yes. <!-- Add document PR link here. eg:
https://github.com/apache/doris-website/pull/1214 -->
### Check List (For Reviewer who merge this PR)
- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label <!-- Add branch pick label that this PR
should merge into -->
### Test
- `MAVEN_OPTS='-Xmx4g -XX:MaxMetaspaceSize=1g' FE_UT_PARALLEL=1
./run-fe-ut.sh --run
org.apache.doris.datasource.iceberg.IcebergMetadataOpTest,org.apache.doris.datasource.property.metastore.IcebergRestPropertiesTest`
---
.../datasource/iceberg/IcebergMetadataOps.java | 23 ++++++--
.../property/metastore/IcebergRestProperties.java | 9 +++
.../datasource/iceberg/IcebergMetadataOpTest.java | 69 ++++++++++++++++++++++
.../metastore/IcebergRestPropertiesTest.java | 17 ++++++
4 files changed, 113 insertions(+), 5 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
index d447bf531e8..c08a822ed0f 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/IcebergMetadataOps.java
@@ -193,7 +193,7 @@ public class IcebergMetadataOps implements
ExternalMetadataOps {
// IcebergMetadataOps handles listTableNames and listViewNames
separately.
// listTableNames should only focus on the table type,
// but in reality, Iceberg's return includes views. Therefore,
we added a filter to exclude views.
- if (catalog instanceof ViewCatalog) {
+ if (isViewCatalogEnabled()) {
views = ((ViewCatalog)
catalog).listViews(getNamespace(dbName))
.stream().map(TableIdentifier::name).collect(Collectors.toList());
} else {
@@ -1133,7 +1133,7 @@ public class IcebergMetadataOps implements
ExternalMetadataOps {
@Override
public boolean viewExists(String remoteDbName, String remoteViewName) {
- if (!(catalog instanceof ViewCatalog)) {
+ if (!isViewCatalogEnabled()) {
return false;
}
try {
@@ -1147,7 +1147,7 @@ public class IcebergMetadataOps implements
ExternalMetadataOps {
@Override
public View loadView(String dbName, String tblName) {
- if (!(catalog instanceof ViewCatalog)) {
+ if (!isViewCatalogEnabled()) {
return null;
}
try {
@@ -1161,7 +1161,7 @@ public class IcebergMetadataOps implements
ExternalMetadataOps {
@Override
public List<String> listViewNames(String db) {
- if (!(catalog instanceof ViewCatalog)) {
+ if (!isViewCatalogEnabled()) {
return Collections.emptyList();
}
try {
@@ -1199,12 +1199,25 @@ public class IcebergMetadataOps implements
ExternalMetadataOps {
return externalCatalogName.map(Namespace::of).orElseGet(() ->
Namespace.empty());
}
+ private boolean isViewCatalogEnabled() {
+ if (!(catalog instanceof ViewCatalog)) {
+ return false;
+ }
+ if (dorisCatalog instanceof IcebergRestExternalCatalog) {
+ MetastoreProperties metaProps =
dorisCatalog.getCatalogProperty().getMetastoreProperties();
+ if (metaProps instanceof IcebergRestProperties) {
+ return ((IcebergRestProperties)
metaProps).isIcebergRestViewEnabled();
+ }
+ }
+ return true;
+ }
+
public ThreadPoolExecutor getThreadPoolWithPreAuth() {
return dorisCatalog.getThreadPoolWithPreAuth();
}
private void performDropView(String remoteDbName, String remoteViewName)
throws DdlException {
- if (!(catalog instanceof ViewCatalog)) {
+ if (!isViewCatalogEnabled()) {
throw new DdlException("Drop Iceberg view is not supported with
not view catalog.");
}
ViewCatalog viewCatalog = (ViewCatalog) catalog;
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergRestProperties.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergRestProperties.java
index 407c5c58b3e..f457c90ff40 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergRestProperties.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/metastore/IcebergRestProperties.java
@@ -116,6 +116,11 @@ public class IcebergRestProperties extends
AbstractIcebergProperties {
description = "Enable nested namespace for the iceberg rest
catalog service.")
private String icebergRestNestedNamespaceEnabled = "false";
+ @ConnectorProperty(names = {"iceberg.rest.view-enabled"},
+ required = false,
+ description = "Enable view operations for the iceberg rest catalog
service.")
+ private String icebergRestViewEnabled = "true";
+
@ConnectorProperty(names = {"iceberg.rest.case-insensitive-name-matching"},
required = false,
supported = false,
@@ -371,6 +376,10 @@ public class IcebergRestProperties extends
AbstractIcebergProperties {
return Boolean.parseBoolean(icebergRestNestedNamespaceEnabled);
}
+ public boolean isIcebergRestViewEnabled() {
+ return Boolean.parseBoolean(icebergRestViewEnabled);
+ }
+
public enum Security {
NONE,
OAUTH2,
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergMetadataOpTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergMetadataOpTest.java
index 3ecdb9ce437..2bf1ef3deb4 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergMetadataOpTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergMetadataOpTest.java
@@ -17,10 +17,23 @@
package org.apache.doris.datasource.iceberg;
+import org.apache.doris.common.security.authentication.ExecutionAuthenticator;
+import org.apache.doris.datasource.CatalogProperty;
+
+import org.apache.iceberg.catalog.Catalog;
import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.catalog.SupportsNamespaces;
+import org.apache.iceberg.catalog.TableIdentifier;
+import org.apache.iceberg.catalog.ViewCatalog;
import org.junit.Assert;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Optional;
public class IcebergMetadataOpTest {
@@ -45,4 +58,60 @@ public class IcebergMetadataOpTest {
ns = IcebergMetadataOps.getNamespace(Optional.empty(), "");
Assert.assertEquals(0, ns.length());
}
+
+ @Test
+ public void testListTableNamesSkipsViewsWhenRestViewDisabled() {
+ IcebergRestExternalCatalog dorisCatalog =
Mockito.mock(IcebergRestExternalCatalog.class);
+ Catalog icebergCatalog = Mockito.mock(Catalog.class,
+
Mockito.withSettings().extraInterfaces(SupportsNamespaces.class,
ViewCatalog.class));
+
+ Map<String, String> props = new HashMap<>();
+ props.put("type", "iceberg");
+ props.put("iceberg.catalog.type", "rest");
+ props.put("iceberg.rest.uri", "http://localhost:8181");
+ props.put("iceberg.rest.view-enabled", "false");
+
+ Mockito.when(dorisCatalog.getExecutionAuthenticator()).thenReturn(new
ExecutionAuthenticator() {
+ });
+
Mockito.when(dorisCatalog.getProperties()).thenReturn(Collections.emptyMap());
+ Mockito.when(dorisCatalog.getCatalogProperty()).thenReturn(new
CatalogProperty(null, props));
+
+ Namespace namespace = Namespace.of("PUBLIC");
+ TableIdentifier table = TableIdentifier.of(namespace,
"DORIS_HORIZON_T");
+
Mockito.when(icebergCatalog.listTables(namespace)).thenReturn(Collections.singletonList(table));
+
+ IcebergMetadataOps ops = new IcebergMetadataOps(dorisCatalog,
icebergCatalog);
+ List<String> tableNames = ops.listTableNames("PUBLIC");
+
+ Assert.assertEquals(Collections.singletonList("DORIS_HORIZON_T"),
tableNames);
+ Mockito.verify((ViewCatalog) icebergCatalog,
Mockito.never()).listViews(Mockito.any());
+ }
+
+ @Test
+ public void testListTableNamesFiltersViewsWhenRestViewEnabled() {
+ IcebergRestExternalCatalog dorisCatalog =
Mockito.mock(IcebergRestExternalCatalog.class);
+ Catalog icebergCatalog = Mockito.mock(Catalog.class,
+
Mockito.withSettings().extraInterfaces(SupportsNamespaces.class,
ViewCatalog.class));
+
+ Map<String, String> props = new HashMap<>();
+ props.put("type", "iceberg");
+ props.put("iceberg.catalog.type", "rest");
+ props.put("iceberg.rest.uri", "http://localhost:8181");
+
+ Mockito.when(dorisCatalog.getExecutionAuthenticator()).thenReturn(new
ExecutionAuthenticator() {
+ });
+
Mockito.when(dorisCatalog.getProperties()).thenReturn(Collections.emptyMap());
+ Mockito.when(dorisCatalog.getCatalogProperty()).thenReturn(new
CatalogProperty(null, props));
+
+ Namespace namespace = Namespace.of("PUBLIC");
+ TableIdentifier table = TableIdentifier.of(namespace,
"DORIS_HORIZON_T");
+ TableIdentifier view = TableIdentifier.of(namespace,
"DORIS_HORIZON_V");
+
Mockito.when(icebergCatalog.listTables(namespace)).thenReturn(Arrays.asList(table,
view));
+ Mockito.when(((ViewCatalog)
icebergCatalog).listViews(namespace)).thenReturn(Collections.singletonList(view));
+
+ IcebergMetadataOps ops = new IcebergMetadataOps(dorisCatalog,
icebergCatalog);
+ List<String> tableNames = ops.listTableNames("PUBLIC");
+
+ Assert.assertEquals(Collections.singletonList("DORIS_HORIZON_T"),
tableNames);
+ }
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/IcebergRestPropertiesTest.java
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/IcebergRestPropertiesTest.java
index 47ce0669a6c..cd9820c2722 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/IcebergRestPropertiesTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/metastore/IcebergRestPropertiesTest.java
@@ -83,6 +83,23 @@ public class IcebergRestPropertiesTest {
Assertions.assertFalse(catalogProps.containsKey("header.X-Iceberg-Access-Delegation"));
}
+ @Test
+ public void testRestViewEnabled() {
+ Map<String, String> props = new HashMap<>();
+ props.put("iceberg.rest.uri", "http://localhost:8080");
+
+ IcebergRestProperties defaultProps = new IcebergRestProperties(props);
+ defaultProps.initNormalizeAndCheckProps();
+ Assertions.assertTrue(defaultProps.isIcebergRestViewEnabled());
+
+ props.put("iceberg.rest.view-enabled", "false");
+ IcebergRestProperties disabledProps = new IcebergRestProperties(props);
+ disabledProps.initNormalizeAndCheckProps();
+ Assertions.assertFalse(disabledProps.isIcebergRestViewEnabled());
+ Assertions.assertFalse(disabledProps.getIcebergRestCatalogProperties()
+ .containsKey("iceberg.rest.view-enabled"));
+ }
+
@Test
public void testOAuth2CredentialFlow() {
Map<String, String> props = new HashMap<>();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]