fix(xugu): generate native column type alterations

This commit is contained in:
t8y2 2026-07-15 14:29:05 +08:00
parent e3350e2ec4
commit 10827f105a
3 changed files with 106 additions and 8 deletions

View File

@ -77,7 +77,11 @@ pub fn build_single_column_alter_sql(options: SingleColumnAlterSqlOptions) -> Ta
StructureDialect::Doris => statements.extend(build_doris_existing_column_sql(&table, &options.column, "")),
StructureDialect::Postgres => statements.extend(build_postgres_existing_column_sql(&table, &options.column)),
StructureDialect::Oracle | StructureDialect::Dameng => {
statements.extend(build_oracle_like_existing_column_sql(dialect, &table, &options.column))
if options.database_type == Some(crate::models::connection::DatabaseType::Xugu) {
statements.extend(build_xugu_existing_column_sql(&table, &options.column));
} else {
statements.extend(build_oracle_like_existing_column_sql(dialect, &table, &options.column))
}
}
StructureDialect::H2 => statements.extend(build_h2_existing_column_sql(&table, &options.column)),
StructureDialect::ClickHouse => {
@ -287,6 +291,19 @@ pub(super) fn build_doris_existing_column_sql(
}
pub(super) fn build_postgres_existing_column_sql(table: &str, column: &EditableStructureColumn) -> Vec<String> {
build_postgres_like_existing_column_sql(table, column, false)
}
pub(super) fn build_xugu_existing_column_sql(table: &str, column: &EditableStructureColumn) -> Vec<String> {
// Xugu shares PostgreSQL's per-attribute ALTER flow, but its type clause omits TYPE entirely.
build_postgres_like_existing_column_sql(table, column, true)
}
fn build_postgres_like_existing_column_sql(
table: &str,
column: &EditableStructureColumn,
use_xugu_type_syntax: bool,
) -> Vec<String> {
let Some(original) = &column.original else {
return Vec::new();
};
@ -300,11 +317,10 @@ pub(super) fn build_postgres_existing_column_sql(table: &str, column: &EditableS
));
}
if column.data_type.trim() != original.data_type.trim() {
statements.push(format!(
"ALTER TABLE {table} ALTER COLUMN {} TYPE {};",
quote_ident(StructureDialect::Postgres, current_name),
column_data_type(StructureDialect::Postgres, column)
));
let column_name = quote_ident(StructureDialect::Postgres, current_name);
let data_type = column_data_type(StructureDialect::Postgres, column);
let type_clause = if use_xugu_type_syntax { data_type } else { format!("TYPE {data_type}") };
statements.push(format!("ALTER TABLE {table} ALTER COLUMN {column_name} {type_clause};"));
}
if column.is_nullable != original.is_nullable {
let action = if column.is_nullable { "DROP NOT NULL" } else { "SET NOT NULL" };

View File

@ -2,7 +2,8 @@ use super::column_alter::{
build_clickhouse_existing_column_sql, build_doris_existing_column_sql, build_h2_existing_column_sql,
build_informix_existing_column_sql, build_mysql_existing_column_sql, build_oracle_like_existing_column_sql,
build_postgres_existing_column_sql, build_questdb_existing_column_sql, build_sqlite_existing_column_sql,
build_sqlserver_existing_column_sql, has_column_extra_change, has_existing_column_attribute_change,
build_sqlserver_existing_column_sql, build_xugu_existing_column_sql, has_column_extra_change,
has_existing_column_attribute_change,
};
use super::column_format::{
column_definition, has_dameng_identity, is_dameng_identity_compatible_type, is_mysql_character_data_type,
@ -160,7 +161,11 @@ pub(super) fn build_column_sql(options: &TableStructureSqlOptions, warnings: &mu
StructureDialect::Doris => statements.extend(build_doris_existing_column_sql(&table, column, "")),
StructureDialect::Postgres => statements.extend(build_postgres_existing_column_sql(&table, column)),
StructureDialect::Oracle | StructureDialect::Dameng => {
statements.extend(build_oracle_like_existing_column_sql(dialect, &table, column))
if options.database_type == Some(crate::models::connection::DatabaseType::Xugu) {
statements.extend(build_xugu_existing_column_sql(&table, column));
} else {
statements.extend(build_oracle_like_existing_column_sql(dialect, &table, column))
}
}
StructureDialect::H2 => statements.extend(build_h2_existing_column_sql(&table, column)),
StructureDialect::ClickHouse => statements.extend(build_clickhouse_existing_column_sql(

View File

@ -120,6 +120,83 @@ fn builds_mysql_column_and_index_changes() {
);
}
#[test]
fn builds_xugu_type_change_with_native_syntax() {
let mut code = column("code");
code.data_type = "bigint".to_string();
code.original = Some(ColumnInfo {
name: "code".to_string(),
data_type: "integer".to_string(),
is_nullable: true,
column_default: None,
is_primary_key: false,
extra: None,
comment: None,
..Default::default()
});
let result = build_single_column_alter_sql(SingleColumnAlterSqlOptions {
database_type: Some(DatabaseType::Xugu),
schema: Some("public".to_string()),
table_name: "info_x".to_string(),
column: code,
});
assert_eq!(result.warnings, Vec::<String>::new());
assert_eq!(result.statements, vec!["ALTER TABLE \"public\".\"info_x\" ALTER COLUMN \"code\" bigint;"]);
let mut code = column("code");
code.data_type = "bigint".to_string();
code.original = Some(ColumnInfo {
name: "code".to_string(),
data_type: "integer".to_string(),
is_nullable: true,
column_default: None,
is_primary_key: false,
extra: None,
comment: None,
..Default::default()
});
let result = build_table_structure_change_sql(TableStructureSqlOptions {
database_type: Some(DatabaseType::Xugu),
schema: Some("public".to_string()),
table_name: "info_x".to_string(),
columns: vec![code],
indexes: Vec::new(),
foreign_keys: Vec::new(),
triggers: Vec::new(),
table_comment: None,
original_table_comment: None,
});
assert_eq!(result.warnings, Vec::<String>::new());
assert_eq!(result.statements, vec!["ALTER TABLE \"public\".\"info_x\" ALTER COLUMN \"code\" bigint;"]);
let mut postgres_code = column("code");
postgres_code.data_type = "integer".to_string();
postgres_code.original = Some(ColumnInfo {
name: "code".to_string(),
data_type: "varchar(20)".to_string(),
is_nullable: true,
column_default: None,
is_primary_key: false,
extra: None,
comment: None,
..Default::default()
});
let postgres_result = build_single_column_alter_sql(SingleColumnAlterSqlOptions {
database_type: Some(DatabaseType::Postgres),
schema: Some("public".to_string()),
table_name: "info_x".to_string(),
column: postgres_code,
});
assert_eq!(
postgres_result.statements,
vec!["ALTER TABLE \"public\".\"info_x\" ALTER COLUMN \"code\" TYPE integer;"]
);
}
#[test]
fn builds_mysql_unsigned_integer_column_with_length_before_attribute() {
let mut score = column("score");