From 2f5469ce6d20e938ee78b287e9c9dbeb6ed06ab0 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Wed, 10 Jun 2026 11:37:45 +0800 Subject: [PATCH] fix(oracle): add listener driver hint --- crates/dbx-core/src/agent_connection.rs | 44 +++++++++++++++++++++++++ crates/dbx-core/src/connection.rs | 5 +-- src-tauri/src/commands/connection.rs | 6 ++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/crates/dbx-core/src/agent_connection.rs b/crates/dbx-core/src/agent_connection.rs index bc80963fc..5639000b7 100644 --- a/crates/dbx-core/src/agent_connection.rs +++ b/crates/dbx-core/src/agent_connection.rs @@ -185,6 +185,24 @@ pub fn mongo_legacy_error_with_auth_hint(err: &str) -> String { ) } +pub fn oracle_error_with_driver_hint(config: &ConnectionConfig, err: &str) -> String { + if config.db_type != DatabaseType::Oracle { + return err.to_string(); + } + if matches!(config.driver_profile.as_deref(), Some("oracle-legacy" | "oracle-10g")) { + return err.to_string(); + } + + let normalized = err.to_lowercase(); + if !normalized.contains("ora-12541") && !err.contains("没有监听程序") { + return err.to_string(); + } + + format!( + "{err}\n\nOracle listener was not reachable with the current driver. If the host and port are correct, try switching Version to Oracle 11g-19c or Oracle 10g." + ) +} + fn oracle_jdbc_connection_string(config: &ConnectionConfig, host: &str, port: u16, database: &str) -> String { if let Some(connection_string) = config.connection_string.as_deref().filter(|value| !value.trim().is_empty()) { let connection_string = connection_string.trim(); @@ -487,6 +505,32 @@ mod tests { assert!(hinted.contains("Current authentication database: admin")); } + #[test] + fn oracle_listener_error_adds_driver_version_hint_for_default_profile() { + let mut cfg = config(DatabaseType::Oracle, Some("ORCL")); + cfg.driver_profile = Some("oracle".to_string()); + let err = "Agent RPC error (-1): ORA-12541: TNS:no listener"; + + let hinted = oracle_error_with_driver_hint(&cfg, err); + + assert!(hinted.starts_with(err)); + assert!(hinted.contains("Oracle 11g-19c")); + assert!(hinted.contains("Oracle 10g")); + } + + #[test] + fn oracle_listener_error_hint_skips_legacy_profiles_and_other_databases() { + let err = "Agent RPC error (-1): ORA-12541: TNS:no listener"; + let mut cfg = config(DatabaseType::Oracle, Some("ORCL")); + cfg.driver_profile = Some("oracle-legacy".to_string()); + + assert_eq!(oracle_error_with_driver_hint(&cfg, err), err); + + cfg.db_type = DatabaseType::OceanbaseOracle; + cfg.driver_profile = None; + assert_eq!(oracle_error_with_driver_hint(&cfg, err), err); + } + #[test] fn oracle_url_uses_sid_or_service_name() { let mut cfg = config(DatabaseType::Oracle, Some("ORCL")); diff --git a/crates/dbx-core/src/connection.rs b/crates/dbx-core/src/connection.rs index 6c28e85c4..09d094b03 100644 --- a/crates/dbx-core/src/connection.rs +++ b/crates/dbx-core/src/connection.rs @@ -8,7 +8,8 @@ use mysql_async::Row as MysqlRow; use crate::agent_connection::{ agent_connect_params, h2_file_path_from_jdbc_url, is_h2_file_connection, mongo_legacy_error_with_auth_hint, - oracle_alternate_connect_config, oracle_auth_fallback_profiles, should_retry_oracle_with_10g_driver, + oracle_alternate_connect_config, oracle_auth_fallback_profiles, oracle_error_with_driver_hint, + should_retry_oracle_with_10g_driver, }; use crate::agent_manager::{JavaRuntimeMode, DEFAULT_JRE_KEY}; use crate::database_capabilities; @@ -577,7 +578,7 @@ impl AppState { ) })?; } else { - return Err(err); + return Err(oracle_error_with_driver_hint(&db_config, &err)); } } PoolKind::Agent(Arc::new(tokio::sync::Mutex::new(client))) diff --git a/src-tauri/src/commands/connection.rs b/src-tauri/src/commands/connection.rs index e31fd3cec..c16e22dd6 100644 --- a/src-tauri/src/commands/connection.rs +++ b/src-tauri/src/commands/connection.rs @@ -3,7 +3,7 @@ use tauri::State; pub use dbx_core::agent_connection::{ agent_connect_params, mongo_legacy_error_with_auth_hint, oracle_alternate_connect_config, - oracle_auth_fallback_profiles, should_retry_oracle_with_10g_driver, + oracle_auth_fallback_profiles, oracle_error_with_driver_hint, should_retry_oracle_with_10g_driver, }; pub use dbx_core::connection::{ connect_bare_metadata_pool, connect_mysql_metadata_pool, connection_url_for_endpoint, metadata_connection_config, @@ -85,7 +85,7 @@ async fn test_agent_connection( )); } } else { - return Err(err); + return Err(oracle_error_with_driver_hint(config, &err)); } } @@ -142,7 +142,7 @@ async fn connect_agent_pool( format!("{err}\n\nFallback with legacy Oracle drivers failed: {}", fallback_errors.join("\n")) })?; } else { - return Err(err); + return Err(oracle_error_with_driver_hint(config, &err)); } }