feat(dameng): full DM8 database support

Adds Dameng DM8 explain/autotrace support and user-management SQL support, with backend autotrace safety checks and escaped CREATE USER SQL.
This commit is contained in:
Quinlevi authored and GitHub committed 2026-06-08 02:07:00 +08:00
1 parent a5659d7637
commit 897e6998fd
22 files changed
+1154 -55

No files matched your search

+66
View File
@@ -451,3 +451,69 @@ pub fn build_database_sql_export(
) -> Result<String, String> {
dbx_core::database_export::build_database_sql_export(options)
}
#[tauri::command]
pub async fn get_explain_info(
state: tauri::State<'_, std::sync::Arc<dbx_core::connection::AppState>>,
connection_id: String,
database: Option<String>,
schema: Option<String>,
sql: String,
mode: Option<String>,
) -> Result<String, String> {
let client = {
let connections = state.connections.read().await;
let pool = connections.get(&connection_id).ok_or_else(|| "Connection not found".to_string())?;
match pool {
dbx_core::connection::PoolKind::Agent(client) => client.clone(),
_ => return Err("Connection is not an agent-based connection".to_string()),
}
};
let config = {
let configs = state.configs.read().await;
configs.get(&connection_id).cloned()
};
let config = config.ok_or_else(|| "Connection config not found".to_string())?;
let timeout_secs = config.query_timeout_secs;
let mut client = client.lock().await;
let mode = mode.unwrap_or_else(|| "explain".to_string());
if mode.eq_ignore_ascii_case("autotrace") && !dbx_core::query_execution_sql::is_safe_dameng_autotrace_sql(&sql) {
return Err("unsafe".to_string());
}
let params = serde_json::json!({
"sql": sql,
"database": database.unwrap_or_default(),
"schema": schema.unwrap_or_default(),
"timeoutSecs": timeout_secs as i64,
"mode": mode,
});
let result: Result<serde_json::Value, String> = client.get_explain_info::<serde_json::Value>(params).await;
match result {
Ok(serde_json::Value::String(s)) => {
eprintln!("[get_explain_info] OK string, len={}", s.len());
Ok(s)
}
Ok(serde_json::Value::Object(obj)) => {
let plan = obj.get("plan").and_then(|v| v.as_str()).unwrap_or("").to_string();
let has_stats = obj.get("has_actual_stats").and_then(|v| v.as_bool()).unwrap_or(false);
eprintln!("[get_explain_info] OK object, plan_len={}, has_actual_stats={}", plan.len(), has_stats);
Ok(plan)
}
Ok(val) => {
eprintln!("[get_explain_info] OK unexpected type: {:?}", val);
Err(format!("Unexpected result type from getExplainInfo: {:?}", val))
}
Err(e) => {
eprintln!("[get_explain_info] error: {e}");
Err(e)
}
}
}
#[tauri::command]
pub fn build_create_user_sql(username: String, password: String, tablespace: String) -> Result<String, String> {
Ok(dbx_core::db_admin_sql::build_create_user_sql(&username, &password, &tablespace))
}