Skip to content

Commit 7b8a32e

Browse files
mvzinkayman-sigma
authored andcommitted
Fix column definition COLLATE parsing (apache#1986)
1 parent 655b87b commit 7b8a32e

3 files changed

Lines changed: 64 additions & 26 deletions

File tree

src/dialect/postgresql.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ impl Dialect for PostgreSqlDialect {
110110
// we only return some custom value here when the behaviour (not merely the numeric value) differs
111111
// from the default implementation
112112
match token.token {
113-
Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)),
113+
Token::Word(w)
114+
if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() =>
115+
{
116+
Some(Ok(COLLATE_PREC))
117+
}
114118
Token::LBracket => Some(Ok(BRACKET_PREC)),
115119
Token::Arrow
116120
| Token::LongArrow

src/parser/mod.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,7 +1722,7 @@ impl<'a> Parser<'a> {
17221722
_ => self.expected_at("an expression", next_token_index),
17231723
}?;
17241724

1725-
if self.parse_keyword(Keyword::COLLATE) {
1725+
if !self.in_column_definition_state() && self.parse_keyword(Keyword::COLLATE) {
17261726
Ok(Expr::Collate {
17271727
expr: Box::new(expr),
17281728
collation: self.parse_object_name(false)?,
@@ -3372,6 +3372,7 @@ impl<'a> Parser<'a> {
33723372

33733373
self.advance_token();
33743374
let tok = self.get_current_token();
3375+
debug!("infix: {tok:?}");
33753376
let tok_index = self.get_current_index();
33763377
let span = tok.span;
33773378
let regular_binary_operator = match &tok.token {
@@ -17854,30 +17855,6 @@ mod tests {
1785417855
assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err());
1785517856
}
1785617857

17857-
#[test]
17858-
fn test_parse_not_null_in_column_options() {
17859-
let canonical = concat!(
17860-
"CREATE TABLE foo (",
17861-
"abc INT DEFAULT (42 IS NOT NULL) NOT NULL,",
17862-
" def INT,",
17863-
" def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,",
17864-
" CHECK (abc IS NOT NULL)",
17865-
")"
17866-
);
17867-
all_dialects().verified_stmt(canonical);
17868-
all_dialects().one_statement_parses_to(
17869-
concat!(
17870-
"CREATE TABLE foo (",
17871-
"abc INT DEFAULT (42 NOT NULL) NOT NULL,",
17872-
" def INT,",
17873-
" def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,",
17874-
" CHECK (abc NOT NULL)",
17875-
")"
17876-
),
17877-
canonical,
17878-
);
17879-
}
17880-
1788117858
#[test]
1788217859
fn test_placeholder_invalid_whitespace() {
1788317860
for w in [" ", "/*invalid*/"] {

tests/sqlparser_common.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16624,3 +16624,60 @@ fn parse_create_view_if_not_exists() {
1662416624
res.unwrap_err()
1662516625
);
1662616626
}
16627+
16628+
#[test]
16629+
fn test_parse_not_null_in_column_options() {
16630+
let canonical = concat!(
16631+
"CREATE TABLE foo (",
16632+
"abc INT DEFAULT (42 IS NOT NULL) NOT NULL,",
16633+
" def INT,",
16634+
" def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,",
16635+
" CHECK (abc IS NOT NULL)",
16636+
")"
16637+
);
16638+
all_dialects().verified_stmt(canonical);
16639+
all_dialects().one_statement_parses_to(
16640+
concat!(
16641+
"CREATE TABLE foo (",
16642+
"abc INT DEFAULT (42 NOT NULL) NOT NULL,",
16643+
" def INT,",
16644+
" def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,",
16645+
" CHECK (abc NOT NULL)",
16646+
")"
16647+
),
16648+
canonical,
16649+
);
16650+
}
16651+
16652+
#[test]
16653+
fn test_parse_default_with_collate_column_option() {
16654+
let sql = "CREATE TABLE foo (abc TEXT DEFAULT 'foo' COLLATE 'en_US')";
16655+
let stmt = all_dialects().verified_stmt(sql);
16656+
if let Statement::CreateTable(CreateTable { mut columns, .. }) = stmt {
16657+
let mut column = columns.pop().unwrap();
16658+
assert_eq!(&column.name.value, "abc");
16659+
assert_eq!(column.data_type, DataType::Text);
16660+
let collate_option = column.options.pop().unwrap();
16661+
if let ColumnOptionDef {
16662+
name: None,
16663+
option: ColumnOption::Collation(collate),
16664+
} = collate_option
16665+
{
16666+
assert_eq!(collate.to_string(), "'en_US'");
16667+
} else {
16668+
panic!("Expected collate column option, got {collate_option}");
16669+
}
16670+
let default_option = column.options.pop().unwrap();
16671+
if let ColumnOptionDef {
16672+
name: None,
16673+
option: ColumnOption::Default(Expr::Value(value)),
16674+
} = default_option
16675+
{
16676+
assert_eq!(value.to_string(), "'foo'");
16677+
} else {
16678+
panic!("Expected default column option, got {default_option}");
16679+
}
16680+
} else {
16681+
panic!("Expected create table statement");
16682+
}
16683+
}

0 commit comments

Comments
 (0)