From d430ec9a4a4f58933206a3481c50a89ed27aaa16 Mon Sep 17 00:00:00 2001 From: Melody Ruch <396921921@qq.com> Date: Fri, 4 Sep 2026 16:48:03 +0800 Subject: [PATCH] fix(imports): map DBeaver DB2 driver id to native db2 type --- .../__tests__/imports/dbeaverImport.spec.ts | 47 ++++++++++++++++++- apps/desktop/src/lib/imports/dbeaverImport.ts | 12 ++++- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/lib/__tests__/imports/dbeaverImport.spec.ts b/apps/desktop/src/lib/__tests__/imports/dbeaverImport.spec.ts index b9281bf4f8..1fa924f895 100644 --- a/apps/desktop/src/lib/__tests__/imports/dbeaverImport.spec.ts +++ b/apps/desktop/src/lib/__tests__/imports/dbeaverImport.spec.ts @@ -222,7 +222,7 @@ describe("DBeaver folder import", () => { expect(connection?.database).toBeUndefined(); }); - it("keeps the default database empty for DB2 connections (fallback to JDBC) without database configured", async () => { + it("maps DB2 connections to DBX's native db2 type instead of falling back to generic JDBC", async () => { const [connection] = await parseDbeaverConnections( payload({ connections: { @@ -243,11 +243,54 @@ describe("DBeaver folder import", () => { expect(connection).toMatchObject({ name: "DB2", - db_type: "jdbc", + db_type: "db2", + driver_profile: "db2", host: "192.168.10.60", port: 50000, }); expect(connection?.database).toBeUndefined(); + expect(connection?.jdbc_driver_class).toBeUndefined(); + }); + + it("does not pass DBeaver's short driver id through as a JDBC driver class for unmapped drivers", async () => { + const [connection] = await parseDbeaverConnections( + payload({ + connections: { + vertica: { + id: "vertica", + name: "Vertica", + provider: "vertica", + driver: "vertica", + configuration: { + url: "jdbc:vertica://192.168.10.61:5433/vdb", + }, + }, + }, + }), + ); + + expect(connection).toMatchObject({ name: "Vertica", db_type: "jdbc" }); + expect(connection?.jdbc_driver_class).toBeUndefined(); + }); + + it("still trusts a package-qualified DBeaver driver id as the JDBC driver class", async () => { + const [connection] = await parseDbeaverConnections( + payload({ + connections: { + opaque: { + id: "opaque", + name: "Custom Driver", + provider: "generic", + driver: "com.example.Driver", + configuration: { + url: "jdbc:example:db.example.com:1234", + }, + }, + }, + }), + ); + + expect(connection).toMatchObject({ db_type: "jdbc", jdbc_driver_class: "com.example.Driver" }); }); it("does not treat an opaque JDBC host and port as the database", async () => { diff --git a/apps/desktop/src/lib/imports/dbeaverImport.ts b/apps/desktop/src/lib/imports/dbeaverImport.ts index c00d230838..33aec127ee 100644 --- a/apps/desktop/src/lib/imports/dbeaverImport.ts +++ b/apps/desktop/src/lib/imports/dbeaverImport.ts @@ -47,6 +47,7 @@ const profileMap: Record = { sqlserver: { dbType: "sqlserver", profile: "sqlserver", label: "SQL Server", port: 1433, user: "sa" }, mssql: { dbType: "sqlserver", profile: "sqlserver", label: "SQL Server", port: 1433, user: "sa" }, oracle: { dbType: "oracle", profile: "oracle", label: "Oracle", port: 1521, user: "system" }, + db2: { dbType: "db2", profile: "db2", label: "IBM DB2", port: 50000, user: "db2inst1" }, clickhouse: { dbType: "clickhouse", profile: "clickhouse", label: "ClickHouse", port: 8123, user: "default" }, duckdb: { dbType: "duckdb", profile: "duckdb", label: "DuckDB", port: 0, user: "" }, mongodb: { dbType: "mongodb", profile: "mongodb", label: "MongoDB", port: 27017, user: "" }, @@ -81,6 +82,15 @@ function getNumber(value: unknown) { return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; } +// DBeaver's own driver id (e.g. "db2", "mysql8") is a short internal registry +// key, not a Java class name; passing it straight to the JDBC agent as +// `jdbc_driver_class` makes it try `Class.forName("db2")` and fail with +// ClassNotFoundException. Only fall back to it when it is actually +// package-qualified, which is how DBeaver identifies genuinely custom drivers. +function looksLikeJdbcDriverClassName(value: string) { + return /^[a-zA-Z_$][\w$]*(\.[a-zA-Z_$][\w$]*)+$/.test(value); +} + function firstNonEmptyString(...values: unknown[]) { for (const value of values) { if (typeof value !== "string") continue; @@ -258,7 +268,7 @@ function buildConnection(entry: DbeaverConnectionEntry, credentials: ReturnType< ssl: false, oracle_connection_type: profile.dbType === "oracle" ? parsedUrl.oracleConnectionType || "service_name" : undefined, connection_string: profile.dbType === "jdbc" || profile.dbType === "mongodb" ? url || undefined : undefined, - jdbc_driver_class: profile.dbType === "jdbc" ? getString(config["driver-class"] || (profile.profile === "jdbcx" ? JDBCX_JDBC_DRIVER_CLASS : entry.driver)) || undefined : undefined, + jdbc_driver_class: profile.dbType === "jdbc" ? getString(config["driver-class"] || (profile.profile === "jdbcx" ? JDBCX_JDBC_DRIVER_CLASS : looksLikeJdbcDriverClassName(getString(entry.driver)) ? entry.driver : undefined)) || undefined : undefined, jdbc_driver_paths: [], };