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

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 32369a90d71 branch-4.0: [fix](iceberg) fix logic of getting namespaces 
#56874 (#57021)
32369a90d71 is described below

commit 32369a90d71f8e8b082de4e401c60e2262c3c413
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Oct 16 18:00:17 2025 +0800

    branch-4.0: [fix](iceberg) fix logic of getting namespaces #56874 (#57021)
    
    Cherry-picked from #56874
    
    Co-authored-by: Mingyu Chen (Rayner) <[email protected]>
---
 .../datasource/iceberg/IcebergMetadataOps.java     | 28 +++++++++----
 .../property/metastore/IcebergRestProperties.java  | 10 ++---
 .../datasource/iceberg/IcebergMetadataOpTest.java  | 48 ++++++++++++++++++++++
 .../metastore/IcebergRestPropertiesTest.java       |  4 +-
 4 files changed, 74 insertions(+), 16 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 d722183caf9..39e7d840e4a 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
@@ -43,6 +43,8 @@ import 
org.apache.doris.nereids.trees.plans.commands.info.DropBranchInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.DropTagInfo;
 import org.apache.doris.nereids.trees.plans.commands.info.TagOptions;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Splitter;
 import org.apache.commons.lang3.exception.ExceptionUtils;
 import org.apache.iceberg.ManageSnapshots;
 import org.apache.iceberg.PartitionSpec;
