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

zykkk 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 232b6c6f899 [improvement](jdbc catalog) Enhance JDBC driver 
ClassLoader cache handling and validity checks (#50353)
232b6c6f899 is described below

commit 232b6c6f8995a48d4a9f0a2c43bb9c8c282ca023
Author: zy-kkk <[email protected]>
AuthorDate: Fri May 9 11:49:38 2025 +0800

    [improvement](jdbc catalog) Enhance JDBC driver ClassLoader cache handling 
and validity checks (#50353)
    
    Problem Summary:
    
    - Added file-existence checks in initializeClassLoader to catch missing 
JARs early
    - On “Failed to load driver class” errors, clear stale ClassLoader cache 
and retry loading
    - mproved exception messages to prompt users to verify driver JAR validity 
and retry
    
    **CASE TEST**
    
    - Case 1: Create catalog without jar package
       - Error: compute driver checksum from url: mysql-connector-j-8.3.0.jar 
meet an IOException: java.io.FileNotFoundException: 
/Users/zyk/LocalDoris/doris-run/fe/../jdbc_drivers/mysql-connector-j-8.3.0.jar 
(No such file or directory)
       - After putting in jar: Successfully created and used
    - Case 3: After the jar package is successfully created, delete the jar and 
do not restart FE to use catalog
      - Normal use
    - Case 3: After the jar package is successfully created, delete the jar and 
restart FE to use catalog
      - Error: Please check that the driver JAR is valid and retry.
      - After putting in jar: Normal use
    - Case 4: Put in the wrong jar:
      - Error: Please check that the driver JAR is valid and retry.
      - After putting in the jar: Use normally
---
 .../org/apache/doris/jdbc/BaseJdbcExecutor.java    | 23 ++++++++++++++++++----
 .../doris/datasource/jdbc/client/JdbcClient.java   | 22 ++++++++++++++++++---
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git 
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
 
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
index 7a6263e5232..4688602d07a 100644
--- 
a/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
+++ 
b/fe/be-java-extensions/jdbc-scanner/src/main/java/org/apache/doris/jdbc/BaseJdbcExecutor.java
@@ -362,17 +362,31 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
         } catch (FileNotFoundException e) {
             throw new JdbcExecutorException("FileNotFoundException failed: ", 
e);
         } catch (Exception e) {
+            String msg = e.getMessage();
+            // If driver class loading failed (Hikari wraps it), clear stale 
cache and prompt retry
+            if (msg != null && msg.contains("Failed to load driver class")) {
+                try {
+                    URL url = new URL(config.getJdbcDriverUrl());
+                    classLoaderMap.remove(url);
+                    // Prompt user to verify driver validity and retry
+                    throw new JdbcExecutorException(
+                        String.format("Failed to load driver class `%s`. "
+                                        + "Please check that the driver JAR is 
valid and retry.",
+                                      config.getJdbcDriverClass()), e);
+                } catch (MalformedURLException ignore) {
+                    // ignore invalid URL when cleaning cache
+                }
+            }
             throw new JdbcExecutorException("Initialize datasource failed: ", 
e);
         } finally {
             Thread.currentThread().setContextClassLoader(oldClassLoader);
         }
     }
 
-    private synchronized void initializeClassLoader(JdbcDataSourceConfig 
config)
-            throws MalformedURLException, FileNotFoundException {
+    private synchronized void initializeClassLoader(JdbcDataSourceConfig 
config) {
         try {
             URL[] urls = {new URL(config.getJdbcDriverUrl())};
-            if (classLoaderMap.containsKey(urls[0])) {
+            if (classLoaderMap.containsKey(urls[0]) && 
classLoaderMap.get(urls[0]) != null) {
                 this.classLoader = classLoaderMap.get(urls[0]);
             } else {
                 String expectedChecksum = config.getJdbcDriverChecksum();
@@ -385,7 +399,8 @@ public abstract class BaseJdbcExecutor implements 
JdbcExecutor {
                 classLoaderMap.put(urls[0], this.classLoader);
             }
         } catch (MalformedURLException e) {
-            throw new RuntimeException("Error loading JDBC driver.", e);
+            throw new RuntimeException("Failed to load JDBC driver from path: "
+                    + config.getJdbcDriverUrl(), e);
         }
     }
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
index 121f7d6ba04..7d3ecdfe4d9 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClient.java
@@ -144,7 +144,22 @@ public abstract class JdbcClient {
                     + ", ConnectionPoolMaxWaitTime = " + 
config.getConnectionPoolMaxWaitTime()
                     + ", ConnectionPoolMaxLifeTime = " + 
config.getConnectionPoolMaxLifeTime());
         } catch (Exception e) {
-            throw new JdbcClientException(e.getMessage());
+            // If driver class loading failed (Hikari wraps it), clean cache 
and prompt retry
+            String msg = e.getMessage();
+            if (msg != null && msg.contains("Failed to load driver class")) {
+                try {
+                    URL url = new 
URL(JdbcResource.getFullDriverUrl(config.getDriverUrl()));
+                    classLoaderMap.remove(url);
+                    // Prompt user to verify driver validity and retry
+                    throw new JdbcClientException(
+                        String.format("Failed to load driver class `%s`. "
+                                        + "Please check that the driver JAR is 
valid and retry.",
+                                      config.getDriverClass()), e);
+                } catch (MalformedURLException ignore) {
+                    // ignore invalid URL when cleaning cache
+                }
+            }
+            throw new JdbcClientException(e.getMessage(), e);
         } finally {
             Thread.currentThread().setContextClassLoader(oldClassLoader);
         }
@@ -153,7 +168,7 @@ public abstract class JdbcClient {
     private synchronized void initializeClassLoader(JdbcClientConfig config) {
         try {
             URL[] urls = {new 
URL(JdbcResource.getFullDriverUrl(config.getDriverUrl()))};
-            if (classLoaderMap.containsKey(urls[0])) {
+            if (classLoaderMap.containsKey(urls[0]) && 
classLoaderMap.get(urls[0]) != null) {
                 this.classLoader = classLoaderMap.get(urls[0]);
             } else {
                 ClassLoader parent = getClass().getClassLoader();
@@ -161,7 +176,8 @@ public abstract class JdbcClient {
                 classLoaderMap.put(urls[0], this.classLoader);
             }
         } catch (MalformedURLException e) {
-            throw new RuntimeException("Error loading JDBC driver.", e);
+            throw new RuntimeException("Failed to load JDBC driver from path: "
+                    + config.getDriverUrl(), e);
         }
     }
 


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

Reply via email to