fix(gbase): generate GBase 8s table DDL with Informix dialect
This commit is contained in:
1 parent
d430ec9a4a
commit
af32936297
20 files changed
+284
-16
No files matched your search
@@ -14,7 +14,7 @@ use super::util::{
|
||||
use crate::table_structure_sql::ColumnExtra;
|
||||
|
||||
pub fn build_single_column_alter_sql(options: SingleColumnAlterSqlOptions) -> TableStructureSqlResult {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
let dialect = capabilities.dialect;
|
||||
let table = qualified_table(dialect, options.schema.as_deref(), &options.table_name);
|
||||
let database_label = database_label(options.database_type);
|
||||
|
||||
@@ -22,7 +22,7 @@ use crate::models::connection::DatabaseType;
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub(super) fn build_column_sql(options: &TableStructureSqlOptions, warnings: &mut Vec<String>) -> Vec<String> {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
let dialect = capabilities.dialect;
|
||||
let table = qualified_table(dialect, options.schema.as_deref(), &options.table_name);
|
||||
let database_label = database_label(options.database_type);
|
||||
@@ -383,7 +383,7 @@ pub(super) fn validate_primary_key_change_scope(options: &TableStructureSqlOptio
|
||||
}
|
||||
|
||||
let Some(change) = primary_key_change(options) else { return Vec::new() };
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
let supported =
|
||||
if change.old_ids.is_empty() { capabilities.add_primary_key } else { capabilities.alter_primary_key };
|
||||
if supported {
|
||||
@@ -452,7 +452,7 @@ pub(super) fn build_primary_key_sql(
|
||||
table: &str,
|
||||
warnings: &mut Vec<String>,
|
||||
) -> Vec<String> {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
|
||||
// Membership by draft id (set equality): pure rename / local reorder of the same key
|
||||
// columns is not a PK change. A draft that drops a PK column is also rejected here.
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::types::TableStructureSqlOptions;
|
||||
use super::util::{clean, qualified_table, quote_string};
|
||||
|
||||
pub(super) fn build_table_comment_sql(options: &TableStructureSqlOptions, warnings: &mut Vec<String>) -> Vec<String> {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
let new_comment = options.table_comment.as_deref().unwrap_or("");
|
||||
let original_comment = options.original_table_comment.as_deref().unwrap_or("");
|
||||
if clean(new_comment) == clean(original_comment) {
|
||||
|
||||
@@ -22,7 +22,7 @@ pub fn build_create_table_sql(mut options: TableStructureSqlOptions) -> TableStr
|
||||
capabilities = super::dialect::gaussdb_m_capabilities();
|
||||
dialect = StructureDialect::GaussdbM;
|
||||
} else {
|
||||
capabilities = capabilities_for(options.database_type);
|
||||
capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
dialect = capabilities.dialect;
|
||||
}
|
||||
options.table_name = clean(&options.table_name);
|
||||
|
||||
@@ -93,7 +93,10 @@ pub(super) fn gaussdb_m_capabilities() -> TableStructureCapabilities {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn capabilities_for(database_type: Option<DatabaseType>) -> TableStructureCapabilities {
|
||||
pub(super) fn capabilities_for(
|
||||
database_type: Option<DatabaseType>,
|
||||
driver_profile: Option<&str>,
|
||||
) -> TableStructureCapabilities {
|
||||
let base = TableStructureCapabilities::default();
|
||||
match database_type {
|
||||
Some(
|
||||
@@ -129,6 +132,23 @@ pub(super) fn capabilities_for(database_type: Option<DatabaseType>) -> TableStru
|
||||
comment: true,
|
||||
..base
|
||||
},
|
||||
// GBase 8s is Informix-compatible, unlike the rest of the `Gbase`
|
||||
// family (GBase 8a and friends) which speak MySQL wire protocol and
|
||||
// SQL dialect. `driver_profile` is the only signal that distinguishes
|
||||
// them (see the same check in `table_export.rs` / `table_select.rs`).
|
||||
Some(DatabaseType::Gbase) if driver_profile.is_some_and(|profile| profile.eq_ignore_ascii_case("gbase8s")) => {
|
||||
TableStructureCapabilities {
|
||||
dialect: StructureDialect::Informix,
|
||||
add_column: true,
|
||||
drop_column: true,
|
||||
rename_column: true,
|
||||
alter_existing_column: true,
|
||||
create_index: true,
|
||||
drop_index: true,
|
||||
rebuild_index: true,
|
||||
..base
|
||||
}
|
||||
}
|
||||
Some(DatabaseType::Gbase) => TableStructureCapabilities {
|
||||
dialect: StructureDialect::Mysql,
|
||||
add_column: true,
|
||||
|
||||
@@ -23,7 +23,7 @@ fn build_foreign_key_sql_with_mode(
|
||||
}
|
||||
|
||||
let database_label = database_label(options.database_type);
|
||||
let capabilities = super::dialect::capabilities_for(options.database_type);
|
||||
let capabilities = super::dialect::capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
let dialect = capabilities.dialect;
|
||||
if !capabilities.foreign_key {
|
||||
if has_foreign_key_edits(&options.foreign_keys) {
|
||||
|
||||
@@ -12,7 +12,7 @@ pub(super) fn build_index_sql(options: &TableStructureSqlOptions, warnings: &mut
|
||||
capabilities = caps;
|
||||
dialect = StructureDialect::GaussdbM;
|
||||
} else {
|
||||
let caps = capabilities_for(options.database_type);
|
||||
let caps = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
capabilities = caps;
|
||||
dialect = caps.dialect;
|
||||
}
|
||||
@@ -346,7 +346,7 @@ pub(super) fn build_create_index_statements(
|
||||
concurrently_supported: bool,
|
||||
for_new_table: bool,
|
||||
) -> Vec<String> {
|
||||
let capabilities = capabilities_for(database_type_for_dialect(dialect));
|
||||
let capabilities = capabilities_for(database_type_for_dialect(dialect), None);
|
||||
let name = clean(&index.name);
|
||||
let columns: Vec<String> =
|
||||
index.columns.iter().map(|column| clean(column)).filter(|column| !column.is_empty()).collect();
|
||||
|
||||
@@ -1484,6 +1484,7 @@ mod tests {
|
||||
) -> TableStructureSqlOptions {
|
||||
TableStructureSqlOptions {
|
||||
database_type: Some(DatabaseType::Sqlite),
|
||||
driver_profile: None,
|
||||
schema: None,
|
||||
table_name: table_name.to_string(),
|
||||
columns: vec![EditableStructureColumn {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -22,7 +22,7 @@ fn build_trigger_sql_with_mode(
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let dialect = super::dialect::capabilities_for(options.database_type).dialect;
|
||||
let dialect = super::dialect::capabilities_for(options.database_type, options.driver_profile.as_deref()).dialect;
|
||||
let database_label = database_label(options.database_type);
|
||||
if !matches!(dialect, StructureDialect::Mysql | StructureDialect::Oracle | StructureDialect::SqlServer) {
|
||||
if options.triggers.iter().any(has_trigger_edit) {
|
||||
|
||||
@@ -207,6 +207,11 @@ pub struct TriggerInfo {
|
||||
pub struct TableStructureSqlOptions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
/// Driver profile reported by the connection (e.g. `"gbase8s"`). GBase 8s
|
||||
/// is Informix-compatible rather than MySQL-compatible like the rest of
|
||||
/// the `Gbase` family, so this disambiguates which dialect to generate.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub driver_profile: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub schema: Option<String>,
|
||||
pub table_name: String,
|
||||
@@ -281,6 +286,8 @@ pub struct SingleColumnAlterSqlOptions {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub database_type: Option<DatabaseType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub driver_profile: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub schema: Option<String>,
|
||||
pub table_name: String,
|
||||
pub column: EditableStructureColumn,
|
||||
|
||||
@@ -15,7 +15,7 @@ use super::util::clean;
|
||||
/// a concurrent request in the first place).
|
||||
pub(super) fn validate_concurrent_index_scope(options: &TableStructureSqlOptions) -> Vec<String> {
|
||||
let mut errors = Vec::new();
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
if !capabilities.index_concurrent || capabilities.dialect != StructureDialect::Postgres {
|
||||
return errors;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ pub(super) fn validate_dameng_identity(
|
||||
columns: &[&EditableStructureColumn],
|
||||
warnings: &mut Vec<String>,
|
||||
) {
|
||||
if capabilities_for(options.database_type).dialect != StructureDialect::Dameng {
|
||||
if capabilities_for(options.database_type, options.driver_profile.as_deref()).dialect != StructureDialect::Dameng {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ pub(super) fn validate_columns(columns: &[&EditableStructureColumn], warnings: &
|
||||
/// classes are almost always needed. This is a warning, not an error, because
|
||||
/// the default class may be deliberate in some cases.
|
||||
fn validate_gin_opclass_warnings(options: &TableStructureSqlOptions, warnings: &mut Vec<String>) {
|
||||
let capabilities = capabilities_for(options.database_type);
|
||||
let capabilities = capabilities_for(options.database_type, options.driver_profile.as_deref());
|
||||
if capabilities.dialect != StructureDialect::Postgres {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user