-
-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse MySQL column default value #110
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
0e2afb6
Parse MySQL column default value
billy1624 43ed184
Fixup
billy1624 be97301
clippy
billy1624 8c73afa
Fix
billy1624 190c8a3
clippy
billy1624 86f794b
Add ColumnDefault::Null
billy1624 3f23b2e
Parse extra to determine if it's default expression
billy1624 cc51c1d
Customized parsing logic for MySQL and MariaDB column default
billy1624 6c1ea4b
Merge remote-tracking branch 'origin/master' into parse-col-default-val
billy1624 fca3ee5
Remove current date and time from `ColumnDefault`
billy1624 880b70d
Add `ColumnDefault::CustomExpr`
billy1624 51e6b40
Simplify
billy1624 146c081
Parse custom expression
billy1624 b078079
fmt
billy1624 f11b494
Fix
billy1624 ae0d2d1
use i64
tyt2y3 ad2bc09
Tweaks
tyt2y3 e9cdd00
MariaDB >= 10.2.7
tyt2y3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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), | ||
default, | ||
extra: parse_column_extra(&mut Parser::new(&result.extra)), | ||
expression: match result.generation_expression { | ||
Some(generation_expression) => parse_generation_expression(generation_expression), | ||
|
@@ -260,11 +262,23 @@ pub fn parse_column_key(string: &str) -> ColumnKey { | |
} | ||
} | ||
|
||
pub fn parse_column_default(column_default: Option<String>) -> Option<ColumnDefault> { | ||
match column_default { | ||
pub fn parse_column_default( | ||
col_type: &Type, | ||
default: Option<String>, | ||
extra: &str, | ||
system: &SystemInfo, | ||
) -> Option<ColumnDefault> { | ||
match default { | ||
Some(default) => { | ||
if !default.is_empty() { | ||
Some(ColumnDefault { expr: default }) | ||
let default_value = if system.is_mysql() && system.version >= 80000 { | ||
parse_mysql_8_default(default, extra) | ||
} else if system.is_maria_db() && system.version >= 100207 { | ||
parse_mariadb_10_default(default) | ||
} else { | ||
parse_mysql_5_default(default, col_type) | ||
}; | ||
Some(default_value) | ||
} else { | ||
None | ||
} | ||
|
@@ -273,6 +287,52 @@ pub fn parse_column_default(column_default: Option<String>) -> Option<ColumnDefa | |
} | ||
} | ||
|
||
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() { | ||
ColumnDefault::Int(int) | ||
} else if let Ok(real) = default.parse() { | ||
ColumnDefault::Real(real) | ||
} else { | ||
ColumnDefault::String(default) | ||
} | ||
} | ||
|
||
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 is_expression && default == "NULL" { | ||
ColumnDefault::Null | ||
} else if let Ok(int) = default.parse() { | ||
ColumnDefault::Int(int) | ||
} else if let Ok(real) = default.parse() { | ||
ColumnDefault::Real(real) | ||
} else if is_expression { | ||
ColumnDefault::CustomExpr(default) | ||
} else { | ||
ColumnDefault::String(default) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in this case the tail case should be split:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
} | ||
|
||
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(real) = default.parse() { | ||
ColumnDefault::Real(real) | ||
} else if default == "current_timestamp()" { | ||
ColumnDefault::CurrentTimestamp | ||
} else if default == "NULL" { | ||
ColumnDefault::Null | ||
} else { | ||
ColumnDefault::CustomExpr(default) | ||
} | ||
} | ||
|
||
pub fn parse_generation_expression(string: String) -> Option<ColumnExpression> { | ||
if string.is_empty() { | ||
None | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just read https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html again,
I think the logic should be as follows:
EXTRA
column; if it containsDEFAULT_GENERATED
, then theCOLUMN_DEFAULT
should be regarded as an expressionExpr
and recognize the keywordsCURRENT_TIMESTAMP
, otherwiseCustom
a. if it is numeric-like then regard it as
Number
b. otherwise regard it as
String
(
regard it as an expressionNumber
. not sure whether it's worth the effort to classify intoint
andreal/decimal
String
It's really a legacy that MySQL does not quote a literal string. It's given as
hello
instead of'hello'
.Edit: I was wrong; apparently
COLUMNS
table does not give a()
for expressions either.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we cannot match the
(
character. The expression(CURRENT_TIMESTAMP)
orCURRENT_TIMESTAMP
both are valid syntax to define default value on table creation. But when you query the default expression via information schema, you get different result.