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 e3d752b56c6 branch-4.0: [feat](oss)Support bucket-domain-name #59755 
(#60432)
e3d752b56c6 is described below

commit e3d752b56c65ad5db27548828f408563853d8d3a
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Feb 3 11:12:14 2026 +0800

    branch-4.0: [feat](oss)Support bucket-domain-name #59755 (#60432)
    
    Cherry-picked from #59755
    
    Co-authored-by: Calvin Kirs <[email protected]>
---
 .../datasource/property/storage/OSSProperties.java | 77 ++++++++++++++++++++++
 .../property/storage/OSSPropertiesTest.java        |  8 +++
 .../test_s3_tvf_s3_storage.groovy                  |  4 +-
 .../hive_on_hms_and_dlf.groovy                     |  8 +++
 .../iceberg_on_hms_and_filesystem_and_dlf.groovy   | 14 ++++
 5 files changed, 110 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
index 0cb87f9b305..c5802496c57 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/property/storage/OSSProperties.java
@@ -17,9 +17,11 @@
 
 package org.apache.doris.datasource.property.storage;
 
+import org.apache.doris.common.UserException;
 import org.apache.doris.datasource.property.ConnectorPropertiesUtils;
 import org.apache.doris.datasource.property.ConnectorProperty;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import lombok.Getter;
 import lombok.Setter;
@@ -28,6 +30,8 @@ import org.apache.commons.lang3.StringUtils;
 import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider;
 import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
 
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -255,6 +259,11 @@ public class OSSProperties extends 
AbstractS3CompatibleProperties {
         super.setEndpointIfPossible();
     }
 
+    @Override
+    public String validateAndNormalizeUri(String uri) throws UserException {
+        return super.validateAndNormalizeUri(rewriteOssBucketIfNecessary(uri));
+    }
+
     @Override
     public void initNormalizeAndCheckProps() {
         super.initNormalizeAndCheckProps();
@@ -303,4 +312,72 @@ public class OSSProperties extends 
AbstractS3CompatibleProperties {
         hadoopStorageConfig.set("fs.oss.accessKeySecret", secretKey);
         hadoopStorageConfig.set("fs.oss.endpoint", endpoint);
     }
+
+    /**
+     * Rewrites the bucket part of an OSS URI if the bucket is specified
+     * in the form of bucket.endpoint. 
https://help.aliyun.com/zh/oss/user-guide/access-oss-via-bucket-domain-name
+     *
+     * <p>This method is designed for OSS usage, but it also supports
+     * the {@code s3://} scheme since OSS URIs are sometimes written
+     * using the S3-style scheme.</p>
+     *
+     * <p>HTTP and HTTPS URIs are returned unchanged.</p>
+     *
+     * <p>Examples:
+     * <pre>
+     *   oss://bucket.endpoint/path  -> oss://bucket/path
+     *   s3://bucket.endpoint        -> s3://bucket
+     *   https://bucket.endpoint     -> unchanged
+     * </pre>
+     *
+     * @param uri the original URI string
+     * @return the rewritten URI string, or the original URI if no rewrite is 
needed
+     */
+    @VisibleForTesting
+    protected static String rewriteOssBucketIfNecessary(String uri) {
+        if (uri == null || uri.isEmpty()) {
+            return uri;
+        }
+
+        URI parsed;
+        try {
+            parsed = URI.create(uri);
+        } catch (IllegalArgumentException e) {
+            // Invalid URI, do not rewrite
+            return uri;
+        }
+
+        String scheme = parsed.getScheme();
+        if ("http".equalsIgnoreCase(scheme) || 
"https".equalsIgnoreCase(scheme)) {
+            return uri;
+        }
+
+        // For non-standard schemes (oss / s3), authority is more reliable 
than host
+        String authority = parsed.getAuthority();
+        if (authority == null || authority.isEmpty()) {
+            return uri;
+        }
+
+        // Handle bucket.endpoint format
+        int dotIndex = authority.indexOf('.');
+        if (dotIndex <= 0) {
+            return uri;
+        }
+
+        String bucket = authority.substring(0, dotIndex);
+
+        try {
+            URI rewritten = new URI(
+                    scheme,
+                    bucket,
+                    parsed.getPath(),
+                    parsed.getQuery(),
+                    parsed.getFragment()
+            );
+            return rewritten.toString();
+        } catch (URISyntaxException e) {
+            // Be conservative: fallback to original URI
+            return uri;
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
index dbf34751742..4be6414ae01 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/property/storage/OSSPropertiesTest.java
@@ -269,4 +269,12 @@ public class OSSPropertiesTest {
         
Assertions.assertFalse(s3Properties.hadoopStorageConfig.getBoolean("fs.oss.impl.disable.cache",
 false));
     }
 
+    @Test
+    public void testOSSBucketEndpointPathProperties() throws UserException {
+        Assertions.assertEquals("oss://my-bucket/path/to/dir/", 
OSSProperties.rewriteOssBucketIfNecessary("oss://my-bucket/path/to/dir/"));
+        Assertions.assertEquals("oss://my-bucket/path/to/dir/file.txt", 
OSSProperties.rewriteOssBucketIfNecessary("oss://my-bucket.oss-cn-hangzhou.aliyuncs.com/path/to/dir/file.txt"));
+        Assertions.assertEquals("s3://my-bucket/path/to/dir/file.txt", 
OSSProperties.rewriteOssBucketIfNecessary("s3://my-bucket.oss-cn-hangzhou.aliyuncs.com/path/to/dir/file.txt"));
+        
Assertions.assertEquals("https://bucket-name.oss-cn-hangzhou.aliyuncs.com/path/to/dir/file.txt";,
 
OSSProperties.rewriteOssBucketIfNecessary("https://bucket-name.oss-cn-hangzhou.aliyuncs.com/path/to/dir/file.txt";));
+    }
 }
+
diff --git 
a/regression-test/suites/external_table_p0/refactor_storage_param/test_s3_tvf_s3_storage.groovy
 
b/regression-test/suites/external_table_p0/refactor_storage_param/test_s3_tvf_s3_storage.groovy
index f8025733298..490e4eb48d1 100644
--- 
a/regression-test/suites/external_table_p0/refactor_storage_param/test_s3_tvf_s3_storage.groovy
+++ 
b/regression-test/suites/external_table_p0/refactor_storage_param/test_s3_tvf_s3_storage.groovy
@@ -176,7 +176,7 @@ suite("test_s3_tvf_s3_storage", 
"p0,external,external_docker") {
         ak = context.config.otherConfigs.get("aliYunAk")
         sk = context.config.otherConfigs.get("aliYunSk")
         s3_endpoint = 
getConfigOrDefault("aliYunEndpoint","oss-cn-hongkong.aliyuncs.com")
-        region = getConfigOrDefault ("aliYunRegion","oss-cn-hongkong")
+        region = getConfigOrDefault ("aliYunRegion","cn-hongkong")
         bucket = getConfigOrDefault ("aliYunBucket","doris-regression-hk");
 
 
@@ -185,6 +185,8 @@ suite("test_s3_tvf_s3_storage", 
"p0,external,external_docker") {
         s3_tvf("http://${bucket}.${s3_endpoint}";, "", "s3.access_key", 
"s3.secret_key", "region", "false");
         s3_tvf("http://${bucket}.${s3_endpoint}";, "", "AWS_ACCESS_KEY", 
"AWS_SECRET_KEY", "region", "false");
         s3_tvf("http://${bucket}.${s3_endpoint}";, "", "s3.access_key", 
"s3.secret_key", "s3.region", "false");
+        s3_tvf("oss://${bucket}.${s3_endpoint}", "", "s3.access_key", 
"s3.secret_key", "s3.region", "false");
+        s3_tvf("s3://${bucket}.${s3_endpoint}", "", "s3.access_key", 
"s3.secret_key", "s3.region", "false");
         shouldFail {
             // it's OSS 
             s3_tvf("http://${bucket}.${s3_endpoint}";, "", "s3.access_key", 
"cos.secret_key", "region", "false");
diff --git 
a/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
 
b/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
index 2d116d07b31..12850cc1091 100644
--- 
a/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
+++ 
b/regression-test/suites/external_table_p2/refactor_catalog_param/hive_on_hms_and_dlf.groovy
@@ -338,6 +338,7 @@ suite("hive_on_hms_and_dlf", 
"p2,external,new_catalog_property") {
     String oss_endpoint = context.config.otherConfigs.get("aliYunEndpoint")
     String bucket = context.config.otherConfigs.get("aliYunBucket")
     String oss_parent_path = "${bucket}/refactor-test"
+    String 
oss_bucket_endpoint_parent_path="${bucket}.${oss_endpoint}/refactor-test"
     String oss_region = context.config.otherConfigs.get("aliYunRegion")
     String oss_region_param = """
               'oss.region' = '${oss_region}',
@@ -519,6 +520,13 @@ suite("hive_on_hms_and_dlf", 
"p2,external,new_catalog_property") {
     //OSS - Insert overwrite tests
     db_location = "oss://${oss_parent_path}/hive/hms/overwrite/" + 
System.currentTimeMillis()
     testInsertOverwrite(hms_properties + oss_storage_properties, 
"hive_hms_oss_overwrite_test", db_location)
+    //OSS - Partition table tests (fix for partition path scheme mismatch)
+    db_location = 
"oss://${oss_bucket_endpoint_parent_path}/hive/hms/bucket_endpoint/partition/" 
+ System.currentTimeMillis()
+    testPartitionTableInsert(hms_properties + oss_storage_properties, 
"hive_hms_oss_partition_test", db_location)
+    testPartitionTableInsert(hms_properties + oss_region_param + 
oss_storage_properties, "hive_hms_oss_bucket_endpoint_partition_test_region", 
db_location)
+    //OSS - Insert overwrite tests
+    db_location = 
"oss://${oss_bucket_endpoint_parent_path}/hive/hms/bucket_endpoint/overwrite/" 
+ System.currentTimeMillis()
+    testInsertOverwrite(hms_properties + oss_storage_properties, 
"hive_hms_oss_bucket_endpoint_overwrite_test", db_location)
 
     //s3
     db_location = 
"s3a://${s3_parent_path}/hive/hms/"+System.currentTimeMillis()
diff --git 
a/regression-test/suites/external_table_p2/refactor_catalog_param/iceberg_on_hms_and_filesystem_and_dlf.groovy
 
b/regression-test/suites/external_table_p2/refactor_catalog_param/iceberg_on_hms_and_filesystem_and_dlf.groovy
index ea98f7c4baa..e7d866796b8 100644
--- 
a/regression-test/suites/external_table_p2/refactor_catalog_param/iceberg_on_hms_and_filesystem_and_dlf.groovy
+++ 
b/regression-test/suites/external_table_p2/refactor_catalog_param/iceberg_on_hms_and_filesystem_and_dlf.groovy
@@ -415,6 +415,7 @@ suite("iceberg_on_hms_and_filesystem_and_dlf", 
"p2,external,new_catalog_property
     String oss_endpoint = context.config.otherConfigs.get("aliYunEndpoint")
     String oss_bucket = context.config.otherConfigs.get("aliYunBucket")
     String oss_parent_path = "${oss_bucket}/refactor-test"
+    String 
oss_bucket_endpoint_parent_path="${oss_bucket}.${oss_endpoint}/refactor-test"
     String oss_region = context.config.otherConfigs.get("aliYunRegion")
     String oss_region_param = """
               'oss.region' = '${oss_region}',
@@ -510,11 +511,13 @@ suite("iceberg_on_hms_and_filesystem_and_dlf", 
"p2,external,new_catalog_property
                                    
RULE:[2:\\\$1@\\\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
                                    
RULE:[2:\\\$1@\\\$0](.*@OTHERREALM.COM)s/@.*//
                                    DEFAULT",
+                "hive.metastore.sasl.enabled " = "true",
                 "hive.metastore.kerberos.principal" = 
"hive/[email protected]",
      """
 
     String hms_kerberos_old_prop_not_include_kerberos_prop = """
                 "hive.metastore.uris" = "thrift://${externalEnvIp}:9583",
+                "hive.metastore.sasl.enabled " = "true",
                 "hive.metastore.kerberos.principal" = 
"hive/[email protected]",
      """
 
@@ -523,6 +526,7 @@ suite("iceberg_on_hms_and_filesystem_and_dlf", 
"p2,external,new_catalog_property
                 
"hive.metastore.client.principal"="hive/[email protected]",
                 "hive.metastore.client.keytab" = 
"${keytab_root_dir}/hive-presto-master.keytab",
                 "hive.metastore.service.principal" = 
"hive/[email protected]",
+                "hive.metastore.sasl.enabled " = "true",
                 "hive.metastore.authentication.type"="kerberos",
                 "hadoop.security.auth_to_local" = 
"RULE:[2:\\\$1@\\\$0](.*@LABS.TERADATA.COM)s/@.*//
                                    
RULE:[2:\\\$1@\\\$0](.*@OTHERLABS.TERADATA.COM)s/@.*//
@@ -549,6 +553,10 @@ suite("iceberg_on_hms_and_filesystem_and_dlf", 
"p2,external,new_catalog_property
     hmsTestQueryAndInsert(hms_kerberos_old_prop + warehouse + 
oss_storage_properties, "iceberg_hms_on_oss_kerberos_old")
     //new kerberos
     hmsTestQueryAndInsert(hms_kerberos_new_prop + warehouse + 
oss_storage_properties, "iceberg_hms_on_oss_kerberos_new")
+    warehouse  """
+                  'warehouse' = 
'oss://${oss_bucket_endpoint_parent_path}/iceberg-hms-warehouse',
+    """
+    testQueryAndInsert(iceberg_hms_type_prop + hms_prop + warehouse + 
oss_region_param + oss_storage_properties, "iceberg_hms_on_oss")
 
     /*--------HMS on OBS-----------*/
     warehouse = """
@@ -678,6 +686,12 @@ suite("iceberg_on_hms_and_filesystem_and_dlf", 
"p2,external,new_catalog_property
         """
     testQueryAndInsert(iceberg_file_system_catalog_properties + warehouse + 
oss_storage_properties, "iceberg_fs_on_oss")
     testQueryAndInsert(iceberg_file_system_catalog_properties + warehouse + 
oss_region_param + oss_storage_properties, "iceberg_fs_on_oss_region")
+
+    warehouse = """
+        'warehouse' = 
'oss://${oss_bucket_endpoint_parent_path}/iceberg-fs-oss-warehouse',
+        """
+    testQueryAndInsert(iceberg_file_system_catalog_properties + warehouse + 
oss_region_param + oss_storage_properties, "iceberg_fs_on_oss_region")
+
     /**  HDFS **/
     warehouse = """
         'warehouse' = '${hdfs_parent_path}/iceberg-fs-hdfs-warehouse',


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

Reply via email to