fix(gbase8s): support CREATE DATABASE and open mixed-locale databases

This commit is contained in:
弈秋 authored and GitHub committed 2026-09-16 11:54:56 +08:00
1 parent 4bf073d5d1
commit 72be4ad9eb
5 files changed
+329 -6

No files matched your search

+97 -3
View File
@@ -274,9 +274,18 @@ pub fn build_create_database_sql(options: CreateDatabaseSqlOptions) -> Result<St
}
fn build_create_database_statement(options: &CreateDatabaseSqlOptions) -> Result<String, String> {
if !supports_create_database_target(options.database_type) {
if !supports_create_database_target(options.database_type, options.driver_profile.as_deref()) {
return Err(format!("Creating databases is not supported for {}.", database_label(options.database_type)));
}
if is_informix_family(options.database_type, options.driver_profile.as_deref()) {
// Informix / GBase 8s accept only a bare `CREATE DATABASE <name>`. The new database
// inherits the instance default locale, and the MySQL `CHARACTER SET`/`COLLATE`
// clauses are invalid syntax here. Database names are ordinary identifiers, so quote
// them with the Informix rule (unquoted for simple identifiers) rather than the
// default double-quote path that `DatabaseType::Gbase` would otherwise take.
let name = quote_table_identifier(Some(DatabaseType::Informix), &options.name);
return Ok(format!("CREATE DATABASE {name};"));
}
let name = quote_table_identifier(options.database_type, &options.name);
let charset = clean_sql_option(options.charset.as_deref());
let collation = clean_sql_option(options.collation.as_deref());
@@ -288,7 +297,25 @@ fn build_create_database_statement(options: &CreateDatabaseSqlOptions) -> Result
Ok(format!("CREATE DATABASE {name} CHARACTER SET {charset}{collate_clause};"))
}
pub fn supports_create_database_target(database_type: Option<DatabaseType>) -> bool {
/// Whether the connection belongs to the Informix family: standalone Informix, or GBase 8s
/// (which shares `DatabaseType::Gbase` with the MySQL-based GBase 8a and is only distinguishable
/// through the `gbase8s` driver profile). Informix-family servers accept `CREATE DATABASE` but
/// have no `CREATE SCHEMA <name>` statement (a "schema" is the table owner), so the create
/// targets differ from the rest of the `Gbase` family.
fn is_informix_family(database_type: Option<DatabaseType>, driver_profile: Option<&str>) -> bool {
match database_type {
Some(DatabaseType::Informix) => true,
Some(DatabaseType::Gbase) => driver_profile.is_some_and(|profile| profile.eq_ignore_ascii_case("gbase8s")),
_ => false,
}
}
pub fn supports_create_database_target(database_type: Option<DatabaseType>, driver_profile: Option<&str>) -> bool {
// Informix / GBase 8s create namespaces with `CREATE DATABASE`, so they are valid targets
// even though they are absent from the explicit list below.
if is_informix_family(database_type, driver_profile) {
return true;
}
matches!(
database_type,
Some(
@@ -341,7 +368,6 @@ pub fn supports_create_schema_target(database_type: Option<DatabaseType>) -> boo
| DatabaseType::Trino
| DatabaseType::PrestoSql
| DatabaseType::H2
| DatabaseType::Informix
| DatabaseType::Xugu
| DatabaseType::Oscar
| DatabaseType::Iris
@@ -1406,6 +1432,74 @@ mod tests {
.contains("Creating databases is not supported"));
}
#[test]
fn builds_informix_family_create_database_without_mysql_clause() {
// GBase 8s shares DatabaseType::Gbase with GBase 8a and is only identified by the
// gbase8s driver profile; it must emit a bare, unquoted CREATE DATABASE.
assert_eq!(
build_create_database_sql(CreateDatabaseSqlOptions {
database_type: Some(DatabaseType::Gbase),
driver_profile: Some("gbase8s".to_string()),
target: None,
parent: None,
name: "app_db".to_string(),
charset: Some("utf8mb4".to_string()),
collation: Some("utf8mb4_unicode_ci".to_string()),
})
.unwrap(),
"CREATE DATABASE app_db;"
);
// Standalone Informix behaves the same.
assert_eq!(
build_create_database_sql(CreateDatabaseSqlOptions {
database_type: Some(DatabaseType::Informix),
driver_profile: None,
target: None,
parent: None,
name: "app_db".to_string(),
charset: None,
collation: None,
})
.unwrap(),
"CREATE DATABASE app_db;"
);
}
#[test]
fn gbase8a_is_not_a_create_database_target() {
assert!(build_create_database_sql(CreateDatabaseSqlOptions {
database_type: Some(DatabaseType::Gbase),
driver_profile: Some("gbase8a".to_string()),
target: None,
parent: None,
name: "app_db".to_string(),
charset: None,
collation: None,
})
.unwrap_err()
.contains("Creating databases is not supported"));
}
#[test]
fn rejects_create_schema_for_informix_effective_dialect() {
// The frontend collapses GBase 8s to the Informix dialect for schema DDL; Informix has no
// CREATE SCHEMA <name>, so it must be rejected rather than emitting invalid SQL.
assert!(build_create_schema_sql(SchemaNameSqlOptions {
database_type: Some(DatabaseType::Informix),
name: "app".to_string(),
})
.unwrap_err()
.contains("Creating schemas is not supported"));
}
#[test]
fn create_database_target_distinguishes_gbase_profiles() {
assert!(supports_create_database_target(Some(DatabaseType::Gbase), Some("gbase8s")));
assert!(!supports_create_database_target(Some(DatabaseType::Gbase), Some("gbase8a")));
assert!(!supports_create_database_target(Some(DatabaseType::Gbase), None));
assert!(supports_create_database_target(Some(DatabaseType::Informix), None));
}
#[test]
fn builds_mysql_database_property_charset_sql() {
assert_eq!(