fix(oracle): honor sysdba agent connections

This commit is contained in:
t8y2
2026-06-03 15:33:05 +08:00
parent fbe64de315
commit f8fc284c54
3 changed files with 54 additions and 3 deletions
@@ -103,6 +103,7 @@ const defaultForm = (): Omit<ConnectionConfig, "id"> => ({
proxy_password: "",
ssl: false,
ca_cert_path: "",
sysdba: false,
oracle_connection_type: "service_name",
connection_string: undefined,
jdbc_driver_class: undefined,
@@ -447,6 +448,7 @@ watch(
proxy_password: config.proxy_password || "",
ssl: config.ssl || false,
ca_cert_path: config.ca_cert_path || "",
sysdba: config.sysdba || isOracleSysUser(config),
oracle_connection_type: config.oracle_connection_type || "service_name",
connection_string: config.connection_string,
jdbc_driver_class: config.jdbc_driver_class,
@@ -898,8 +900,10 @@ function connectionConfigForSubmit(id: string): ConnectionConfig {
config.connection_string = normalizeMongoConnectionString(config.connection_string?.trim() || "");
}
if (config.db_type !== "oracle") {
config.sysdba = undefined;
config.oracle_connection_type = undefined;
} else {
config.sysdba = !!config.sysdba || isOracleSysUser(config);
config.oracle_connection_type = config.oracle_connection_type || "service_name";
}
if (config.db_type !== "redis") {
@@ -1123,6 +1127,10 @@ function parseRedisEndpoint(value: string, defaultPort: number): { host: string;
return { host: endpoint, port: defaultPort };
}
function isOracleSysUser(config: Pick<ConnectionConfig, "db_type" | "username">): boolean {
return config.db_type === "oracle" && config.username.trim().toLowerCase() === "sys";
}
function resetTestState() {
testRunId += 1;
isTesting.value = false;
@@ -1257,6 +1265,10 @@ watch(
},
);
watch([() => form.value.db_type, () => form.value.username], () => {
if (isOracleSysUser(form.value)) form.value.sysdba = true;
});
watch(canUseSsh, (value) => {
if (!value && configTab.value === "ssh") {
configTab.value = "connection";
@@ -2247,7 +2259,7 @@ function openExternalUrl(url: string) {
<div v-if="form.db_type === 'oracle'" class="grid grid-cols-4 items-center gap-4">
<Label class="text-right text-xs">SYSDBA</Label>
<label class="col-span-3 flex items-center gap-2 cursor-pointer">
<input type="checkbox" v-model="form.sysdba" class="mr-0" />
<input type="checkbox" v-model="form.sysdba" class="mr-0" :disabled="isOracleSysUser(form)" />
<span class="text-xs text-muted-foreground">as SYSDBA</span>
</label>
</div>
+40 -1
View File
@@ -5,6 +5,8 @@ use crate::models::connection::{ConnectionConfig, DatabaseType};
pub fn agent_connect_params(config: &ConnectionConfig, host: &str, port: u16, database: &str) -> serde_json::Value {
let agent_database = if config.db_type == DatabaseType::MongoDb {
mongo_agent_database(config, database)
} else if config.db_type == DatabaseType::Oracle {
oracle_agent_database(config, database)
} else {
database.to_string()
};
@@ -26,12 +28,24 @@ pub fn agent_connect_params(config: &ConnectionConfig, host: &str, port: u16, da
"database": agent_database,
"username": config.username,
"password": config.password,
"sysdba": config.sysdba,
"sysdba": oracle_uses_sysdba(config),
"url_params": config.url_params.as_deref().unwrap_or(""),
"connection_string": connection_string,
})
}
fn oracle_uses_sysdba(config: &ConnectionConfig) -> bool {
config.sysdba || (config.db_type == DatabaseType::Oracle && config.username.trim().eq_ignore_ascii_case("sys"))
}
fn oracle_agent_database(config: &ConnectionConfig, database: &str) -> String {
let database = database.trim();
if database.is_empty() || !oracle_uses_sysdba(config) || database.to_uppercase().starts_with("SYSDBA:") {
return database.to_string();
}
format!("SYSDBA:{database}")
}
fn mongo_agent_database(config: &ConnectionConfig, database: &str) -> String {
if let Some(database) = non_empty_database(database) {
return database.to_string();
@@ -278,6 +292,31 @@ mod tests {
assert_eq!(service["connection_string"], "jdbc:oracle:thin:@//oracle.example.com:1521/ORCL");
}
#[test]
fn oracle_sys_user_connects_as_sysdba_for_agent_protocol() {
let mut cfg = config(DatabaseType::Oracle, Some("ORCLPDB1"));
cfg.username = "SYS".to_string();
cfg.oracle_connection_type = Some("service_name".to_string());
let params = agent_connect_params(&cfg, "oracle.example.com", 1521, "ORCLPDB1");
assert_eq!(params["database"], "SYSDBA:ORCLPDB1");
assert_eq!(params["sysdba"], true);
assert_eq!(params["connection_string"], "jdbc:oracle:thin:@//oracle.example.com:1521/ORCLPDB1");
}
#[test]
fn oracle_sysdba_checkbox_connects_as_sysdba_for_agent_protocol() {
let mut cfg = config(DatabaseType::Oracle, Some("ORCLPDB1"));
cfg.username = "system".to_string();
cfg.sysdba = true;
let params = agent_connect_params(&cfg, "oracle.example.com", 1521, "ORCLPDB1");
assert_eq!(params["database"], "SYSDBA:ORCLPDB1");
assert_eq!(params["sysdba"], true);
}
#[test]
fn oracle_url_preserves_custom_jdbc_descriptor_and_rewrites_host_port() {
let mut cfg = config(DatabaseType::Oracle, Some("ORCL"));
+1 -1
View File
@@ -1183,7 +1183,7 @@ mod tests {
let params = agent_connect_params(&config, "oracle.example.com", 1521, "ORCLPDB1");
assert_eq!(params["database"], "ORCLPDB1");
assert_eq!(params["database"], "SYSDBA:ORCLPDB1");
assert_eq!(params["sysdba"], true);
assert_eq!(params["connection_string"], "jdbc:oracle:thin:@//oracle.example.com:1521/ORCLPDB1");
}