fix(mongodb): support legacy driver fallback
This commit is contained in:
parent
090f073206
commit
7bb869d398
|
|
@ -28,7 +28,7 @@ import { isLocalFileTypeDb } from "@/lib/connectionFile";
|
|||
import { mongodbAuthFailureHint, mongoUrlParam, setMongoUrlParam } from "@/lib/mongoConnectionOptions";
|
||||
import { copyToClipboard } from "@/lib/clipboard";
|
||||
import { showAgentDriverInstallHint, type AgentDriverInstallState } from "@/lib/agentDriverInstallHint";
|
||||
import { ArrowLeft, ArrowDown, ArrowUp, CheckSquare, ChevronRight, Copy, ExternalLink, FilePlus2, FolderOpen, GripVertical, Grid3X3, KeyRound, Link2, List, ListFilter, Loader2, Pipette, Plus, Search, ShieldCheck, Square, Trash2 } from "@lucide/vue";
|
||||
import { ArrowLeft, ArrowDown, ArrowUp, CheckSquare, ChevronRight, CircleHelp, Copy, ExternalLink, FilePlus2, FolderOpen, GripVertical, Grid3X3, KeyRound, Link2, List, ListFilter, Loader2, Pipette, Plus, Search, ShieldCheck, Square, Trash2 } from "@lucide/vue";
|
||||
import { buildDraftVisibleDatabasesConnectionId, connectionCanChooseVisibleDatabases, initialVisibleDatabaseSelection, visibleDatabaseSelectionIsStale } from "@/lib/connectionVisibleDatabases";
|
||||
import { canSaveVisibleDatabaseSelection, filterDatabaseNamesForConnection, isSystemDatabaseName, normalizeVisibleDatabaseSelection } from "@/lib/visibleDatabases";
|
||||
|
||||
|
|
@ -998,6 +998,13 @@ const mongoAuthMechanism = computed({
|
|||
form.value.url_params = setMongoUrlParam(form.value.url_params, "authMechanism", value === "default" ? "" : value);
|
||||
},
|
||||
});
|
||||
const mongoDriverMode = computed({
|
||||
get: () => (form.value.driver_profile === "mongodb-legacy" ? "legacy" : "auto"),
|
||||
set: (value: string) => {
|
||||
form.value.driver_profile = value === "legacy" ? "mongodb-legacy" : "mongodb";
|
||||
form.value.driver_label = value === "legacy" ? "MongoDB (Legacy)" : "MongoDB";
|
||||
},
|
||||
});
|
||||
|
||||
function goToConnectionStep(value = selectedType.value) {
|
||||
if (value !== selectedType.value) {
|
||||
|
|
@ -1029,6 +1036,9 @@ async function testConnection() {
|
|||
const config = connectionConfigForSubmit(editingId.value || uuid());
|
||||
const msg = await api.testConnection(config);
|
||||
if (runId !== testRunId) return;
|
||||
if (config.db_type === "mongodb" && /legacy driver/i.test(msg)) {
|
||||
mongoDriverMode.value = "legacy";
|
||||
}
|
||||
testResult.value = { ok: true, message: msg };
|
||||
} catch (e: any) {
|
||||
if (runId !== testRunId) return;
|
||||
|
|
@ -1101,6 +1111,10 @@ function connectionConfigForSubmit(id: string): ConnectionConfig {
|
|||
} else if (config.db_type === "mongodb") {
|
||||
config.connection_string = normalizeMongoConnectionString(config.connection_string?.trim() || "");
|
||||
}
|
||||
if (config.db_type === "mongodb" && config.driver_profile !== "mongodb-legacy") {
|
||||
config.driver_profile = "mongodb";
|
||||
config.driver_label = "MongoDB";
|
||||
}
|
||||
if (config.db_type !== "oracle") {
|
||||
config.sysdba = undefined;
|
||||
config.oracle_connection_type = undefined;
|
||||
|
|
@ -2493,6 +2507,21 @@ function openExternalUrl(url: string) {
|
|||
|
||||
<!-- MongoDB: URL or form -->
|
||||
<template v-else-if="form.db_type === 'mongodb'">
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right text-xs">{{ t("connection.driverMode") }}</Label>
|
||||
<div class="col-span-3 flex items-center gap-2">
|
||||
<Button size="sm" :variant="mongoDriverMode === 'legacy' ? 'outline' : 'default'" @click="mongoDriverMode = 'auto'">{{ t("connection.mongoDriverAuto") }}</Button>
|
||||
<Button size="sm" :variant="mongoDriverMode === 'legacy' ? 'default' : 'outline'" @click="mongoDriverMode = 'legacy'">{{ t("connection.mongoDriverLegacy") }}</Button>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<CircleHelp class="h-3.5 w-3.5 cursor-help text-muted-foreground hover:text-foreground" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" align="center" class="max-w-[320px] text-xs leading-relaxed">
|
||||
{{ t("connection.mongoLegacyHint") }}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right text-xs">{{ t("connection.mode") }}</Label>
|
||||
<div class="col-span-3 flex gap-2">
|
||||
|
|
@ -2556,12 +2585,6 @@ function openExternalUrl(url: string) {
|
|||
<Label class="text-right">{{ t("connection.urlParams") }}</Label>
|
||||
<Input v-model="form.url_params" class="col-span-3" placeholder="authSource=admin&authMechanism=SCRAM-SHA-1" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-start gap-4">
|
||||
<span />
|
||||
<p class="col-span-3 text-xs text-muted-foreground">
|
||||
{{ t("connection.mongoLegacyHint") }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const assetIcons: Record<string, string> = {
|
|||
turso: "turso.png",
|
||||
redis: "redis",
|
||||
mongodb: "mongodb",
|
||||
mongodb_legacy: "mongodb",
|
||||
clickhouse: "clickhouse",
|
||||
duckdb: "duckdb",
|
||||
mariadb: "mariadb",
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@
|
|||
authDatabasePlaceholder: "Optional, often admin",
|
||||
authMechanism: "Auth Mechanism",
|
||||
authMechanismDefault: "Default",
|
||||
driverMode: "Driver",
|
||||
mongoDriverAuto: "Auto",
|
||||
mongoDriverLegacy: "Legacy",
|
||||
serviceName: "Service/SID",
|
||||
serviceNameOnly: "Service Name",
|
||||
version: "Version",
|
||||
|
|
@ -327,7 +330,7 @@
|
|||
jdbcPluginHint: "Install the DBX JDBC plugin first, then import the database vendor's JDBC driver JAR.",
|
||||
dmCompatHint: "Requires DM8 ODBC driver installed on your system.",
|
||||
dmDownload: "Download from Dameng",
|
||||
mongoLegacyHint: "MongoDB below 4.2 requires the MongoDB (Legacy) driver. If authentication fails and the user was created in admin, set Auth DB to admin.",
|
||||
mongoLegacyHint: "Use Legacy for older MongoDB servers, especially versions below 4.2. If authentication fails and the user was created in admin, set Auth DB to admin.",
|
||||
compatible: "Compatible",
|
||||
mainstream: "Popular",
|
||||
color: "Color",
|
||||
|
|
|
|||
|
|
@ -152,6 +152,9 @@
|
|||
authDatabasePlaceholder: "Opcional, normalmente admin",
|
||||
authMechanism: "Mecanismo de autenticación",
|
||||
authMechanismDefault: "Predeterminado",
|
||||
driverMode: "Controlador",
|
||||
mongoDriverAuto: "Automático",
|
||||
mongoDriverLegacy: "Legacy",
|
||||
serviceName: "Servicio/SID",
|
||||
serviceNameOnly: "Nombre de servicio",
|
||||
version: "Versión",
|
||||
|
|
@ -306,7 +309,7 @@
|
|||
jdbcPluginHint: "Instala primero el plugin JDBC de DBX y luego importa el JAR del driver JDBC del proveedor.",
|
||||
dmCompatHint: "Requiere el driver ODBC DM8 instalado en el sistema.",
|
||||
dmDownload: "Descargar desde Dameng",
|
||||
mongoLegacyHint: "MongoDB inferior a 4.2 requiere el controlador MongoDB (Legacy) del Gestor de controladores; la conexión cambiará automáticamente.",
|
||||
mongoLegacyHint: "Usa Legacy para servidores MongoDB antiguos, especialmente versiones anteriores a 4.2. Si falla la autenticación y el usuario se creó en admin, define Auth DB como admin.",
|
||||
compatible: "Compatible",
|
||||
mainstream: "Popular",
|
||||
color: "Color",
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@
|
|||
authDatabasePlaceholder: "Opzionale, spesso admin",
|
||||
authMechanism: "Meccanismo di Autenticazione",
|
||||
authMechanismDefault: "Predefinito",
|
||||
driverMode: "Driver",
|
||||
mongoDriverAuto: "Automatico",
|
||||
mongoDriverLegacy: "Legacy",
|
||||
serviceName: "Servizio/SID",
|
||||
serviceNameOnly: "Nome Servizio",
|
||||
version: "Versione",
|
||||
|
|
@ -311,7 +314,7 @@
|
|||
jdbcPluginHint: "Installa prima il plugin DBX JDBC, quindi importa il file JAR del driver JDBC del fornitore del database.",
|
||||
dmCompatHint: "Richiede il driver ODBC DM8 installato sul sistema.",
|
||||
dmDownload: "Scarica da Dameng",
|
||||
mongoLegacyHint: "MongoDB precedente a 4.2 richiede il driver MongoDB (Legacy). Se l'autenticazione fallisce e l'utente è stato creato in admin, imposta DB di Autenticazione su admin.",
|
||||
mongoLegacyHint: "Usa Legacy per server MongoDB meno recenti, specialmente versioni precedenti alla 4.2. Se l'autenticazione fallisce e l'utente è stato creato in admin, imposta DB di Autenticazione su admin.",
|
||||
compatible: "Compatibile",
|
||||
mainstream: "Popolare",
|
||||
color: "Colore",
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@
|
|||
authDatabasePlaceholder: "Opcional, geralmente admin",
|
||||
authMechanism: "Mecanismo de Autenticação",
|
||||
authMechanismDefault: "Padrão",
|
||||
driverMode: "Driver",
|
||||
mongoDriverAuto: "Automático",
|
||||
mongoDriverLegacy: "Legacy",
|
||||
serviceName: "Service/SID",
|
||||
serviceNameOnly: "Service Name",
|
||||
version: "Versão",
|
||||
|
|
@ -311,7 +314,7 @@
|
|||
jdbcPluginHint: "Instale primeiro o plugin JDBC do DBX e depois importe o JAR do driver JDBC do fornecedor do banco de dados.",
|
||||
dmCompatHint: "Requer o driver ODBC DM8 instalado no seu sistema.",
|
||||
dmDownload: "Baixar da Dameng",
|
||||
mongoLegacyHint: "MongoDB abaixo de 4.2 requer o driver MongoDB (Legacy). Se a autenticação falhar e o usuário foi criado em admin, defina o BD de autenticação como admin.",
|
||||
mongoLegacyHint: "Use Legacy para servidores MongoDB antigos, especialmente versões anteriores à 4.2. Se a autenticação falhar e o usuário foi criado em admin, defina o BD de autenticação como admin.",
|
||||
compatible: "Compatível",
|
||||
mainstream: "Popular",
|
||||
color: "Cor",
|
||||
|
|
|
|||
|
|
@ -160,6 +160,9 @@
|
|||
authDatabasePlaceholder: "可选,通常为 admin",
|
||||
authMechanism: "认证机制",
|
||||
authMechanismDefault: "默认",
|
||||
driverMode: "驱动",
|
||||
mongoDriverAuto: "自动",
|
||||
mongoDriverLegacy: "旧版兼容",
|
||||
serviceName: "服务名/SID",
|
||||
serviceNameOnly: "服务名",
|
||||
version: "版本",
|
||||
|
|
@ -328,7 +331,7 @@
|
|||
jdbcPluginHint: "先安装 DBX JDBC 插件,再导入数据库厂商提供的 JDBC 驱动 JAR。",
|
||||
dmCompatHint: "需要在系统上安装达梦 DM8 ODBC 驱动程序。",
|
||||
dmDownload: "前往达梦官网下载",
|
||||
mongoLegacyHint: "MongoDB 4.2 以下版本需安装 MongoDB (Legacy) 驱动。若账号创建在 admin 且认证失败,请将认证库设为 admin。",
|
||||
mongoLegacyHint: "旧版 MongoDB(尤其是 4.2 以下版本)请选择旧版兼容。若账号创建在 admin 且认证失败,请将认证库设为 admin。",
|
||||
compatible: "兼容",
|
||||
mainstream: "主流",
|
||||
color: "颜色",
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@
|
|||
authDatabasePlaceholder: "可選,通常為 admin",
|
||||
authMechanism: "認證機制",
|
||||
authMechanismDefault: "預設",
|
||||
driverMode: "驅動",
|
||||
mongoDriverAuto: "自動",
|
||||
mongoDriverLegacy: "舊版相容",
|
||||
serviceName: "服務/SID",
|
||||
serviceNameOnly: "服務名稱",
|
||||
version: "版本",
|
||||
|
|
@ -311,7 +314,7 @@
|
|||
jdbcPluginHint: "先安裝 DBX JDBC 外掛程式,再匯入資料庫廠商提供的 JDBC 驅動程式 JAR。",
|
||||
dmCompatHint: "需要在系統上安裝達夢 DM8 ODBC 驅動程式。",
|
||||
dmDownload: "前往達夢官網下載",
|
||||
mongoLegacyHint: "MongoDB 4.2 以下版本需安裝 MongoDB (Legacy) 驅動程式。若帳號建立在 admin 且認證失敗,請將認證庫設為 admin。",
|
||||
mongoLegacyHint: "舊版 MongoDB(尤其是 4.2 以下版本)請選擇舊版相容。若帳號建立在 admin 且認證失敗,請將認證庫設為 admin。",
|
||||
compatible: "相容",
|
||||
mainstream: "熱門",
|
||||
color: "顏色",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export interface AgentDriverInstallState {
|
|||
|
||||
function agentDriverInstallKey(dbType: DatabaseType | undefined, driverProfile?: string): string | undefined {
|
||||
if (dbType === "oracle") return "oracle";
|
||||
if (dbType === "mongodb") return "mongodb";
|
||||
return driverProfile && driverProfile !== dbType ? driverProfile : dbType;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,13 @@ const GBASE_PROFILES: &[AgentDriverProfile] = &[
|
|||
AgentDriverProfile { profile: "gbase8a", key: "gbase8a", label: "GBase 8a", store_visible: true },
|
||||
];
|
||||
|
||||
const MONGODB_PROFILES: &[AgentDriverProfile] = &[AgentDriverProfile {
|
||||
profile: "mongodb-legacy",
|
||||
key: "mongodb",
|
||||
label: "MongoDB (Legacy)",
|
||||
store_visible: false,
|
||||
}];
|
||||
|
||||
const AGENT_CATALOG: &[AgentCatalogEntry] = &[
|
||||
AgentCatalogEntry {
|
||||
db_type: DatabaseType::Dameng,
|
||||
|
|
@ -246,7 +253,7 @@ const AGENT_CATALOG: &[AgentCatalogEntry] = &[
|
|||
key: "mongodb",
|
||||
label: "MongoDB (Legacy)",
|
||||
store_visible: true,
|
||||
profiles: &[],
|
||||
profiles: MONGODB_PROFILES,
|
||||
},
|
||||
AgentCatalogEntry {
|
||||
db_type: DatabaseType::Iris,
|
||||
|
|
|
|||
|
|
@ -190,6 +190,30 @@ pub fn mongo_legacy_error_with_auth_hint(err: &str) -> String {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn mongo_uses_legacy_driver(config: &ConnectionConfig) -> bool {
|
||||
config.driver_profile.as_deref().is_some_and(|profile| {
|
||||
profile.eq_ignore_ascii_case("mongodb-legacy")
|
||||
|| profile.eq_ignore_ascii_case("mongodb_legacy")
|
||||
|| profile.eq_ignore_ascii_case("legacy")
|
||||
})
|
||||
}
|
||||
|
||||
pub fn should_retry_mongo_with_legacy_driver(err: &str) -> bool {
|
||||
let normalized = err.to_lowercase();
|
||||
if normalized.contains("wire version") {
|
||||
return true;
|
||||
}
|
||||
|
||||
let looks_like_handshake_io_error = normalized.contains("unexpected end of file")
|
||||
|| normalized.contains("connection reset by peer")
|
||||
|| normalized.contains("broken pipe");
|
||||
looks_like_handshake_io_error
|
||||
&& (normalized.contains("server selection timeout")
|
||||
|| normalized.contains("no available servers")
|
||||
|| normalized.contains("topology:")
|
||||
|| normalized.contains("i/o error"))
|
||||
}
|
||||
|
||||
pub fn oracle_error_with_driver_hint(config: &ConnectionConfig, err: &str) -> String {
|
||||
if config.db_type != DatabaseType::Oracle {
|
||||
return err.to_string();
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ 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_labels, oracle_alternate_connect_configs, oracle_auth_fallback_profiles,
|
||||
oracle_error_with_driver_hint, should_retry_oracle_with_10g_driver,
|
||||
mongo_uses_legacy_driver, oracle_alternate_connect_config_labels, oracle_alternate_connect_configs,
|
||||
oracle_auth_fallback_profiles, oracle_error_with_driver_hint, should_retry_mongo_with_legacy_driver,
|
||||
should_retry_oracle_with_10g_driver,
|
||||
};
|
||||
use crate::agent_manager::{JavaRuntimeMode, DEFAULT_JRE_KEY};
|
||||
use crate::database_capabilities;
|
||||
|
|
@ -437,35 +438,49 @@ impl AppState {
|
|||
return Err("DuckDB support is not compiled in this build. Rebuild with default features.".to_string());
|
||||
}
|
||||
DatabaseType::MongoDb => {
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout, idle_timeout).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(
|
||||
&client,
|
||||
connect_timeout,
|
||||
db_config.effective_database(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let mut conns = self.connections.write().await;
|
||||
// Re-check: another task may have created the pool while we were connecting.
|
||||
if conns.contains_key(&pool_key) {
|
||||
return Ok(pool_key);
|
||||
}
|
||||
conns.insert(pool_key.clone(), PoolKind::MongoDb(client));
|
||||
return Ok(pool_key);
|
||||
}
|
||||
Err(e) => e,
|
||||
},
|
||||
Err(e) => e,
|
||||
};
|
||||
if native_err.contains("wire version") {
|
||||
log::info!("Native MongoDB driver failed ({native_err}), falling back to agent driver");
|
||||
if mongo_uses_legacy_driver(&db_config) {
|
||||
log::info!("Using configured MongoDB legacy driver for connection_id={connection_id}");
|
||||
let connect_params = serde_json::json!({ "connection": agent_connect_params(&db_config, &host, port, db_config.effective_database().unwrap_or("")) });
|
||||
let mut client = self.agent_manager.spawn(&DatabaseType::MongoDb, None).await?;
|
||||
let mut client = self.agent_manager.spawn(&DatabaseType::MongoDb, Some("mongodb-legacy")).await?;
|
||||
client.connect(connect_params).await.map_err(|err| mongo_legacy_error_with_auth_hint(&err))?;
|
||||
PoolKind::Agent(Arc::new(tokio::sync::Mutex::new(client)))
|
||||
} else {
|
||||
return Err(native_err);
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout, idle_timeout).await {
|
||||
Ok(client) => match db::mongo_driver::test_connection(
|
||||
&client,
|
||||
connect_timeout,
|
||||
db_config.effective_database(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
let mut conns = self.connections.write().await;
|
||||
// Re-check: another task may have created the pool while we were connecting.
|
||||
if conns.contains_key(&pool_key) {
|
||||
return Ok(pool_key);
|
||||
}
|
||||
conns.insert(pool_key.clone(), PoolKind::MongoDb(client));
|
||||
return Ok(pool_key);
|
||||
}
|
||||
Err(e) => e,
|
||||
},
|
||||
Err(e) => e,
|
||||
};
|
||||
if should_retry_mongo_with_legacy_driver(&native_err) {
|
||||
log::info!("Native MongoDB driver failed ({native_err}), falling back to agent driver");
|
||||
let connect_params = serde_json::json!({ "connection": agent_connect_params(&db_config, &host, port, db_config.effective_database().unwrap_or("")) });
|
||||
let mut client =
|
||||
self.agent_manager.spawn(&DatabaseType::MongoDb, Some("mongodb-legacy")).await?;
|
||||
client.connect(connect_params).await.map_err(|err| {
|
||||
format!(
|
||||
"{native_err}\n\nFallback with MongoDB (Legacy) driver failed: {}",
|
||||
mongo_legacy_error_with_auth_hint(&err)
|
||||
)
|
||||
})?;
|
||||
PoolKind::Agent(Arc::new(tokio::sync::Mutex::new(client)))
|
||||
} else {
|
||||
return Err(native_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
DatabaseType::ClickHouse => {
|
||||
|
|
@ -1297,8 +1312,8 @@ mod tests {
|
|||
AppState, PoolKind,
|
||||
};
|
||||
use crate::agent_connection::{
|
||||
agent_connect_params, mongo_legacy_error_with_auth_hint, oracle_alternate_connect_config,
|
||||
should_retry_oracle_with_10g_driver,
|
||||
agent_connect_params, mongo_legacy_error_with_auth_hint, mongo_uses_legacy_driver,
|
||||
oracle_alternate_connect_config, should_retry_mongo_with_legacy_driver, should_retry_oracle_with_10g_driver,
|
||||
};
|
||||
use crate::agent_manager::{AgentState, JavaRuntimeConfig, JavaRuntimeMode, DEFAULT_JRE_KEY};
|
||||
use crate::db;
|
||||
|
|
@ -1433,6 +1448,19 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongo_legacy_retry_covers_old_server_handshake_eof() {
|
||||
let err = r#"MongoDB connection failed: Kind: Server selection timeout: No available servers. Topology: { Type: Unknown, Servers: [ { Address: db.example.com:27017, Type: Unknown, Error: Kind: I/O error: unexpected end of file } ] }"#;
|
||||
|
||||
assert!(mongo_uses_legacy_driver(&ConnectionConfig {
|
||||
driver_profile: Some("mongodb-legacy".to_string()),
|
||||
..mysql_config(None)
|
||||
}));
|
||||
assert!(should_retry_mongo_with_legacy_driver(err));
|
||||
assert!(should_retry_mongo_with_legacy_driver("server reports wire version 5, but this driver requires 8"));
|
||||
assert!(!should_retry_mongo_with_legacy_driver("Authentication failed."));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_connect_params_build_oracle_service_connection_string() {
|
||||
let mut config = mysql_config(Some("ORCLPDB1"));
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use std::sync::Arc;
|
|||
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, oracle_error_with_driver_hint, should_retry_oracle_with_10g_driver,
|
||||
agent_connect_params, mongo_legacy_error_with_auth_hint, mongo_uses_legacy_driver, oracle_alternate_connect_config,
|
||||
oracle_auth_fallback_profiles, oracle_error_with_driver_hint, should_retry_mongo_with_legacy_driver,
|
||||
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,
|
||||
|
|
@ -333,6 +334,17 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
|||
#[cfg(not(feature = "duckdb-bundled"))]
|
||||
DatabaseType::DuckDb => Err("DuckDB support not compiled (enable duckdb-bundled feature)".to_string()),
|
||||
DatabaseType::MongoDb => {
|
||||
if mongo_uses_legacy_driver(&config) {
|
||||
let am = &state.agent_manager;
|
||||
let mut client = am.spawn(&config.db_type, config.driver_profile.as_deref()).await?;
|
||||
client
|
||||
.connect(mongo_legacy_connect_params(&config, &host, port))
|
||||
.await
|
||||
.map_err(|err| mongo_legacy_error_with_auth_hint(&err))?;
|
||||
client.disconnect().await.ok();
|
||||
return Ok("Connection successful (via legacy driver)".to_string());
|
||||
}
|
||||
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout, idle_timeout).await {
|
||||
Ok(client) => {
|
||||
match db::mongo_driver::test_connection(&client, connect_timeout, config.effective_database())
|
||||
|
|
@ -344,13 +356,15 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
|||
}
|
||||
Err(e) => e,
|
||||
};
|
||||
if native_err.contains("wire version") {
|
||||
if should_retry_mongo_with_legacy_driver(&native_err) {
|
||||
let am = &state.agent_manager;
|
||||
let mut client = am.spawn(&config.db_type, config.driver_profile.as_deref()).await?;
|
||||
client
|
||||
.connect(mongo_legacy_connect_params(&config, &host, port))
|
||||
.await
|
||||
.map_err(|err| mongo_legacy_error_with_auth_hint(&err))?;
|
||||
let mut client = am.spawn(&config.db_type, Some("mongodb-legacy")).await?;
|
||||
client.connect(mongo_legacy_connect_params(&config, &host, port)).await.map_err(|err| {
|
||||
format!(
|
||||
"{native_err}\n\nFallback with MongoDB (Legacy) driver failed: {}",
|
||||
mongo_legacy_error_with_auth_hint(&err)
|
||||
)
|
||||
})?;
|
||||
client.disconnect().await.ok();
|
||||
Ok("Connection successful (via legacy driver)".to_string())
|
||||
} else {
|
||||
|
|
@ -542,29 +556,46 @@ pub async fn connect_db(state: State<'_, Arc<AppState>>, config: ConnectionConfi
|
|||
#[cfg(not(feature = "duckdb-bundled"))]
|
||||
DatabaseType::DuckDb => return Err("DuckDB support not compiled (enable duckdb-bundled feature)".to_string()),
|
||||
DatabaseType::MongoDb => {
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout, idle_timeout).await {
|
||||
Ok(client) => {
|
||||
match db::mongo_driver::test_connection(&client, connect_timeout, db_config.effective_database())
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
state.configs.write().await.insert(id.clone(), config);
|
||||
state.connections.write().await.insert(id.clone(), PoolKind::MongoDb(client));
|
||||
return Ok(id);
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
};
|
||||
if native_err.contains("wire version") {
|
||||
log::info!("Native MongoDB driver failed ({native_err}), falling back to agent driver");
|
||||
let mut client =
|
||||
state.agent_manager.spawn(&db_config.db_type, db_config.driver_profile.as_deref()).await?;
|
||||
client.connect(mongo_legacy_connect_params(&db_config, &host, port)).await?;
|
||||
if mongo_uses_legacy_driver(&db_config) {
|
||||
let mut client = state.agent_manager.spawn(&db_config.db_type, Some("mongodb-legacy")).await?;
|
||||
client
|
||||
.connect(mongo_legacy_connect_params(&db_config, &host, port))
|
||||
.await
|
||||
.map_err(|err| mongo_legacy_error_with_auth_hint(&err))?;
|
||||
PoolKind::Agent(std::sync::Arc::new(tokio::sync::Mutex::new(client)))
|
||||
} else {
|
||||
return Err(native_err);
|
||||
let native_err = match db::mongo_driver::connect(&url, connect_timeout, idle_timeout).await {
|
||||
Ok(client) => {
|
||||
match db::mongo_driver::test_connection(
|
||||
&client,
|
||||
connect_timeout,
|
||||
db_config.effective_database(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(()) => {
|
||||
state.configs.write().await.insert(id.clone(), config);
|
||||
state.connections.write().await.insert(id.clone(), PoolKind::MongoDb(client));
|
||||
return Ok(id);
|
||||
}
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
Err(e) => e,
|
||||
};
|
||||
if should_retry_mongo_with_legacy_driver(&native_err) {
|
||||
log::info!("Native MongoDB driver failed ({native_err}), falling back to agent driver");
|
||||
let mut client = state.agent_manager.spawn(&db_config.db_type, Some("mongodb-legacy")).await?;
|
||||
client.connect(mongo_legacy_connect_params(&db_config, &host, port)).await.map_err(|err| {
|
||||
format!(
|
||||
"{native_err}\n\nFallback with MongoDB (Legacy) driver failed: {}",
|
||||
mongo_legacy_error_with_auth_hint(&err)
|
||||
)
|
||||
})?;
|
||||
PoolKind::Agent(std::sync::Arc::new(tokio::sync::Mutex::new(client)))
|
||||
} else {
|
||||
return Err(native_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
DatabaseType::ClickHouse => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue