fix(connection): preserve Oracle SID fallback
This commit is contained in:
parent
9622080e59
commit
b4e9e798f1
|
|
@ -330,7 +330,7 @@ watch(
|
|||
proxy_username: config.proxy_username || "",
|
||||
proxy_password: config.proxy_password || "",
|
||||
ssl: config.ssl || false,
|
||||
oracle_connection_type: config.oracle_connection_type || "service_name",
|
||||
oracle_connection_type: config.oracle_connection_type || "sid",
|
||||
connection_string: config.connection_string,
|
||||
jdbc_driver_class: config.jdbc_driver_class,
|
||||
jdbc_driver_paths: config.jdbc_driver_paths || [],
|
||||
|
|
|
|||
|
|
@ -595,14 +595,14 @@ fn oracle_jdbc_connection_string(config: &ConnectionConfig, host: &str, port: u1
|
|||
return config.connection_string.as_deref().unwrap_or("").to_string();
|
||||
}
|
||||
|
||||
if config.oracle_connection_type.as_deref() == Some("sid") {
|
||||
format!("jdbc:oracle:thin:@{host}:{port}:{database}")
|
||||
} else {
|
||||
if config.oracle_connection_type.as_deref() == Some("service_name") {
|
||||
format!("jdbc:oracle:thin:@//{host}:{port}/{database}")
|
||||
} else {
|
||||
format!("jdbc:oracle:thin:@{host}:{port}:{database}")
|
||||
}
|
||||
}
|
||||
|
||||
fn should_retry_oracle_with_10g_driver(config: &ConnectionConfig, err: &str) -> bool {
|
||||
pub fn should_retry_oracle_with_10g_driver(config: &ConnectionConfig, err: &str) -> bool {
|
||||
if config.db_type != DatabaseType::Oracle {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -808,6 +808,7 @@ mod tests {
|
|||
config.port = 1521;
|
||||
config.username = "system".to_string();
|
||||
config.password = "oracle".to_string();
|
||||
config.oracle_connection_type = Some("service_name".to_string());
|
||||
|
||||
let params = agent_connect_params(&config, "oracle.example.com", 1521, "ORCLPDB1");
|
||||
|
||||
|
|
@ -826,6 +827,17 @@ mod tests {
|
|||
assert_eq!(params["connection_string"], "jdbc:oracle:thin:@127.0.0.1:11521:ORCL");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_connect_params_preserve_legacy_oracle_configs_as_sid() {
|
||||
let mut config = mysql_config(Some("ORCL"));
|
||||
config.db_type = DatabaseType::Oracle;
|
||||
config.oracle_connection_type = None;
|
||||
|
||||
let params = agent_connect_params(&config, "127.0.0.1", 11521, "ORCL");
|
||||
|
||||
assert_eq!(params["connection_string"], "jdbc:oracle:thin:@127.0.0.1:11521:ORCL");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn oracle_retry_guard_only_triggers_for_non_10g_listener_errors() {
|
||||
let mut config = mysql_config(Some("ORCL"));
|
||||
|
|
|
|||
|
|
@ -15,3 +15,7 @@ test("Oracle connection mode uses an inline option group", () => {
|
|||
assert.match(oracleModeBlock, /form\.oracle_connection_type = 'sid'/);
|
||||
assert.doesNotMatch(oracleModeBlock, /<Select/);
|
||||
});
|
||||
|
||||
test("legacy Oracle edit configs without a mode are shown as SID connections", () => {
|
||||
assert.match(source, /oracle_connection_type: config\.oracle_connection_type \|\| "sid"/);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
|
||||
const coreConnectionSource = readFileSync(new URL("../../crates/dbx-core/src/connection.rs", import.meta.url), "utf8");
|
||||
const tauriConnectionSource = readFileSync(
|
||||
new URL("../../src-tauri/src/commands/connection.rs", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
test("Oracle agent fallback helper is shared with Tauri connection commands", () => {
|
||||
assert.match(coreConnectionSource, /pub fn should_retry_oracle_with_10g_driver/);
|
||||
assert.match(tauriConnectionSource, /should_retry_oracle_with_10g_driver/);
|
||||
});
|
||||
|
||||
test("connection test retries Oracle listener errors with the 10g profile", () => {
|
||||
assert.match(tauriConnectionSource, /async fn test_agent_connection/);
|
||||
assert.match(
|
||||
tauriConnectionSource,
|
||||
/call_daemon_method::<serde_json::Value>\([\s\S]*?AgentMethod::TestConnection[\s\S]*?should_retry_oracle_with_10g_driver/,
|
||||
);
|
||||
assert.match(tauriConnectionSource, /Some\("oracle-10g"\)/);
|
||||
});
|
||||
|
||||
test("initial connect retries Oracle listener errors with the 10g profile", () => {
|
||||
assert.match(tauriConnectionSource, /async fn connect_agent_pool/);
|
||||
assert.match(
|
||||
tauriConnectionSource,
|
||||
/call_method::<serde_json::Value>\([\s\S]*?AgentMethod::Connect[\s\S]*?should_retry_oracle_with_10g_driver/,
|
||||
);
|
||||
});
|
||||
|
|
@ -3,8 +3,8 @@ use tauri::State;
|
|||
|
||||
pub use dbx_core::connection::{
|
||||
agent_connect_params, connection_url_for_endpoint, expand_tilde, metadata_connection_config,
|
||||
mongo_legacy_error_with_auth_hint, probe_connection_endpoint, redacted_connection_url_for_endpoint, AppState,
|
||||
MysqlMode, PoolKind,
|
||||
mongo_legacy_error_with_auth_hint, probe_connection_endpoint, redacted_connection_url_for_endpoint,
|
||||
should_retry_oracle_with_10g_driver, AppState, MysqlMode, PoolKind,
|
||||
};
|
||||
use dbx_core::database_capabilities;
|
||||
use dbx_core::db;
|
||||
|
|
@ -17,6 +17,69 @@ fn mongo_legacy_connect_params(config: &ConnectionConfig, host: &str, port: u16)
|
|||
})
|
||||
}
|
||||
|
||||
async fn test_agent_connection(
|
||||
state: &Arc<AppState>,
|
||||
config: &ConnectionConfig,
|
||||
host: &str,
|
||||
port: u16,
|
||||
) -> Result<String, String> {
|
||||
let connect_params = agent_connect_params(config, host, port, config.database.as_deref().unwrap_or(""));
|
||||
let result = state
|
||||
.agent_manager
|
||||
.call_daemon_method::<serde_json::Value>(
|
||||
&config.db_type,
|
||||
config.driver_profile.as_deref(),
|
||||
AgentMethod::TestConnection,
|
||||
connect_params.clone(),
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Err(err) = result {
|
||||
if should_retry_oracle_with_10g_driver(config, &err) {
|
||||
state
|
||||
.agent_manager
|
||||
.call_daemon_method::<serde_json::Value>(
|
||||
&config.db_type,
|
||||
Some("oracle-10g"),
|
||||
AgentMethod::TestConnection,
|
||||
connect_params,
|
||||
)
|
||||
.await
|
||||
.map_err(|fallback_err| format!("{err}\n\nFallback with oracle-10g driver failed: {fallback_err}"))?;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
|
||||
async fn connect_agent_pool(
|
||||
state: &Arc<AppState>,
|
||||
config: &ConnectionConfig,
|
||||
host: &str,
|
||||
port: u16,
|
||||
) -> Result<PoolKind, String> {
|
||||
let connect_params = agent_connect_params(config, host, port, config.effective_database().unwrap_or(""));
|
||||
let mut client = state.agent_manager.spawn(&config.db_type, config.driver_profile.as_deref()).await?;
|
||||
let connect_result = client.call_method::<serde_json::Value>(AgentMethod::Connect, connect_params.clone()).await;
|
||||
|
||||
if let Err(err) = connect_result {
|
||||
if should_retry_oracle_with_10g_driver(config, &err) {
|
||||
let mut fallback_client = state.agent_manager.spawn(&config.db_type, Some("oracle-10g")).await?;
|
||||
fallback_client
|
||||
.call_method::<serde_json::Value>(AgentMethod::Connect, connect_params)
|
||||
.await
|
||||
.map_err(|fallback_err| format!("{err}\n\nFallback with oracle-10g driver failed: {fallback_err}"))?;
|
||||
client = fallback_client;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PoolKind::Agent(Arc::new(tokio::sync::Mutex::new(client))))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::mongo_legacy_connect_params;
|
||||
|
|
@ -205,16 +268,7 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
|||
db::elasticsearch_driver::test_connection(&client).await.map(|_| "Connection successful".to_string())
|
||||
}
|
||||
db_type if database_capabilities::is_agent_type(&db_type) => {
|
||||
state
|
||||
.agent_manager
|
||||
.call_daemon_method::<serde_json::Value>(
|
||||
&config.db_type,
|
||||
config.driver_profile.as_deref(),
|
||||
AgentMethod::TestConnection,
|
||||
agent_connect_params(&config, &host, port, config.database.as_deref().unwrap_or("")),
|
||||
)
|
||||
.await?;
|
||||
Ok("Connection successful".to_string())
|
||||
test_agent_connection(state.inner(), &config, &host, port).await
|
||||
}
|
||||
DatabaseType::Jdbc => {
|
||||
let mut jdbc_config = config.clone();
|
||||
|
|
@ -328,14 +382,7 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
|||
PoolKind::Elasticsearch(client)
|
||||
}
|
||||
db_type if database_capabilities::is_agent_type(&db_type) => {
|
||||
let mut client = state.agent_manager.spawn(&db_config.db_type, db_config.driver_profile.as_deref()).await?;
|
||||
client
|
||||
.call_method::<serde_json::Value>(
|
||||
AgentMethod::Connect,
|
||||
agent_connect_params(&db_config, &host, port, db_config.effective_database().unwrap_or("")),
|
||||
)
|
||||
.await?;
|
||||
PoolKind::Agent(std::sync::Arc::new(tokio::sync::Mutex::new(client)))
|
||||
connect_agent_pool(state.inner(), &db_config, &host, port).await?
|
||||
}
|
||||
DatabaseType::Jdbc => state.external_driver_pool("jdbc", &db_config).await?,
|
||||
db_type => return Err(format!("Unsupported database type: {db_type:?}")),
|
||||
|
|
|
|||
Loading…
Reference in New Issue