From 0e2afb6a3ae5ba0c94880dc3efdaa3a0b4b6870c Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 7 Jun 2023 16:41:05 +0800 Subject: [PATCH 01/17] Parse MySQL column default value --- src/mysql/def/column.rs | 10 +++++++--- src/mysql/parser/column.rs | 15 ++++++++++++++- src/mysql/writer/column.rs | 19 +++++++++++++------ tests/live/mysql/src/main.rs | 21 ++++++++++++++++++++- 4 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/mysql/def/column.rs b/src/mysql/def/column.rs index 7ce262a6..61d7ce48 100644 --- a/src/mysql/def/column.rs +++ b/src/mysql/def/column.rs @@ -41,9 +41,13 @@ pub enum ColumnKey { #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))] -pub struct ColumnDefault { - /// default value expression - pub expr: String, +pub enum ColumnDefault { + Int(i32), + Double(f64), + String(String), + CurrentDate, + CurrentTime, + CurrentTimestamp, } #[derive(Clone, Debug, PartialEq)] diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 2a9f266a..e4cac8b6 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -264,7 +264,20 @@ pub fn parse_column_default(column_default: Option) -> Option { if !default.is_empty() { - Some(ColumnDefault { expr: default }) + let column_default = if let Some(int) = default.parse::().ok() { + ColumnDefault::Int(int) + } else if let Some(double) = default.parse::().ok() { + ColumnDefault::Double(double) + } else if default == "CURRENT_DATE" { + ColumnDefault::CurrentDate + } else if default == "CURRENT_TIME" { + ColumnDefault::CurrentTime + } else if default == "CURRENT_TIMESTAMP" { + ColumnDefault::CurrentTimestamp + } else { + ColumnDefault::String(default) + }; + Some(column_default) } else { None } diff --git a/src/mysql/writer/column.rs b/src/mysql/writer/column.rs index bd55b0e3..49421924 100644 --- a/src/mysql/writer/column.rs +++ b/src/mysql/writer/column.rs @@ -1,6 +1,7 @@ -use crate::mysql::def::{CharSet, ColumnInfo, NumericAttr, StringAttr, Type}; +use crate::mysql::def::{CharSet, ColumnDefault, ColumnInfo, NumericAttr, StringAttr, Type}; use sea_query::{ - Alias, BlobSize, ColumnDef, DynIden, EscapeBuilder, Iden, IntoIden, MysqlQueryBuilder, + Alias, BlobSize, ColumnDef, DynIden, EscapeBuilder, Iden, IntoIden, Keyword, MysqlQueryBuilder, + SimpleExpr, }; use std::fmt::Write; @@ -15,10 +16,16 @@ impl ColumnInfo { col_def.auto_increment(); } let mut extras = Vec::new(); - if let Some(default) = self.default.as_ref() { - let mut string = "".to_owned(); - write!(&mut string, "DEFAULT {}", default.expr).unwrap(); - extras.push(string); + if let Some(default) = &self.default { + let default_expr: SimpleExpr = match default { + ColumnDefault::Int(int) => (*int).into(), + ColumnDefault::Double(double) => (*double).into(), + ColumnDefault::String(string) => string.into(), + ColumnDefault::CurrentDate => Keyword::CurrentDate.into(), + ColumnDefault::CurrentTime => Keyword::CurrentTime.into(), + ColumnDefault::CurrentTimestamp => Keyword::CurrentTimestamp.into(), + }; + col_def.default(default_expr); } if self.extra.on_update_current_timestamp { extras.push("ON UPDATE CURRENT_TIMESTAMP".to_owned()); diff --git a/tests/live/mysql/src/main.rs b/tests/live/mysql/src/main.rs index afcf1d4a..dbb4a6d8 100644 --- a/tests/live/mysql/src/main.rs +++ b/tests/live/mysql/src/main.rs @@ -203,7 +203,26 @@ fn create_order_table() -> TableCreateStatement { .col( ColumnDef::new(Alias::new("placed_at")) .date_time() - .not_null(), + .not_null() + .default(Expr::current_timestamp()), + ) + .col( + ColumnDef::new(Alias::new("updated")) + .date_time() + .not_null() + .default("2023-06-07 16:24:00"), + ) + .col( + ColumnDef::new(Alias::new("net_weight")) + .double() + .not_null() + .default(10.05), + ) + .col( + ColumnDef::new(Alias::new("priority")) + .integer() + .not_null() + .default(5), ) .index( Index::create() From 43ed1840d8dbf1b254967ab767418f37f370c5f2 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 7 Jun 2023 17:02:37 +0800 Subject: [PATCH 02/17] Fixup --- src/mysql/writer/table.rs | 8 ++------ tests/live/mysql/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/mysql/writer/table.rs b/src/mysql/writer/table.rs index 8c3f68b7..b78b0de0 100644 --- a/src/mysql/writer/table.rs +++ b/src/mysql/writer/table.rs @@ -119,9 +119,7 @@ mod tests { null: false, key: ColumnKey::NotKey, default: Some( - ColumnDefault { - expr: "CURRENT_TIMESTAMP".to_owned(), - }, + ColumnDefault::CurrentTimestamp, ), extra: ColumnExtra { auto_increment: false, @@ -219,9 +217,7 @@ mod tests { null: false, key: ColumnKey::NotKey, default: Some( - ColumnDefault { - expr: "CURRENT_TIMESTAMP".to_owned(), - }, + ColumnDefault::CurrentTimestamp, ), extra: ColumnExtra { auto_increment: false, diff --git a/tests/live/mysql/src/main.rs b/tests/live/mysql/src/main.rs index dbb4a6d8..718070bd 100644 --- a/tests/live/mysql/src/main.rs +++ b/tests/live/mysql/src/main.rs @@ -2,7 +2,7 @@ use pretty_assertions::assert_eq; use regex::Regex; use sea_schema::mysql::{def::TableDef, discovery::SchemaDiscovery}; use sea_schema::sea_query::{ - Alias, ColumnDef, ForeignKey, ForeignKeyAction, Index, MysqlQueryBuilder, Table, + Alias, ColumnDef, Expr, ForeignKey, ForeignKeyAction, Index, MysqlQueryBuilder, Table, TableCreateStatement, TableRef, }; use sqlx::{MySql, MySqlPool, Pool}; From be97301805077b37d968efd4d531cad3965d60cf Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 7 Jun 2023 17:02:40 +0800 Subject: [PATCH 03/17] clippy --- src/mysql/parser/column.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index e4cac8b6..b187fccb 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -264,9 +264,9 @@ pub fn parse_column_default(column_default: Option) -> Option { if !default.is_empty() { - let column_default = if let Some(int) = default.parse::().ok() { + let column_default = if let Ok(int) = default.parse::() { ColumnDefault::Int(int) - } else if let Some(double) = default.parse::().ok() { + } else if let Ok(double) = default.parse::() { ColumnDefault::Double(double) } else if default == "CURRENT_DATE" { ColumnDefault::CurrentDate From 8c73afa18681cd364ef01aea011d9866500a8062 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 7 Jun 2023 18:21:27 +0800 Subject: [PATCH 04/17] Fix --- src/mysql/parser/column.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index b187fccb..018a1d19 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -264,20 +264,23 @@ pub fn parse_column_default(column_default: Option) -> Option { if !default.is_empty() { - let column_default = if let Ok(int) = default.parse::() { - ColumnDefault::Int(int) + if let Ok(int) = default.parse::() { + Some(ColumnDefault::Int(int)) } else if let Ok(double) = default.parse::() { - ColumnDefault::Double(double) - } else if default == "CURRENT_DATE" { - ColumnDefault::CurrentDate - } else if default == "CURRENT_TIME" { - ColumnDefault::CurrentTime - } else if default == "CURRENT_TIMESTAMP" { - ColumnDefault::CurrentTimestamp + Some(ColumnDefault::Double(double)) + } else if default == "CURRENT_DATE" || default == "current_date()" { + Some(ColumnDefault::CurrentDate) + } else if default == "CURRENT_TIME" || default == "current_time()" { + Some(ColumnDefault::CurrentTime) + } else if default == "CURRENT_TIMESTAMP" || default == "current_timestamp()" { + Some(ColumnDefault::CurrentTimestamp) + } else if default.starts_with("'") && default.ends_with("'") { + Some(ColumnDefault::String(default[1..(default.len()-1)].into())) + } else if default == "NULL" { + None } else { - ColumnDefault::String(default) - }; - Some(column_default) + Some(ColumnDefault::String(default)) + } } else { None } From 190c8a3bdbd1a00a4dd0c491395808c95cf2ab43 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 7 Jun 2023 18:39:08 +0800 Subject: [PATCH 05/17] clippy --- src/mysql/parser/column.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 018a1d19..bae95609 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -274,8 +274,10 @@ pub fn parse_column_default(column_default: Option) -> Option Date: Thu, 8 Jun 2023 19:44:53 +0800 Subject: [PATCH 06/17] Add ColumnDefault::Null --- src/mysql/def/column.rs | 1 + src/mysql/parser/column.rs | 2 +- src/mysql/writer/column.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mysql/def/column.rs b/src/mysql/def/column.rs index 61d7ce48..f0bbaaa0 100644 --- a/src/mysql/def/column.rs +++ b/src/mysql/def/column.rs @@ -45,6 +45,7 @@ pub enum ColumnDefault { Int(i32), Double(f64), String(String), + Null, CurrentDate, CurrentTime, CurrentTimestamp, diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index bae95609..079a40d7 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -279,7 +279,7 @@ pub fn parse_column_default(column_default: Option) -> Option (*int).into(), ColumnDefault::Double(double) => (*double).into(), ColumnDefault::String(string) => string.into(), + ColumnDefault::Null => Option::::None.into(), ColumnDefault::CurrentDate => Keyword::CurrentDate.into(), ColumnDefault::CurrentTime => Keyword::CurrentTime.into(), ColumnDefault::CurrentTimestamp => Keyword::CurrentTimestamp.into(), From 3f23b2e075e13748feaae497e0a3a9b36ae37b94 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 8 Jun 2023 19:46:12 +0800 Subject: [PATCH 07/17] Parse extra to determine if it's default expression --- src/mysql/parser/column.rs | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 079a40d7..16073e62 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -15,7 +15,7 @@ pub fn parse_column_query_result(result: ColumnQueryResult) -> ColumnInfo { col_type: parse_column_type(&mut Parser::new(&result.column_type)), null: parse_column_null(&result.is_nullable), key: parse_column_key(&result.column_key), - default: parse_column_default(result.column_default), + default: parse_column_default(result.column_default, &result.extra), extra: parse_column_extra(&mut Parser::new(&result.extra)), expression: match result.generation_expression { Some(generation_expression) => parse_generation_expression(generation_expression), @@ -260,29 +260,35 @@ pub fn parse_column_key(string: &str) -> ColumnKey { } } -pub fn parse_column_default(column_default: Option) -> Option { +pub fn parse_column_default(column_default: Option, extra: &str) -> Option { match column_default { Some(default) => { if !default.is_empty() { - if let Ok(int) = default.parse::() { - Some(ColumnDefault::Int(int)) + let is_expression = extra == "DEFAULT_GENERATED"; + let default_value = if let Ok(int) = default.parse::() { + ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { - Some(ColumnDefault::Double(double)) - } else if default == "CURRENT_DATE" || default == "current_date()" { - Some(ColumnDefault::CurrentDate) - } else if default == "CURRENT_TIME" || default == "current_time()" { - Some(ColumnDefault::CurrentTime) - } else if default == "CURRENT_TIMESTAMP" || default == "current_timestamp()" { - Some(ColumnDefault::CurrentTimestamp) + ColumnDefault::Double(double) + } else if is_expression + && (default == "CURRENT_DATE" || default == "current_date()") + { + ColumnDefault::CurrentDate + } else if is_expression + && (default == "CURRENT_TIME" || default == "current_time()") + { + ColumnDefault::CurrentTime + } else if is_expression + && (default == "CURRENT_TIMESTAMP" || default == "current_timestamp()") + { + ColumnDefault::CurrentTimestamp } else if default.starts_with('\'') && default.ends_with('\'') { - Some(ColumnDefault::String( - default[1..(default.len() - 1)].into(), - )) + ColumnDefault::String(default[1..(default.len() - 1)].into()) } else if default == "NULL" { ColumnDefault::Null } else { - Some(ColumnDefault::String(default)) - } + ColumnDefault::String(default) + }; + Some(default_value) } else { None } From cc51c1dc057b903136ed06a866d8ccb8a45d2548 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 8 Jun 2023 21:45:13 +0800 Subject: [PATCH 08/17] Customized parsing logic for MySQL and MariaDB column default --- src/mysql/discovery/mod.rs | 5 +- src/mysql/parser/column.rs | 105 +++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 31 deletions(-) diff --git a/src/mysql/discovery/mod.rs b/src/mysql/discovery/mod.rs index 8fb36204..d6601ad4 100644 --- a/src/mysql/discovery/mod.rs +++ b/src/mysql/discovery/mod.rs @@ -92,7 +92,7 @@ impl SchemaDiscovery { pub async fn discover_table(&self, info: TableInfo) -> TableDef { let table = SeaRc::new(Alias::new(info.name.as_str())); let columns = self - .discover_columns(self.schema.clone(), table.clone()) + .discover_columns(self.schema.clone(), table.clone(), &self.query.system) .await; let indexes = self .discover_indexes(self.schema.clone(), table.clone()) @@ -113,6 +113,7 @@ impl SchemaDiscovery { &self, schema: SeaRc, table: SeaRc, + system: &SystemInfo, ) -> Vec { let rows = self .executor @@ -124,7 +125,7 @@ impl SchemaDiscovery { .map(|row| { let result: ColumnQueryResult = row.into(); debug_print!("{:?}", result); - let column = result.parse(); + let column = result.parse(system); debug_print!("{:?}", column); column }) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 16073e62..d245f513 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -4,18 +4,20 @@ use crate::{parser::Parser, Name}; use sea_query::{EscapeBuilder, MysqlQueryBuilder}; impl ColumnQueryResult { - pub fn parse(self) -> ColumnInfo { - parse_column_query_result(self) + pub fn parse(self, system: &SystemInfo) -> ColumnInfo { + parse_column_query_result(self, system) } } -pub fn parse_column_query_result(result: ColumnQueryResult) -> ColumnInfo { +pub fn parse_column_query_result(result: ColumnQueryResult, system: &SystemInfo) -> ColumnInfo { + let col_type = parse_column_type(&mut Parser::new(&result.column_type)); + let default = parse_column_default(&col_type, result.column_default, &result.extra, system); ColumnInfo { name: result.column_name, - col_type: parse_column_type(&mut Parser::new(&result.column_type)), + col_type, null: parse_column_null(&result.is_nullable), key: parse_column_key(&result.column_key), - default: parse_column_default(result.column_default, &result.extra), + default, extra: parse_column_extra(&mut Parser::new(&result.extra)), expression: match result.generation_expression { Some(generation_expression) => parse_generation_expression(generation_expression), @@ -260,33 +262,21 @@ pub fn parse_column_key(string: &str) -> ColumnKey { } } -pub fn parse_column_default(column_default: Option, extra: &str) -> Option { - match column_default { +pub fn parse_column_default( + col_type: &Type, + default: Option, + extra: &str, + system: &SystemInfo, +) -> Option { + match default { Some(default) => { if !default.is_empty() { - let is_expression = extra == "DEFAULT_GENERATED"; - let default_value = if let Ok(int) = default.parse::() { - ColumnDefault::Int(int) - } else if let Ok(double) = default.parse::() { - ColumnDefault::Double(double) - } else if is_expression - && (default == "CURRENT_DATE" || default == "current_date()") - { - ColumnDefault::CurrentDate - } else if is_expression - && (default == "CURRENT_TIME" || default == "current_time()") - { - ColumnDefault::CurrentTime - } else if is_expression - && (default == "CURRENT_TIMESTAMP" || default == "current_timestamp()") - { - ColumnDefault::CurrentTimestamp - } else if default.starts_with('\'') && default.ends_with('\'') { - ColumnDefault::String(default[1..(default.len() - 1)].into()) - } else if default == "NULL" { - ColumnDefault::Null + let default_value = if system.is_mysql() && system.version >= 80000 { + parse_mysql_8_default(default, extra) + } else if system.is_maria_db() && system.version >= 100201 { + parse_mariadb_10_default(default) } else { - ColumnDefault::String(default) + parse_mysql_5_default(default, col_type) }; Some(default_value) } else { @@ -297,6 +287,63 @@ pub fn parse_column_default(column_default: Option, extra: &str) -> Opti } } +pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault { + let is_date_time_col = matches!( + col_type, + Type::Date | Type::DateTime(_) | Type::Timestamp(_) + ); + if is_date_time_col && default == "CURRENT_DATE" { + ColumnDefault::CurrentDate + } else if is_date_time_col && default == "CURRENT_TIME" { + ColumnDefault::CurrentTime + } else if is_date_time_col && default == "CURRENT_TIMESTAMP" { + ColumnDefault::CurrentTimestamp + } else if let Ok(int) = default.parse::() { + ColumnDefault::Int(int) + } else if let Ok(double) = default.parse::() { + ColumnDefault::Double(double) + } else { + ColumnDefault::String(default) + } +} + +pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { + let is_expression = extra == "DEFAULT_GENERATED"; + if is_expression && default == "CURRENT_DATE" { + ColumnDefault::CurrentDate + } else if is_expression && default == "CURRENT_TIME" { + ColumnDefault::CurrentTime + } else if is_expression && default == "CURRENT_TIMESTAMP" { + ColumnDefault::CurrentTimestamp + } else if let Ok(int) = default.parse::() { + ColumnDefault::Int(int) + } else if let Ok(double) = default.parse::() { + ColumnDefault::Double(double) + } else { + ColumnDefault::String(default) + } +} + +pub fn parse_mariadb_10_default(default: String) -> ColumnDefault { + if default.starts_with('\'') && default.ends_with('\'') { + ColumnDefault::String(default[1..(default.len() - 1)].into()) + } else if let Ok(int) = default.parse::() { + ColumnDefault::Int(int) + } else if let Ok(double) = default.parse::() { + ColumnDefault::Double(double) + } else if default == "current_date()" { + ColumnDefault::CurrentDate + } else if default == "current_time()" { + ColumnDefault::CurrentTime + } else if default == "current_timestamp()" { + ColumnDefault::CurrentTimestamp + } else if default == "NULL" { + ColumnDefault::Null + } else { + ColumnDefault::String(default) + } +} + pub fn parse_generation_expression(string: String) -> Option { if string.is_empty() { None From fca3ee59229ed09ba35772631a06bb0977cf5955 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:08:50 +0800 Subject: [PATCH 09/17] Remove current date and time from `ColumnDefault` --- src/mysql/def/column.rs | 2 -- src/mysql/parser/column.rs | 21 +++------------------ src/mysql/writer/column.rs | 2 -- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/src/mysql/def/column.rs b/src/mysql/def/column.rs index f0bbaaa0..e0ffb0f3 100644 --- a/src/mysql/def/column.rs +++ b/src/mysql/def/column.rs @@ -46,8 +46,6 @@ pub enum ColumnDefault { Double(f64), String(String), Null, - CurrentDate, - CurrentTime, CurrentTimestamp, } diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index d245f513..dc3126bb 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -288,15 +288,8 @@ pub fn parse_column_default( } pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault { - let is_date_time_col = matches!( - col_type, - Type::Date | Type::DateTime(_) | Type::Timestamp(_) - ); - if is_date_time_col && default == "CURRENT_DATE" { - ColumnDefault::CurrentDate - } else if is_date_time_col && default == "CURRENT_TIME" { - ColumnDefault::CurrentTime - } else if is_date_time_col && default == "CURRENT_TIMESTAMP" { + let is_date_time_col = matches!(col_type, Type::Timestamp(_)); + if is_date_time_col && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) @@ -309,11 +302,7 @@ pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { let is_expression = extra == "DEFAULT_GENERATED"; - if is_expression && default == "CURRENT_DATE" { - ColumnDefault::CurrentDate - } else if is_expression && default == "CURRENT_TIME" { - ColumnDefault::CurrentTime - } else if is_expression && default == "CURRENT_TIMESTAMP" { + if is_expression && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) @@ -331,10 +320,6 @@ pub fn parse_mariadb_10_default(default: String) -> ColumnDefault { ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { ColumnDefault::Double(double) - } else if default == "current_date()" { - ColumnDefault::CurrentDate - } else if default == "current_time()" { - ColumnDefault::CurrentTime } else if default == "current_timestamp()" { ColumnDefault::CurrentTimestamp } else if default == "NULL" { diff --git a/src/mysql/writer/column.rs b/src/mysql/writer/column.rs index b3d18402..d3640eef 100644 --- a/src/mysql/writer/column.rs +++ b/src/mysql/writer/column.rs @@ -22,8 +22,6 @@ impl ColumnInfo { ColumnDefault::Double(double) => (*double).into(), ColumnDefault::String(string) => string.into(), ColumnDefault::Null => Option::::None.into(), - ColumnDefault::CurrentDate => Keyword::CurrentDate.into(), - ColumnDefault::CurrentTime => Keyword::CurrentTime.into(), ColumnDefault::CurrentTimestamp => Keyword::CurrentTimestamp.into(), }; col_def.default(default_expr); From 880b70d91cebef776506c246a942514166e81930 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:13:06 +0800 Subject: [PATCH 10/17] Add `ColumnDefault::CustomExpr` --- src/mysql/def/column.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mysql/def/column.rs b/src/mysql/def/column.rs index e0ffb0f3..603d5a7c 100644 --- a/src/mysql/def/column.rs +++ b/src/mysql/def/column.rs @@ -45,6 +45,7 @@ pub enum ColumnDefault { Int(i32), Double(f64), String(String), + CustomExpr(String), Null, CurrentTimestamp, } From 51e6b4090da83e3893336717f9daf8c10f75a9f4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:13:36 +0800 Subject: [PATCH 11/17] Simplify --- src/mysql/parser/column.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index dc3126bb..280a1f6f 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -288,8 +288,7 @@ pub fn parse_column_default( } pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault { - let is_date_time_col = matches!(col_type, Type::Timestamp(_)); - if is_date_time_col && default == "CURRENT_TIMESTAMP" { + if matches!(col_type, Type::Timestamp(_)) && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) From 146c081ee17e55c5350b3919dc09a1fcf1f47d25 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:14:07 +0800 Subject: [PATCH 12/17] Parse custom expression --- src/mysql/parser/column.rs | 6 ++++-- src/mysql/writer/column.rs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 280a1f6f..dc180e7c 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -300,13 +300,15 @@ pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault } pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { - let is_expression = extra == "DEFAULT_GENERATED"; + let is_expression = extra.contains("DEFAULT_GENERATED"); if is_expression && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { ColumnDefault::Double(double) + } else if is_expression { + ColumnDefault::CustomExpr(default) } else { ColumnDefault::String(default) } @@ -324,7 +326,7 @@ pub fn parse_mariadb_10_default(default: String) -> ColumnDefault { } else if default == "NULL" { ColumnDefault::Null } else { - ColumnDefault::String(default) + ColumnDefault::CustomExpr(default) } } diff --git a/src/mysql/writer/column.rs b/src/mysql/writer/column.rs index d3640eef..57e5ff84 100644 --- a/src/mysql/writer/column.rs +++ b/src/mysql/writer/column.rs @@ -1,7 +1,7 @@ use crate::mysql::def::{CharSet, ColumnDefault, ColumnInfo, NumericAttr, StringAttr, Type}; use sea_query::{ Alias, BlobSize, ColumnDef, DynIden, EscapeBuilder, Iden, IntoIden, Keyword, MysqlQueryBuilder, - SimpleExpr, + SimpleExpr, Expr, }; use std::fmt::Write; @@ -21,6 +21,7 @@ impl ColumnInfo { ColumnDefault::Int(int) => (*int).into(), ColumnDefault::Double(double) => (*double).into(), ColumnDefault::String(string) => string.into(), + ColumnDefault::CustomExpr(string) => Expr::cust(string), ColumnDefault::Null => Option::::None.into(), ColumnDefault::CurrentTimestamp => Keyword::CurrentTimestamp.into(), }; From b078079733a77650901390b86d9489cf45c3c96c Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:15:42 +0800 Subject: [PATCH 13/17] fmt --- src/mysql/writer/column.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mysql/writer/column.rs b/src/mysql/writer/column.rs index 57e5ff84..f5a1104a 100644 --- a/src/mysql/writer/column.rs +++ b/src/mysql/writer/column.rs @@ -1,7 +1,7 @@ use crate::mysql::def::{CharSet, ColumnDefault, ColumnInfo, NumericAttr, StringAttr, Type}; use sea_query::{ - Alias, BlobSize, ColumnDef, DynIden, EscapeBuilder, Iden, IntoIden, Keyword, MysqlQueryBuilder, - SimpleExpr, Expr, + Alias, BlobSize, ColumnDef, DynIden, EscapeBuilder, Expr, Iden, IntoIden, Keyword, + MysqlQueryBuilder, SimpleExpr, }; use std::fmt::Write; From f11b494230985fb028166755f69de86a056d3a39 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 9 Jun 2023 15:23:17 +0800 Subject: [PATCH 14/17] Fix --- src/mysql/parser/column.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index dc180e7c..07177b1f 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -288,7 +288,8 @@ pub fn parse_column_default( } pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault { - if matches!(col_type, Type::Timestamp(_)) && default == "CURRENT_TIMESTAMP" { + let is_date_time = matches!(col_type, Type::DateTime(_) | Type::Timestamp(_)); + if is_date_time && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) From ae0d2d11bd8ea48639349373d56b4b6140be1f7d Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 11 Jun 2023 01:10:56 +0800 Subject: [PATCH 15/17] use i64 --- src/mysql/def/column.rs | 6 +++--- src/mysql/parser/column.rs | 12 ++++++------ src/mysql/writer/column.rs | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mysql/def/column.rs b/src/mysql/def/column.rs index 603d5a7c..3cddd688 100644 --- a/src/mysql/def/column.rs +++ b/src/mysql/def/column.rs @@ -42,11 +42,11 @@ pub enum ColumnKey { #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "with-serde", derive(Serialize, Deserialize))] pub enum ColumnDefault { - Int(i32), - Double(f64), + Null, + Int(i64), + Real(f64), String(String), CustomExpr(String), - Null, CurrentTimestamp, } diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 07177b1f..513e08f7 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -291,10 +291,10 @@ pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault let is_date_time = matches!(col_type, Type::DateTime(_) | Type::Timestamp(_)); if is_date_time && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp - } else if let Ok(int) = default.parse::() { + } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { - ColumnDefault::Double(double) + ColumnDefault::Real(double) } else { ColumnDefault::String(default) } @@ -304,10 +304,10 @@ pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { let is_expression = extra.contains("DEFAULT_GENERATED"); if is_expression && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp - } else if let Ok(int) = default.parse::() { + } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { - ColumnDefault::Double(double) + ColumnDefault::Real(double) } else if is_expression { ColumnDefault::CustomExpr(default) } else { @@ -318,10 +318,10 @@ pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { pub fn parse_mariadb_10_default(default: String) -> ColumnDefault { if default.starts_with('\'') && default.ends_with('\'') { ColumnDefault::String(default[1..(default.len() - 1)].into()) - } else if let Ok(int) = default.parse::() { + } else if let Ok(int) = default.parse::() { ColumnDefault::Int(int) } else if let Ok(double) = default.parse::() { - ColumnDefault::Double(double) + ColumnDefault::Real(double) } else if default == "current_timestamp()" { ColumnDefault::CurrentTimestamp } else if default == "NULL" { diff --git a/src/mysql/writer/column.rs b/src/mysql/writer/column.rs index f5a1104a..7991922e 100644 --- a/src/mysql/writer/column.rs +++ b/src/mysql/writer/column.rs @@ -18,11 +18,11 @@ impl ColumnInfo { let mut extras = Vec::new(); if let Some(default) = &self.default { let default_expr: SimpleExpr = match default { + ColumnDefault::Null => Option::::None.into(), ColumnDefault::Int(int) => (*int).into(), - ColumnDefault::Double(double) => (*double).into(), + ColumnDefault::Real(double) => (*double).into(), ColumnDefault::String(string) => string.into(), ColumnDefault::CustomExpr(string) => Expr::cust(string), - ColumnDefault::Null => Option::::None.into(), ColumnDefault::CurrentTimestamp => Keyword::CurrentTimestamp.into(), }; col_def.default(default_expr); From ad2bc09a86b834658df9b7c6b3895c264437dae4 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 11 Jun 2023 01:39:15 +0800 Subject: [PATCH 16/17] Tweaks --- src/mysql/parser/column.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 513e08f7..6bc5eab9 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -291,10 +291,10 @@ pub fn parse_mysql_5_default(default: String, col_type: &Type) -> ColumnDefault let is_date_time = matches!(col_type, Type::DateTime(_) | Type::Timestamp(_)); if is_date_time && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp - } else if let Ok(int) = default.parse::() { + } else if let Ok(int) = default.parse() { ColumnDefault::Int(int) - } else if let Ok(double) = default.parse::() { - ColumnDefault::Real(double) + } else if let Ok(real) = default.parse() { + ColumnDefault::Real(real) } else { ColumnDefault::String(default) } @@ -304,10 +304,12 @@ pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { let is_expression = extra.contains("DEFAULT_GENERATED"); if is_expression && default == "CURRENT_TIMESTAMP" { ColumnDefault::CurrentTimestamp - } else if let Ok(int) = default.parse::() { + } else if is_expression && default == "NULL" { + ColumnDefault::Null + } else if let Ok(int) = default.parse() { ColumnDefault::Int(int) - } else if let Ok(double) = default.parse::() { - ColumnDefault::Real(double) + } else if let Ok(real) = default.parse() { + ColumnDefault::Real(real) } else if is_expression { ColumnDefault::CustomExpr(default) } else { @@ -318,10 +320,10 @@ pub fn parse_mysql_8_default(default: String, extra: &str) -> ColumnDefault { pub fn parse_mariadb_10_default(default: String) -> ColumnDefault { if default.starts_with('\'') && default.ends_with('\'') { ColumnDefault::String(default[1..(default.len() - 1)].into()) - } else if let Ok(int) = default.parse::() { + } else if let Ok(int) = default.parse() { ColumnDefault::Int(int) - } else if let Ok(double) = default.parse::() { - ColumnDefault::Real(double) + } else if let Ok(real) = default.parse() { + ColumnDefault::Real(real) } else if default == "current_timestamp()" { ColumnDefault::CurrentTimestamp } else if default == "NULL" { From e9cdd00a680c9052c5b8f3e404681bdf2b644815 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 11 Jun 2023 01:54:15 +0800 Subject: [PATCH 17/17] MariaDB >= 10.2.7 --- src/mysql/parser/column.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mysql/parser/column.rs b/src/mysql/parser/column.rs index 6bc5eab9..f1481f56 100644 --- a/src/mysql/parser/column.rs +++ b/src/mysql/parser/column.rs @@ -273,7 +273,7 @@ pub fn parse_column_default( if !default.is_empty() { let default_value = if system.is_mysql() && system.version >= 80000 { parse_mysql_8_default(default, extra) - } else if system.is_maria_db() && system.version >= 100201 { + } else if system.is_maria_db() && system.version >= 100207 { parse_mariadb_10_default(default) } else { parse_mysql_5_default(default, col_type)