fix(core): preserve mysql numeric export literals
This commit is contained in:
parent
430f097602
commit
ae627de320
|
|
@ -482,7 +482,9 @@ fn looks_like_numeric_literal(raw: &str) -> bool {
|
|||
if trimmed.is_empty() {
|
||||
return false;
|
||||
}
|
||||
trimmed.parse::<i64>().is_ok() || trimmed.parse::<u64>().is_ok() || trimmed.parse::<f64>().is_ok()
|
||||
trimmed.parse::<i64>().is_ok()
|
||||
|| trimmed.parse::<u64>().is_ok()
|
||||
|| trimmed.parse::<f64>().is_ok_and(|value| value.is_finite())
|
||||
}
|
||||
|
||||
fn format_mysql_default_literal(raw: &str, data_type: &str) -> String {
|
||||
|
|
@ -971,6 +973,9 @@ pub fn escape_value_typed(val: &serde_json::Value, db_type: &DatabaseType, colum
|
|||
if let Some(binary_literal) = format_postgres_binary_sql_literal(s, db_type, column_type) {
|
||||
return binary_literal;
|
||||
}
|
||||
if let Some(numeric_literal) = format_mysql_numeric_string_literal(s, db_type, column_type) {
|
||||
return numeric_literal;
|
||||
}
|
||||
|
||||
let literal = format_literal_string(s, db_type, column_type);
|
||||
let escaped = if is_postgres_family_target(db_type) {
|
||||
|
|
@ -1005,6 +1010,37 @@ fn is_mysql_bit_type(column_type: &str) -> bool {
|
|||
lower == "bit" || lower.starts_with("bit(") || lower.starts_with("bit ")
|
||||
}
|
||||
|
||||
fn is_mysql_numeric_string_literal_database(db_type: &DatabaseType) -> bool {
|
||||
matches!(
|
||||
db_type,
|
||||
DatabaseType::Mysql
|
||||
| DatabaseType::Doris
|
||||
| DatabaseType::StarRocks
|
||||
| DatabaseType::Goldendb
|
||||
| DatabaseType::Sundb
|
||||
)
|
||||
}
|
||||
|
||||
fn is_mysql_non_bit_numeric_type(column_type: &str) -> bool {
|
||||
is_mysql_numeric_base_type(column_type) && !is_mysql_bit_type(column_type)
|
||||
}
|
||||
|
||||
fn format_mysql_numeric_string_literal(
|
||||
value: &str,
|
||||
db_type: &DatabaseType,
|
||||
column_type: Option<&str>,
|
||||
) -> Option<String> {
|
||||
if !is_mysql_numeric_string_literal_database(db_type) || !column_type.is_some_and(is_mysql_non_bit_numeric_type) {
|
||||
return None;
|
||||
}
|
||||
let trimmed = value.trim();
|
||||
if looks_like_numeric_literal(trimmed) {
|
||||
Some(trimmed.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn is_binary_transfer_column_type(column_type: &str) -> bool {
|
||||
let lower = column_type.trim().to_ascii_lowercase();
|
||||
let base = lower.split(['(', ' ', '\t', '\n']).next().unwrap_or("");
|
||||
|
|
@ -5461,6 +5497,62 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_insert_formats_numeric_strings_from_numeric_columns_as_numeric_literals() {
|
||||
let sql = generate_insert_typed(
|
||||
&[
|
||||
String::from("id"),
|
||||
String::from("amount"),
|
||||
String::from("quantity"),
|
||||
String::from("text_id"),
|
||||
String::from("bad_number"),
|
||||
String::from("missing"),
|
||||
],
|
||||
&[
|
||||
Some(String::from("bigint(20)")),
|
||||
Some(String::from("decimal(10,2)")),
|
||||
Some(String::from("int unsigned")),
|
||||
Some(String::from("varchar(64)")),
|
||||
Some(String::from("bigint(20)")),
|
||||
Some(String::from("bigint(20)")),
|
||||
],
|
||||
&[vec![
|
||||
json!("1234567890123"),
|
||||
json!("12.34"),
|
||||
json!("42"),
|
||||
json!("123"),
|
||||
json!("not-a-number"),
|
||||
serde_json::Value::Null,
|
||||
]],
|
||||
"orders",
|
||||
"",
|
||||
&DatabaseType::Mysql,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
sql,
|
||||
"INSERT INTO `orders` (`id`, `amount`, `quantity`, `text_id`, `bad_number`, `missing`) VALUES\n(1234567890123, 12.34, 42, '123', 'not-a-number', NULL)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mysql_upsert_formats_numeric_strings_from_numeric_columns_as_numeric_literals() {
|
||||
let sql = generate_upsert_typed(
|
||||
&[String::from("id"), String::from("amount")],
|
||||
&[Some(String::from("bigint(20)")), Some(String::from("decimal(10,2)"))],
|
||||
&[vec![json!("1234567890123"), json!("12.34")]],
|
||||
"orders",
|
||||
"",
|
||||
&DatabaseType::Mysql,
|
||||
&[String::from("id")],
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
sql,
|
||||
"INSERT INTO `orders` (`id`, `amount`) VALUES\n(1234567890123, 12.34)\nON DUPLICATE KEY UPDATE `amount` = VALUES(`amount`)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sqlserver_insert_prefixes_string_literals_as_unicode() {
|
||||
let sql = generate_insert_typed(
|
||||
|
|
|
|||
|
|
@ -304,7 +304,6 @@ mod tests {
|
|||
external_config: None,
|
||||
jdbc_driver_class: None,
|
||||
jdbc_driver_paths: Vec::new(),
|
||||
agent_java_options: Vec::new(),
|
||||
one_time: false,
|
||||
read_only: false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ mod tests {
|
|||
external_config: None,
|
||||
jdbc_driver_class: None,
|
||||
jdbc_driver_paths: Vec::new(),
|
||||
agent_java_options: Vec::new(),
|
||||
one_time: false,
|
||||
read_only: false,
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue