From c97a326aae1a4ade6b80276b6a90d06597408a0e Mon Sep 17 00:00:00 2001 From: Socrates Date: Mon, 21 Sep 2026 15:34:11 +0800 Subject: [PATCH 1/3] [fix](fe) Recognize enterprise JDBC targets without cloud suffix ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: JDBC Catalog can misidentify an enterprise Doris endpoint as MySQL when its version comment omits optional product markers. This skips Doris-specific type mapping and can expose incorrect schemas. Recognize the stable enterprise version prefix in both JDBC client implementations while retaining the existing compatibility rules. ### Release note Fix JDBC Catalog type mapping for enterprise Doris endpoints whose version comment omits optional product markers. ### Check List (For Author) - Test: Unit Test - Legacy and connector JDBC endpoint detection tests - Behavior changed: Yes, recognized enterprise endpoints use Doris-specific type mapping - Does this need documentation: No --- .../doris/connector/jdbc/client/JdbcMySQLConnectorClient.java | 2 ++ .../apache/doris/datasource/jdbc/client/JdbcMySQLClient.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java index 9874d1b2460646..c98a107e8b29b8 100644 --- a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java +++ b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java @@ -93,9 +93,11 @@ static boolean isDorisCompatibleVersionComment(String versionComment) { return false; } String lowerVersionComment = versionComment.toLowerCase(Locale.ROOT); + // Enterprise releases can omit the optional "(Cloud Mode)" suffix. return lowerVersionComment.contains("doris") || lowerVersionComment.contains("selectdb") || lowerVersionComment.contains("velodb") + || lowerVersionComment.contains("enterprise version enterprise-") || (lowerVersionComment.contains("enterprise version") && lowerVersionComment.contains("cloud mode")); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java index bcdc9ccc03bd69..cfc1e47af5cc2f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java @@ -81,9 +81,11 @@ static boolean isDorisCompatibleVersionComment(String versionComment) { return false; } String lowerVersionComment = versionComment.toLowerCase(Locale.ROOT); + // Enterprise releases can omit the optional "(Cloud Mode)" suffix. return lowerVersionComment.contains("doris") || lowerVersionComment.contains("selectdb") || lowerVersionComment.contains("velodb") + || lowerVersionComment.contains("enterprise version enterprise-") || (lowerVersionComment.contains("enterprise version") && lowerVersionComment.contains("cloud mode")); } From c8b014225eefb04df63bb99aadd1b4d4ca646c52 Mon Sep 17 00:00:00 2001 From: Socrates Date: Mon, 21 Sep 2026 15:34:11 +0800 Subject: [PATCH 2/3] [fix](fe) Detect Doris JDBC targets with server identity ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: JDBC Catalog infers whether a MySQL-compatible endpoint is Doris from version_comment. Product branding and packaging can change that display string and cause Doris-specific types to be mapped as MySQL types. Expose a stable read-only session variable, prefer it in both JDBC client implementations, and retain version_comment as a fallback for older endpoints. ### Release note Use a stable server identity when detecting Doris JDBC endpoints. ### Check List (For Author) - Test: Unit Test - Legacy and connector JDBC endpoint identity and compatibility detection tests - Behavior changed: Yes, JDBC Catalog prefers doris_server_identity and falls back to version_comment for older endpoints - Does this need documentation: No --- .../jdbc/client/JdbcMySQLConnectorClient.java | 16 +++++++++++++--- .../client/JdbcMySQLConnectorClientTest.java | 10 ++++++++++ .../datasource/jdbc/client/JdbcMySQLClient.java | 17 ++++++++++++++--- .../org/apache/doris/qe/SessionVariable.java | 5 +++++ .../jdbc/client/JdbcMySQLClientTest.java | 10 ++++++++++ 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java index c98a107e8b29b8..e9dc10d872f3fc 100644 --- a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java +++ b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java @@ -47,6 +47,7 @@ public class JdbcMySQLConnectorClient extends JdbcConnectorClient { private static final Logger LOG = LogManager.getLogger(JdbcMySQLConnectorClient.class); + private static final String DORIS_SERVER_IDENTITY = "apache_doris"; private final boolean convertDateToNull; private boolean isDoris = false; @@ -76,10 +77,15 @@ private void detectDoris() { try { conn = getConnection(); stmt = conn.createStatement(); - rs = stmt.executeQuery("SHOW VARIABLES LIKE 'version_comment'"); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'doris_server_identity'"); if (rs.next()) { - String versionComment = rs.getString("Value"); - isDoris = isDorisCompatibleVersionComment(versionComment); + isDoris = isDorisServerIdentity(rs.getString("Value")); + } else { + closeResources(rs); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'version_comment'"); + if (rs.next()) { + isDoris = isDorisCompatibleVersionComment(rs.getString("Value")); + } } } catch (Exception e) { LOG.warn("Failed to detect if remote MySQL is Doris: {}", e.getMessage()); @@ -88,6 +94,10 @@ private void detectDoris() { } } + static boolean isDorisServerIdentity(String serverIdentity) { + return DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); + } + static boolean isDorisCompatibleVersionComment(String versionComment) { if (versionComment == null || versionComment.isEmpty()) { return false; diff --git a/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClientTest.java b/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClientTest.java index 5cb178a9268001..772108a5b724f1 100644 --- a/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClientTest.java +++ b/fe/fe-connector/fe-connector-jdbc/src/test/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClientTest.java @@ -22,6 +22,14 @@ public class JdbcMySQLConnectorClientTest { + @Test + void testIsDorisServerIdentity() { + Assertions.assertTrue(JdbcMySQLConnectorClient.isDorisServerIdentity("apache_doris")); + Assertions.assertTrue(JdbcMySQLConnectorClient.isDorisServerIdentity("APACHE_DORIS")); + Assertions.assertFalse(JdbcMySQLConnectorClient.isDorisServerIdentity("mysql")); + Assertions.assertFalse(JdbcMySQLConnectorClient.isDorisServerIdentity(null)); + } + @Test void testIsDorisCompatibleVersionComment() { Assertions.assertTrue(JdbcMySQLConnectorClient.isDorisCompatibleVersionComment( @@ -32,6 +40,8 @@ void testIsDorisCompatibleVersionComment() { "VeloDB version 2.1.0")); Assertions.assertTrue(JdbcMySQLConnectorClient.isDorisCompatibleVersionComment( "enterprise version enterprise-4.0.5-rc01-0724569463d (Cloud Mode)")); + Assertions.assertTrue(JdbcMySQLConnectorClient.isDorisCompatibleVersionComment( + "enterprise version enterprise-current")); Assertions.assertFalse(JdbcMySQLConnectorClient.isDorisCompatibleVersionComment( "MySQL Community Server - GPL")); diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java index cfc1e47af5cc2f..461a3d72a6f63d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java @@ -45,6 +45,8 @@ public class JdbcMySQLClient extends JdbcClient { + private static final String DORIS_SERVER_IDENTITY = "apache_doris"; + private boolean convertDateToNull = false; private boolean isDoris = false; @@ -57,10 +59,15 @@ protected JdbcMySQLClient(JdbcClientConfig jdbcClientConfig) { try { conn = super.getConnection(); stmt = conn.createStatement(); - rs = stmt.executeQuery("SHOW VARIABLES LIKE 'version_comment'"); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'doris_server_identity'"); if (rs.next()) { - String versionComment = rs.getString("Value"); - isDoris = isDorisCompatibleVersionComment(versionComment); + isDoris = isDorisServerIdentity(rs.getString("Value")); + } else { + close(rs); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'version_comment'"); + if (rs.next()) { + isDoris = isDorisCompatibleVersionComment(rs.getString("Value")); + } } } catch (SQLException | JdbcClientException e) { closeClient(); @@ -76,6 +83,10 @@ protected JdbcMySQLClient(JdbcClientConfig jdbcClientConfig, String dbType) { this.dbType = dbType; } + static boolean isDorisServerIdentity(String serverIdentity) { + return DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); + } + static boolean isDorisCompatibleVersionComment(String versionComment) { if (Strings.isNullOrEmpty(versionComment)) { return false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 9e40aa4869c539..ae8dff2dd21b06 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -164,6 +164,8 @@ public class SessionVariable implements Serializable, Writable { public static final String SQL_SAFE_UPDATES = "sql_safe_updates"; public static final String NET_BUFFER_LENGTH = "net_buffer_length"; public static final String HAVE_QUERY_CACHE = "have_query_cache"; + public static final String DORIS_SERVER_IDENTITY = "doris_server_identity"; + public static final String APACHE_DORIS_SERVER_IDENTITY = "apache_doris"; // mem limit can't smaller than bufferpool's default page size public static final int MIN_EXEC_MEM_LIMIT = 2097152; public static final String BATCH_SIZE = "batch_size"; @@ -1385,6 +1387,9 @@ public void checkQuerySlotCount(String slotCnt) { @VarAttrDef.VarAttr(name = HAVE_QUERY_CACHE, flag = VarAttrDef.READ_ONLY) public boolean haveQueryCache = false; + @VarAttrDef.VarAttr(name = DORIS_SERVER_IDENTITY, flag = VarAttrDef.READ_ONLY) + public String dorisServerIdentity = APACHE_DORIS_SERVER_IDENTITY; + // 8192 minus 16 + 16 bytes padding that in padding pod array. // This remains the row cap for output blocks even when adaptive byte budgeting is enabled. @VarAttrDef.VarAttr(name = BATCH_SIZE, fuzzy = true, checker = "checkBatchSize", needForward = true) diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClientTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClientTest.java index 6379c0db52aae2..375bb4f2e03156 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClientTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClientTest.java @@ -22,6 +22,14 @@ public class JdbcMySQLClientTest { + @Test + public void testIsDorisServerIdentity() { + Assertions.assertTrue(JdbcMySQLClient.isDorisServerIdentity("apache_doris")); + Assertions.assertTrue(JdbcMySQLClient.isDorisServerIdentity("APACHE_DORIS")); + Assertions.assertFalse(JdbcMySQLClient.isDorisServerIdentity("mysql")); + Assertions.assertFalse(JdbcMySQLClient.isDorisServerIdentity(null)); + } + @Test public void testIsDorisCompatibleVersionComment() { Assertions.assertTrue(JdbcMySQLClient.isDorisCompatibleVersionComment("Apache Doris version 3.1.0")); @@ -29,6 +37,8 @@ public void testIsDorisCompatibleVersionComment() { Assertions.assertTrue(JdbcMySQLClient.isDorisCompatibleVersionComment("VeloDB version 2.1.0")); Assertions.assertTrue(JdbcMySQLClient.isDorisCompatibleVersionComment( "enterprise version enterprise-4.0.5-rc01-0724569463d (Cloud Mode)")); + Assertions.assertTrue(JdbcMySQLClient.isDorisCompatibleVersionComment( + "enterprise version enterprise-current")); Assertions.assertFalse(JdbcMySQLClient.isDorisCompatibleVersionComment("MySQL Community Server - GPL")); Assertions.assertFalse(JdbcMySQLClient.isDorisCompatibleVersionComment("")); From 8f714fa11d736848b171e5a259a1b80a3b013d22 Mon Sep 17 00:00:00 2001 From: Socrates Date: Mon, 21 Sep 2026 18:00:22 +0800 Subject: [PATCH 3/3] [fix](fe) Rename JDBC server identity variable ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: Use the generic read-only session variable name `server_identity` for stable JDBC server identification and update both JDBC client implementations to query it. ### Release note Rename the read-only JDBC server identity variable to `server_identity`. ### Check List (For Author) - Test: Unit Test - JdbcMySQLClientTest - JdbcMySQLConnectorClientTest - Behavior changed: Yes. The read-only identity variable is exposed as `server_identity`. - Does this need documentation: No --- .../connector/jdbc/client/JdbcMySQLConnectorClient.java | 6 +++--- .../doris/datasource/jdbc/client/JdbcMySQLClient.java | 6 +++--- .../src/main/java/org/apache/doris/qe/SessionVariable.java | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java index e9dc10d872f3fc..992bf5b2b44b56 100644 --- a/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java +++ b/fe/fe-connector/fe-connector-jdbc/src/main/java/org/apache/doris/connector/jdbc/client/JdbcMySQLConnectorClient.java @@ -47,7 +47,7 @@ public class JdbcMySQLConnectorClient extends JdbcConnectorClient { private static final Logger LOG = LogManager.getLogger(JdbcMySQLConnectorClient.class); - private static final String DORIS_SERVER_IDENTITY = "apache_doris"; + private static final String APACHE_DORIS_SERVER_IDENTITY = "apache_doris"; private final boolean convertDateToNull; private boolean isDoris = false; @@ -77,7 +77,7 @@ private void detectDoris() { try { conn = getConnection(); stmt = conn.createStatement(); - rs = stmt.executeQuery("SHOW VARIABLES LIKE 'doris_server_identity'"); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'server_identity'"); if (rs.next()) { isDoris = isDorisServerIdentity(rs.getString("Value")); } else { @@ -95,7 +95,7 @@ private void detectDoris() { } static boolean isDorisServerIdentity(String serverIdentity) { - return DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); + return APACHE_DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); } static boolean isDorisCompatibleVersionComment(String versionComment) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java index 461a3d72a6f63d..c3233c859a32bb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java @@ -45,7 +45,7 @@ public class JdbcMySQLClient extends JdbcClient { - private static final String DORIS_SERVER_IDENTITY = "apache_doris"; + private static final String APACHE_DORIS_SERVER_IDENTITY = "apache_doris"; private boolean convertDateToNull = false; private boolean isDoris = false; @@ -59,7 +59,7 @@ protected JdbcMySQLClient(JdbcClientConfig jdbcClientConfig) { try { conn = super.getConnection(); stmt = conn.createStatement(); - rs = stmt.executeQuery("SHOW VARIABLES LIKE 'doris_server_identity'"); + rs = stmt.executeQuery("SHOW VARIABLES LIKE 'server_identity'"); if (rs.next()) { isDoris = isDorisServerIdentity(rs.getString("Value")); } else { @@ -84,7 +84,7 @@ protected JdbcMySQLClient(JdbcClientConfig jdbcClientConfig, String dbType) { } static boolean isDorisServerIdentity(String serverIdentity) { - return DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); + return APACHE_DORIS_SERVER_IDENTITY.equalsIgnoreCase(serverIdentity); } static boolean isDorisCompatibleVersionComment(String versionComment) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index ae8dff2dd21b06..502096fe535566 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -164,7 +164,7 @@ public class SessionVariable implements Serializable, Writable { public static final String SQL_SAFE_UPDATES = "sql_safe_updates"; public static final String NET_BUFFER_LENGTH = "net_buffer_length"; public static final String HAVE_QUERY_CACHE = "have_query_cache"; - public static final String DORIS_SERVER_IDENTITY = "doris_server_identity"; + public static final String SERVER_IDENTITY = "server_identity"; public static final String APACHE_DORIS_SERVER_IDENTITY = "apache_doris"; // mem limit can't smaller than bufferpool's default page size public static final int MIN_EXEC_MEM_LIMIT = 2097152; @@ -1387,8 +1387,8 @@ public void checkQuerySlotCount(String slotCnt) { @VarAttrDef.VarAttr(name = HAVE_QUERY_CACHE, flag = VarAttrDef.READ_ONLY) public boolean haveQueryCache = false; - @VarAttrDef.VarAttr(name = DORIS_SERVER_IDENTITY, flag = VarAttrDef.READ_ONLY) - public String dorisServerIdentity = APACHE_DORIS_SERVER_IDENTITY; + @VarAttrDef.VarAttr(name = SERVER_IDENTITY, flag = VarAttrDef.READ_ONLY) + public String serverIdentity = APACHE_DORIS_SERVER_IDENTITY; // 8192 minus 16 + 16 bytes padding that in padding pod array. // This remains the row cap for output blocks even when adaptive byte budgeting is enabled.