mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
fix(transfer): keep identity sources auto-increment on mysql targets
This commit is contained in:
@@ -2762,6 +2762,15 @@ fn parse_mysql_extra_clauses(extra: Option<&str>) -> MysqlExtraClauses {
|
||||
result
|
||||
}
|
||||
|
||||
/// Whether a mapped target type is one MySQL accepts for `AUTO_INCREMENT`.
|
||||
///
|
||||
/// MySQL allows the clause on integer columns only, so an identity source mapped to
|
||||
/// `DECIMAL`/`NUMBER` must not receive it even when its metadata is identity-style.
|
||||
fn mysql_auto_increment_type_supported(mapped_type: &str) -> bool {
|
||||
let base = mapped_type.split(['(', ' ']).next().unwrap_or("").trim().to_ascii_lowercase();
|
||||
matches!(base.as_str(), "tinyint" | "smallint" | "mediumint" | "int" | "integer" | "bigint")
|
||||
}
|
||||
|
||||
fn postgres_order_by_expression(columns: &[String], db_type: &DatabaseType) -> Option<String> {
|
||||
postgres_order_by_expression_with_identifier_quote(columns, db_type, None)
|
||||
}
|
||||
@@ -4768,7 +4777,15 @@ fn generate_create_table_ddl_with_column_quoting(
|
||||
}
|
||||
if is_mysql_family {
|
||||
let extra_clauses = parse_mysql_extra_clauses(c.extra.as_deref());
|
||||
if extra_clauses.auto_increment {
|
||||
// `AUTO_INCREMENT` must also follow identity-style sources (SQL
|
||||
// Server `identity(1, 1)`, Dameng `identity`): the MySQL-spelling
|
||||
// parser only recognises `auto_increment`. Only a primary key on
|
||||
// an integer column qualifies — MySQL requires the auto-increment
|
||||
// column to be a key and rejects the clause on other types.
|
||||
let identity_source = c.is_primary_key
|
||||
&& column_is_auto_increment(c)
|
||||
&& mysql_auto_increment_type_supported(&mapped_type);
|
||||
if extra_clauses.auto_increment || identity_source {
|
||||
line.push_str(" AUTO_INCREMENT");
|
||||
}
|
||||
if let Some(on_update_expr) = extra_clauses.on_update {
|
||||
@@ -23337,6 +23354,59 @@ SELECT 1 FROM dual"#
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_create_table_preserves_identity_sources_for_mysql() {
|
||||
// `AUTO_INCREMENT` must also follow identity-style sources (SQL Server
|
||||
// `identity(1, 1)`, Dameng `identity`); the MySQL-spelling parser alone only
|
||||
// recognises `auto_increment`.
|
||||
for (source, extra) in [(DatabaseType::SqlServer, "identity(1,1)"), (DatabaseType::Dameng, "identity")] {
|
||||
let cols = vec![db::ColumnInfo {
|
||||
is_primary_key: true,
|
||||
is_nullable: false,
|
||||
extra: Some(extra.to_string()),
|
||||
..test_column("id", "int")
|
||||
}];
|
||||
|
||||
let ddl =
|
||||
generate_create_table_ddl(&cols, "users", "source", "shop", &DatabaseType::Mysql, &source, None, None);
|
||||
assert!(ddl.contains("`id` INT NOT NULL AUTO_INCREMENT"), "{source:?}->Mysql: {ddl}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transfer_create_table_keeps_non_key_identity_sources_out_of_auto_increment() {
|
||||
// MySQL requires the auto-increment column to be a key: an identity source on
|
||||
// a non-key column stays a plain column instead of failing CREATE TABLE.
|
||||
let cols = vec![db::ColumnInfo {
|
||||
is_nullable: false,
|
||||
extra: Some("identity".to_string()),
|
||||
..test_column("ticket", "int")
|
||||
}];
|
||||
|
||||
let ddl = generate_create_table_ddl(
|
||||
&cols,
|
||||
"users",
|
||||
"source",
|
||||
"shop",
|
||||
&DatabaseType::Mysql,
|
||||
&DatabaseType::Dameng,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(!ddl.contains("AUTO_INCREMENT"), "ddl: {ddl}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_auto_increment_type_supported_accepts_only_mysql_integers() {
|
||||
for supported in ["INT", "int(11)", "BIGINT", "TINYINT(1)", "SMALLINT UNSIGNED", "MEDIUMINT", "INTEGER"] {
|
||||
assert!(mysql_auto_increment_type_supported(supported), "{supported}");
|
||||
}
|
||||
for rejected in ["DECIMAL(10,0)", "NUMBER(10)", "VARCHAR(32)", "TEXT", "POINT", "DATETIME"] {
|
||||
assert!(!mysql_auto_increment_type_supported(rejected), "{rejected}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn postgres_create_table_default_clause_unchanged() {
|
||||
let cols = vec![db::ColumnInfo {
|
||||
|
||||
Reference in New Issue
Block a user