fix(db): normalize default database handling

This commit is contained in:
t8y2
2026-05-09 15:53:06 +08:00
parent 5cffe12014
commit af029daf57
8 changed files with 144 additions and 30 deletions
+23 -8
View File
@@ -58,10 +58,7 @@ pub fn metadata_connection_config(config: &ConnectionConfig) -> ConnectionConfig
pub fn database_connection_config(config: &ConnectionConfig, database: Option<&str>) -> ConnectionConfig {
let mut db_config = if database.is_some() { config.clone() } else { metadata_connection_config(config) };
if let Some(db) = database {
if db_config.db_type != DatabaseType::Oracle
&& db_config.db_type != DatabaseType::Dameng
&& db_config.db_type != DatabaseType::Gaussdb
{
if db_config.db_type != DatabaseType::Oracle && db_config.db_type != DatabaseType::Dameng {
db_config.database = Some(db.to_string());
}
}
@@ -90,8 +87,7 @@ impl AppState {
return Ok(connection_id.to_string());
}
let is_single_conn =
matches!(db_type, Some(DatabaseType::Oracle) | Some(DatabaseType::Dameng) | Some(DatabaseType::Gaussdb));
let is_single_conn = matches!(db_type, Some(DatabaseType::Oracle) | Some(DatabaseType::Dameng));
let pool_key = if is_single_conn {
connection_id.to_string()
} else {
@@ -207,7 +203,7 @@ impl AppState {
let client = db::gaussdb_driver::connect(
&host,
port,
db_config.database.as_deref().unwrap_or(""),
db_config.effective_database().unwrap_or("postgres"),
&db_config.username,
&db_config.password,
)
@@ -272,7 +268,6 @@ impl AppState {
c.db_type == DatabaseType::Oracle
|| c.db_type == DatabaseType::Elasticsearch
|| c.db_type == DatabaseType::Dameng
|| c.db_type == DatabaseType::Gaussdb
})
.unwrap_or(false)
};
@@ -378,4 +373,24 @@ mod tests {
assert_eq!(scoped.database.as_deref(), Some("analytics"));
}
#[test]
fn gaussdb_database_connection_keeps_requested_database() {
let mut config = mysql_config(Some("postgres"));
config.db_type = DatabaseType::Gaussdb;
let scoped = database_connection_config(&config, Some("analytics"));
assert_eq!(scoped.database.as_deref(), Some("analytics"));
}
#[test]
fn oracle_database_connection_ignores_requested_database() {
let mut config = mysql_config(Some("ORCL"));
config.db_type = DatabaseType::Oracle;
let scoped = database_connection_config(&config, Some("analytics"));
assert_eq!(scoped.database.as_deref(), Some("ORCL"));
}
}
+26
View File
@@ -30,6 +30,7 @@ impl GaussdbClient {
}
pub async fn connect(host: &str, port: u16, database: &str, user: &str, pass: &str) -> Result<GaussdbClient, String> {
let database = normalize_database(database);
let dsn = format!("host={host} port={port} user={user} password={pass} dbname={database}");
let result = tokio::time::timeout(std::time::Duration::from_secs(CONNECTION_TIMEOUT_SECS), async {
@@ -41,6 +42,15 @@ pub async fn connect(host: &str, port: u16, database: &str, user: &str, pass: &s
result.map(|client| GaussdbClient { client })
}
fn normalize_database(database: &str) -> &str {
let database = database.trim();
if database.is_empty() {
"postgres"
} else {
database
}
}
pub async fn list_databases(client: &mut GaussdbClient) -> Result<Vec<DatabaseInfo>, String> {
let rows = client
.query_single_column("SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname")
@@ -276,3 +286,19 @@ pub async fn execute_query(client: &mut GaussdbClient, sql: &str) -> Result<Quer
})
}
}
#[cfg(test)]
mod tests {
use super::normalize_database;
#[test]
fn normalize_database_defaults_blank_to_postgres() {
assert_eq!(normalize_database(""), "postgres");
assert_eq!(normalize_database(" "), "postgres");
}
#[test]
fn normalize_database_keeps_explicit_database() {
assert_eq!(normalize_database("app"), "app");
}
}
+63 -12
View File
@@ -75,6 +75,26 @@ pub enum DatabaseType {
}
impl ConnectionConfig {
pub fn effective_database(&self) -> Option<&str> {
self.database
.as_deref()
.map(str::trim)
.filter(|database| !database.is_empty())
.or_else(|| self.default_database())
}
fn default_database(&self) -> Option<&'static str> {
match self.db_type {
DatabaseType::Postgres => match self.driver_profile.as_deref() {
Some("cockroachdb") => Some("defaultdb"),
_ => Some("postgres"),
},
DatabaseType::Redshift => Some("dev"),
DatabaseType::Gaussdb => Some("postgres"),
_ => None,
}
}
pub fn needs_bare_mysql(&self) -> bool {
matches!(self.db_type, DatabaseType::Doris | DatabaseType::StarRocks)
|| self
@@ -94,12 +114,7 @@ impl ConnectionConfig {
pub fn redacted_connection_url_with_host(&self, host: &str, port: u16) -> String {
let host = bracket_ipv6(host);
let db_part = self
.database
.as_deref()
.filter(|d| !d.is_empty())
.map(|d| format!("/{}", encode_url_part(d)))
.unwrap_or_default();
let db_part = self.effective_database().map(|d| format!("/{}", encode_url_part(d))).unwrap_or_default();
let params = self.normalized_url_params();
match self.db_type {
@@ -148,12 +163,7 @@ impl ConnectionConfig {
pub fn connection_url_with_host(&self, host: &str, port: u16) -> String {
let host = bracket_ipv6(host);
let db_part = self
.database
.as_deref()
.filter(|d| !d.is_empty())
.map(|d| format!("/{}", encode_url_part(d)))
.unwrap_or_default();
let db_part = self.effective_database().map(|d| format!("/{}", encode_url_part(d))).unwrap_or_default();
let username = encode_url_part(&self.username);
let password = encode_url_part(&self.password);
let params = self.normalized_url_params();
@@ -413,6 +423,47 @@ mod tests {
assert_eq!(config.connection_url(), "postgres://postgres:secret@10.1.2.3:2883/test?sslmode=disable");
}
#[test]
fn postgres_url_defaults_to_postgres_database_when_omitted() {
let mut config = mysql_config("root", "secret", None);
config.db_type = DatabaseType::Postgres;
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/postgres");
}
#[test]
fn postgres_url_defaults_to_postgres_database_when_empty() {
let mut config = mysql_config("root", "secret", Some(""));
config.db_type = DatabaseType::Postgres;
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/postgres");
}
#[test]
fn redshift_url_defaults_to_dev_database_when_empty() {
let mut config = mysql_config("awsuser", "secret", Some(""));
config.db_type = DatabaseType::Redshift;
assert_eq!(config.connection_url(), "postgres://awsuser:secret@10.1.2.3:2883/dev");
}
#[test]
fn cockroachdb_url_defaults_to_defaultdb_database() {
let mut config = mysql_config("root", "secret", None);
config.db_type = DatabaseType::Postgres;
config.driver_profile = Some("cockroachdb".to_string());
assert_eq!(config.connection_url(), "postgres://root:secret@10.1.2.3:2883/defaultdb");
}
#[test]
fn gaussdb_url_defaults_to_postgres_database() {
let mut config = mysql_config("gaussdb", "secret", None);
config.db_type = DatabaseType::Gaussdb;
assert_eq!(config.connection_url(), "gaussdb://gaussdb:secret@10.1.2.3:2883/postgres");
}
#[test]
fn mongodb_form_url_without_params_does_not_force_topology_or_auth() {
let config = mongodb_config("root", "secret", Some("admin"));