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 8a3d7414198 [fix](fe) Support ClickHouse JDBC V2 metadata (#65709)
8a3d7414198 is described below

commit 8a3d7414198f71c83fbb837a0bf08b81390e6ee3
Author: Gabriel <[email protected]>
AuthorDate: Fri Jul 17 23:06:32 2026 +0800

    [fix](fe) Support ClickHouse JDBC V2 metadata (#65709)
    
    ClickHouse JDBC V2 exposes databases as schemas and
    reports distributed tables as `REMOTE TABLE`. Doris inferred the
    database metadata mode from the legacy `databaseterm` URL parameter and
    filtered the vendor table type, so V2 catalogs could not discover
    databases or distributed tables. This change uses JDBC metadata
    capabilities to select catalog/schema mode and includes remote tables in
    discovery in both JDBC client implementations.
---
 .../clickhouse/init/03-create-table.sql            | 10 +++-
 .../jdbc/client/JdbcClickHouseConnectorClient.java | 38 +++++++-----
 .../client/JdbcClickHouseConnectorClientTest.java  | 70 ++++++++++++++++++++++
 .../jdbc/client/JdbcClickHouseClient.java          | 23 +++----
 .../jdbc/client/JdbcClickHouseClientTest.java      | 25 ++++++++
 .../jdbc/test_clickhouse_jdbc_v2.out               |  9 +++
 .../jdbc/test_clickhouse_jdbc_v2.groovy            | 43 +++++++++++++
 7 files changed, 187 insertions(+), 31 deletions(-)

diff --git 
a/docker/thirdparties/docker-compose/clickhouse/init/03-create-table.sql 
b/docker/thirdparties/docker-compose/clickhouse/init/03-create-table.sql
index 039ddd1d369..d45b878d1ed 100644
--- a/docker/thirdparties/docker-compose/clickhouse/init/03-create-table.sql
+++ b/docker/thirdparties/docker-compose/clickhouse/init/03-create-table.sql
@@ -342,6 +342,14 @@ CREATE TABLE doris_test.extreme_test
 ) ENGINE = MergeTree()
 ORDER BY id;
 
+CREATE TABLE doris_test.distributed_type AS doris_test.type
+ENGINE = Distributed(default, doris_test, type, rand());
+
+CREATE MATERIALIZED VIEW doris_test.materialized_view_type
+ENGINE = MergeTree
+ORDER BY k1
+AS SELECT * FROM doris_test.type;
+
 CREATE TABLE doris_test.extreme_test_multi_block
 (
     id UInt64,
@@ -392,4 +400,4 @@ CREATE TABLE doris_test.extreme_test_multi_block
     ipv6_col         IPv6,
     ipv6_nullable    Nullable(IPv6)
 ) ENGINE = MergeTree()
-ORDER BY id;
\ No newline at end of file
+ORDER BY id;
diff --git 
a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClient.java
 
b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClient.java
index b945bcb6c1c..c4cea29b4aa 100644
--- 
a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClient.java
+++ 
b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClient.java
@@ -133,7 +133,8 @@ public class JdbcClickHouseConnectorClient extends 
JdbcConnectorClient {
 
     @Override
     protected String[] getTableTypes() {
-        return new String[] {"TABLE", "VIEW", "SYSTEM TABLE"};
+        // ClickHouse JDBC V2 filters engines by these vendor-specific table 
type names.
+        return new String[] {"TABLE", "VIEW", "SYSTEM TABLE", "REMOTE TABLE", 
"MATERIALIZED VIEW"};
     }
 
     @Override
@@ -145,25 +146,32 @@ public class JdbcClickHouseConnectorClient extends 
JdbcConnectorClient {
 
     private boolean isNewClickHouseDriver(Connection conn) throws SQLException 
{
         if (isNewDriver == null) {
-            String driverVersion = conn.getMetaData().getDriverVersion();
-            isNewDriver = driverVersion != null && 
!driverVersion.startsWith("0.3")
-                    && !driverVersion.startsWith("0.4");
-            if (!isNewDriver) {
-                // Old driver uses schema mode (not catalog), matching old 
JdbcClickHouseClient
-                databaseTermIsCatalog = false;
-            } else {
-                // New driver checks the JDBC URL for databaseterm parameter
-                databaseTermIsCatalog = 
"catalog".equalsIgnoreCase(getDatabaseTermFromUrl());
-            }
+            DatabaseMetaData meta = conn.getMetaData();
+            String driverVersion = meta.getDriverVersion();
+            isNewDriver = isNewClickHouseDriverVersion(driverVersion);
+            databaseTermIsCatalog = isDatabaseTermCatalog(
+                    driverVersion, meta.supportsCatalogsInDataManipulation());
         }
         return isNewDriver;
     }
 
-    private String getDatabaseTermFromUrl() {
-        if (jdbcUrl != null && 
jdbcUrl.toLowerCase().contains("databaseterm=schema")) {
-            return "schema";
+    static boolean isNewClickHouseDriverVersion(String driverVersion) {
+        // Custom jars may omit or rewrite manifest versions; only a known 
legacy version overrides metadata.
+        if (driverVersion == null || driverVersion.isEmpty()) {
+            return true;
         }
-        return "catalog";
+        try {
+            String[] versionParts = driverVersion.split("\\.");
+            int majorVersion = Integer.parseInt(versionParts[0]);
+            int minorVersion = Integer.parseInt(versionParts[1]);
+            return majorVersion > 0 || (majorVersion == 0 && minorVersion >= 
5);
+        } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
+            return true;
+        }
+    }
+
+    static boolean isDatabaseTermCatalog(String driverVersion, boolean 
supportsCatalogs) {
+        return isNewClickHouseDriverVersion(driverVersion) && supportsCatalogs;
     }
 
     @Override
diff --git 
a/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClientTest.java
 
b/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClientTest.java
new file mode 100644
index 00000000000..06124b24ba0
--- /dev/null
+++ 
b/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcClickHouseConnectorClientTest.java
@@ -0,0 +1,70 @@
+// 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.connector.jdbc.client;
+
+import org.apache.doris.connector.jdbc.JdbcDbType;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+public class JdbcClickHouseConnectorClientTest {
+
+    private JdbcClickHouseConnectorClient createClient() {
+        return new JdbcClickHouseConnectorClient(
+                "test_catalog",
+                JdbcDbType.CLICKHOUSE,
+                "jdbc:clickhouse://localhost:8123/default",
+                false,
+                Collections.emptyMap(),
+                Collections.emptyMap(),
+                false,
+                false);
+    }
+
+    @Test
+    void testDriverVersionDetection() {
+        
Assertions.assertTrue(JdbcClickHouseConnectorClient.isNewClickHouseDriverVersion("0.9.8"));
+        
Assertions.assertTrue(JdbcClickHouseConnectorClient.isNewClickHouseDriverVersion("0.7.1"));
+        
Assertions.assertFalse(JdbcClickHouseConnectorClient.isNewClickHouseDriverVersion("0.4.2"));
+    }
+
+    @Test
+    void testDatabaseTermFollowsDriverMetadata() {
+        
Assertions.assertFalse(JdbcClickHouseConnectorClient.isDatabaseTermCatalog("0.9.8",
 false));
+        
Assertions.assertTrue(JdbcClickHouseConnectorClient.isDatabaseTermCatalog("0.7.1",
 true));
+        
Assertions.assertFalse(JdbcClickHouseConnectorClient.isDatabaseTermCatalog("0.4.2",
 true));
+    }
+
+    @Test
+    void testUnknownDriverVersionFollowsDriverMetadata() {
+        for (String driverVersion : new String[] {null, "", "custom-build"}) {
+            
Assertions.assertTrue(JdbcClickHouseConnectorClient.isNewClickHouseDriverVersion(driverVersion));
+            
Assertions.assertTrue(JdbcClickHouseConnectorClient.isDatabaseTermCatalog(driverVersion,
 true));
+            
Assertions.assertFalse(JdbcClickHouseConnectorClient.isDatabaseTermCatalog(driverVersion,
 false));
+        }
+    }
+
+    @Test
+    void testClickHouseSpecificTableTypesAreVisible() {
+        Assertions.assertArrayEquals(
+                new String[] {"TABLE", "VIEW", "SYSTEM TABLE", "REMOTE TABLE", 
"MATERIALIZED VIEW"},
+                createClient().getTableTypes());
+    }
+}
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
index 4f340bebed4..fec623e88f2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java
@@ -39,12 +39,9 @@ public class JdbcClickHouseClient extends JdbcClient {
     protected JdbcClickHouseClient(JdbcClientConfig jdbcClientConfig) {
         super(jdbcClientConfig);
         try (Connection conn = getConnection()) {
-            String jdbcUrl = conn.getMetaData().getURL();
-            if (!isNewClickHouseDriver(getJdbcDriverVersion())) {
-                this.databaseTermIsCatalog = false;
-            } else {
-                this.databaseTermIsCatalog = 
"catalog".equalsIgnoreCase(getDatabaseTermFromUrl(jdbcUrl));
-            }
+            DatabaseMetaData databaseMetaData = conn.getMetaData();
+            this.databaseTermIsCatalog = isDatabaseTermCatalog(
+                    databaseMetaData, databaseMetaData.getDriverVersion());
         } catch (SQLException e) {
             throw new JdbcClientException("Failed to initialize 
JdbcClickHouseClient: %s", e.getMessage());
         }
@@ -123,7 +120,8 @@ public class JdbcClickHouseClient extends JdbcClient {
 
     @Override
     protected String[] getTableTypes() {
-        return new String[] {"TABLE", "VIEW", "SYSTEM TABLE"};
+        // ClickHouse JDBC V2 filters engines by these vendor-specific table 
type names.
+        return new String[] {"TABLE", "VIEW", "SYSTEM TABLE", "REMOTE TABLE", 
"MATERIALIZED VIEW"};
     }
 
     @Override
@@ -231,14 +229,9 @@ public class JdbcClickHouseClient extends JdbcClient {
         }
     }
 
-    /**
-     * Extract databaseterm parameters from the jdbc url.
-     */
-    private String getDatabaseTermFromUrl(String jdbcUrl) {
-        if (jdbcUrl != null && 
jdbcUrl.toLowerCase().contains("databaseterm=schema")) {
-            return "schema";
-        }
-        return "catalog";
+    static boolean isDatabaseTermCatalog(DatabaseMetaData databaseMetaData, 
String driverVersion)
+            throws SQLException {
+        return isNewClickHouseDriver(driverVersion) && 
databaseMetaData.supportsCatalogsInDataManipulation();
     }
 
     /**
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClientTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClientTest.java
index 99e4aa62dd5..a76319d108f 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClientTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClientTest.java
@@ -19,11 +19,36 @@ package org.apache.doris.datasource.jdbc.client;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.Mockito;
 
 import java.lang.reflect.Method;
+import java.sql.DatabaseMetaData;
 
 public class JdbcClickHouseClientTest {
 
+    @Test
+    public void testDatabaseTermFollowsDriverMetadata() throws Exception {
+        DatabaseMetaData databaseMetaData = 
Mockito.mock(DatabaseMetaData.class);
+
+        
Mockito.when(databaseMetaData.supportsCatalogsInDataManipulation()).thenReturn(false);
+        
Assert.assertFalse(JdbcClickHouseClient.isDatabaseTermCatalog(databaseMetaData, 
"0.9.8"));
+
+        
Mockito.when(databaseMetaData.supportsCatalogsInDataManipulation()).thenReturn(true);
+        
Assert.assertTrue(JdbcClickHouseClient.isDatabaseTermCatalog(databaseMetaData, 
"0.7.1"));
+
+        
Assert.assertFalse(JdbcClickHouseClient.isDatabaseTermCatalog(databaseMetaData, 
"0.4.2"));
+    }
+
+    @Test
+    public void testClickHouseSpecificTableTypesAreVisible() {
+        JdbcClickHouseClient client = Mockito.mock(JdbcClickHouseClient.class, 
Answers.CALLS_REAL_METHODS);
+
+        Assert.assertArrayEquals(
+                new String[] {"TABLE", "VIEW", "SYSTEM TABLE", "REMOTE TABLE", 
"MATERIALIZED VIEW"},
+                client.getTableTypes());
+    }
+
     @Test
     public void testIsNewClickHouseDriver() {
         try {
diff --git 
a/regression-test/data/external_table_p0/jdbc/test_clickhouse_jdbc_v2.out 
b/regression-test/data/external_table_p0/jdbc/test_clickhouse_jdbc_v2.out
new file mode 100644
index 00000000000..0ad208e4be8
--- /dev/null
+++ b/regression-test/data/external_table_p0/jdbc/test_clickhouse_jdbc_v2.out
@@ -0,0 +1,9 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !clickhouse_v2_schema --
+2
+
+-- !clickhouse_v2_distributed --
+2
+
+-- !clickhouse_v2_materialized_view --
+2
diff --git 
a/regression-test/suites/external_table_p0/jdbc/test_clickhouse_jdbc_v2.groovy 
b/regression-test/suites/external_table_p0/jdbc/test_clickhouse_jdbc_v2.groovy
new file mode 100644
index 00000000000..4d986201fbe
--- /dev/null
+++ 
b/regression-test/suites/external_table_p0/jdbc/test_clickhouse_jdbc_v2.groovy
@@ -0,0 +1,43 @@
+// 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.
+
+suite("test_clickhouse_jdbc_v2", "p0,external") {
+    String enabled = context.config.otherConfigs.get("enableJdbcTest")
+    if (enabled != null && enabled.equalsIgnoreCase("true")) {
+        String clickhousePort = 
context.config.otherConfigs.get("clickhouse_22_port")
+        String externalEnvIp = context.config.otherConfigs.get("externalEnvIp")
+        String s3Endpoint = getS3Endpoint()
+        String bucket = getS3BucketName()
+        // Keep large drivers in the regression bucket so isolated workers do 
not require public egress.
+        String driverUrl = 
"https://${bucket}.${s3Endpoint}/regression/jdbc_driver/clickhouse-jdbc-0.9.8-all.jar";
+
+        sql """ drop catalog if exists clickhouse_v2_schema """
+        sql """ create catalog clickhouse_v2_schema properties(
+                    "type"="jdbc",
+                    "user"="default",
+                    "password"="123456",
+                    "jdbc_url" = 
"jdbc:clickhouse://${externalEnvIp}:${clickhousePort}/doris_test?jdbc_schema_term=schema",
+                    "driver_url" = "${driverUrl}",
+                    "driver_class" = "com.clickhouse.jdbc.Driver"
+        );"""
+
+        order_qt_clickhouse_v2_schema """ select count(*) from 
clickhouse_v2_schema.doris_test.type """
+        order_qt_clickhouse_v2_distributed """ select count(*) from 
clickhouse_v2_schema.doris_test.distributed_type """
+        order_qt_clickhouse_v2_materialized_view """ select count(*) from 
clickhouse_v2_schema.doris_test.materialized_view_type """
+        sql """ drop catalog clickhouse_v2_schema """
+    }
+}


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

Reply via email to