@@ -66,6 +68,7 @@ import org.apache.logging.log4j.Logger;
 import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -794,7 +797,8 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         }
         try {
             ViewCatalog viewCatalog = (ViewCatalog) catalog;
-            return executionAuthenticator.execute(() -> 
viewCatalog.loadView(TableIdentifier.of(dbName, tblName)));
+            return executionAuthenticator.execute(
+                    () -> 
viewCatalog.loadView(TableIdentifier.of(getNamespace(dbName), tblName)));
         } catch (Exception e) {
             throw new RuntimeException("Failed to load view, error message 
is:" + e.getMessage(), e);
         }
@@ -807,7 +811,7 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
         }
         try {
             return executionAuthenticator.execute(() ->
-                ((ViewCatalog) catalog).listViews(Namespace.of(db))
+                    ((ViewCatalog) catalog).listViews(getNamespace(db))
                     
.stream().map(TableIdentifier::name).collect(Collectors.toList()));
         } catch (Exception e) {
             throw new RuntimeException("Failed to list view names, error 
message is:" + e.getMessage(), e);
@@ -815,15 +819,22 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
     }
 
     private TableIdentifier getTableIdentifier(String dbName, String tblName) {
-        return externalCatalogName
-            .map(s -> TableIdentifier.of(s, dbName, tblName))
-            .orElseGet(() -> TableIdentifier.of(dbName, tblName));
+        Namespace ns = getNamespace(dbName);
+        return TableIdentifier.of(ns, tblName);
     }
 
     private Namespace getNamespace(String dbName) {
-        return externalCatalogName
-            .map(s -> Namespace.of(s, dbName))
-            .orElseGet(() -> Namespace.of(dbName));
+        return getNamespace(externalCatalogName, dbName);
+    }
+
+    @VisibleForTesting
+    public static Namespace getNamespace(Optional<String> catalogName, String 
dbName) {
+        String[] splits = 
Splitter.on(".").omitEmptyStrings().trimResults().splitToList(dbName).toArray(new
 String[0]);
+        if (catalogName.isPresent()) {
+            splits = Arrays.copyOf(splits, splits.length + 1);
+            splits[splits.length - 1] = catalogName.get();
+        }
+        return Namespace.of(splits);
     }
 
     private Namespace getNamespace() {
@@ -843,3 +854,4 @@ public class IcebergMetadataOps implements 
ExternalMetadataOps {
     }
 }
 
+
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 3110745b91e..b899116a1a8 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
@@ -200,11 +200,7 @@ public class IcebergRestProperties extends 
AbstractIcebergProperties {
         ParamRules rules = new ParamRules()
                 // OAuth2 requires either credential or token, but not both
                 .mutuallyExclusive(icebergRestOauth2Credential, 
icebergRestOauth2Token,
-                        "OAuth2 cannot have both credential and token 
configured")
-                // If using credential flow, server URI is required
-                .requireAllIfPresent(icebergRestOauth2Credential,
-                        new String[] {icebergRestOauth2ServerUri},
-                        "OAuth2 credential flow requires server-uri");
+                        "OAuth2 cannot have both credential and token 
configured");
 
         // Custom validation: OAuth2 scope should not be used with token
         if (Strings.isNotBlank(icebergRestOauth2Token) && 
Strings.isNotBlank(icebergRestOauth2Scope)) {
@@ -274,7 +270,9 @@ public class IcebergRestProperties extends 
AbstractIcebergProperties {
         if (Strings.isNotBlank(icebergRestOauth2Credential)) {
             // Client Credentials Flow
             icebergRestCatalogProperties.put(OAuth2Properties.CREDENTIAL, 
icebergRestOauth2Credential);
-            
icebergRestCatalogProperties.put(OAuth2Properties.OAUTH2_SERVER_URI, 
icebergRestOauth2ServerUri);
+            if (Strings.isNotBlank(icebergRestOauth2ServerUri)) {
+                
icebergRestCatalogProperties.put(OAuth2Properties.OAUTH2_SERVER_URI, 
icebergRestOauth2ServerUri);
+            }
             if (Strings.isNotBlank(icebergRestOauth2Scope)) {
                 icebergRestCatalogProperties.put(OAuth2Properties.SCOPE, 
icebergRestOauth2Scope);
             }
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
new file mode 100644
index 00000000000..3ecdb9ce437
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/iceberg/IcebergMetadataOpTest.java
@@ -0,0 +1,48 @@
+// 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.
+
+package org.apache.doris.datasource.iceberg;
+
+import org.apache.iceberg.catalog.Namespace;
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+
+import java.util.Optional;
+
+public class IcebergMetadataOpTest {
+
+    @Test
+    public void testGetNamespaces() {
+        Namespace ns = IcebergMetadataOps.getNamespace(Optional.empty(), 
"db1");
+        Assert.assertEquals(1, ns.length());
+
+        ns = IcebergMetadataOps.getNamespace(Optional.empty(), "db1.db2.db3");
+        Assert.assertEquals(3, ns.length());
+
+        ns = IcebergMetadataOps.getNamespace(Optional.empty(), "db1..db2");
+        Assert.assertEquals(2, ns.length());
+
+        ns = IcebergMetadataOps.getNamespace(Optional.of("p1"), "db1");
+        Assert.assertEquals(2, ns.length());
+
+        ns = IcebergMetadataOps.getNamespace(Optional.of("p1"), "");
+        Assert.assertEquals(1, ns.length());
+
+        ns = IcebergMetadataOps.getNamespace(Optional.empty(), "");
+        Assert.assertEquals(0, ns.length());
+    }
+}
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 d1199df2ae6..226f6dd6551 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
@@ -131,14 +131,14 @@ public class IcebergRestPropertiesTest {
         IcebergRestProperties restProps2 = new IcebergRestProperties(props2);
         Assertions.assertThrows(IllegalArgumentException.class, 
restProps2::initNormalizeAndCheckProps);
 
-        // Test: credential flow without server URI
+        // Test: credential flow without server URI is ok
         Map<String, String> props3 = new HashMap<>();
         props3.put("iceberg.rest.uri", "http://localhost:8080";);
         props3.put("iceberg.rest.security.type", "oauth2");
         props3.put("iceberg.rest.oauth2.credential", "client_credentials");
 
         IcebergRestProperties restProps3 = new IcebergRestProperties(props3);
-        Assertions.assertThrows(IllegalArgumentException.class, 
restProps3::initNormalizeAndCheckProps);
+        Assertions.assertDoesNotThrow(restProps3::initNormalizeAndCheckProps);
 
         // Test: scope with token (should fail)
         Map<String, String> props4 = new HashMap<>();


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

Reply via email to