Skip to content

Commit 60a5c8d

Browse files
authored
Fix column definition COLLATE parsing (#1986)
1 parent b2f9773 commit 60a5c8d

File tree

3 files changed

+64
-26
lines changed

3 files changed

+64
-26
lines changed

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 {
@@ -17822,30 +17823,6 @@ mod tests {
1782217823
assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err());
1782317824
}
1782417825

17825-
#[test]
17826-
fn test_parse_not_null_in_column_options() {
17827-
let canonical = concat!(
17828-
"CREATE TABLE foo (",
17829-
"abc INT DEFAULT (42 IS NOT NULL) NOT NULL,",
17830-
" def INT,",
17831-
" def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,",
17832-
" CHECK (abc IS NOT NULL)",
17833-
")"
17834-
);
17835-
all_dialects().verified_stmt(canonical);
17836-
all_dialects().one_statement_parses_to(
17837-
concat!(
17838-
"CREATE TABLE foo (",
17839-
"abc INT DEFAULT (42 NOT NULL) NOT NULL,",
17840-
" def INT,",
17841-
" def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,",
17842-
" CHECK (abc NOT NULL)",
17843-
")"
17844-
),
17845-
canonical,
17846-
);
17847-
}
17848-
1784917826
#[test]
1785017827
fn test_placeholder_invalid_whitespace() {
1785117828
for w in [" ", "/*invalid*/"] {

tests/sqlparser_common.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16598,3 +16598,60 @@ fn parse_create_view_if_not_exists() {
1659816598
res.unwrap_err()
1659916599
);
1660016600
}
16601+
16602+
#[test]
16603+
fn test_parse_not_null_in_column_options() {
16604+
let canonical = concat!(
16605+
"CREATE TABLE foo (",
16606+
"abc INT DEFAULT (42 IS NOT NULL) NOT NULL,",
16607+
" def INT,",
16608+
" def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,",
16609+
" CHECK (abc IS NOT NULL)",
16610+
")"
16611+
);
16612+
all_dialects().verified_stmt(canonical);
16613+
all_dialects().one_statement_parses_to(
16614+
concat!(
16615+
"CREATE TABLE foo (",
16616+
"abc INT DEFAULT (42 NOT NULL) NOT NULL,",
16617+
" def INT,",
16618+
" def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,",
16619+
" CHECK (abc NOT NULL)",
16620+
")"
16621+
),
16622+
canonical,
16623+
);
16624+
}
16625+
16626+
#[test]
16627+
fn test_parse_default_with_collate_column_option() {
16628+
let sql = "CREATE TABLE foo (abc TEXT DEFAULT 'foo' COLLATE 'en_US')";
16629+
let stmt = all_dialects().verified_stmt(sql);
16630+
if let Statement::CreateTable(CreateTable { mut columns, .. }) = stmt {
16631+
let mut column = columns.pop().unwrap();
16632+
assert_eq!(&column.name.value, "abc");
16633+
assert_eq!(column.data_type, DataType::Text);
16634+
let collate_option = column.options.pop().unwrap();
16635+
if let ColumnOptionDef {
16636+
name: None,
16637+
option: ColumnOption::Collation(collate),
16638+
} = collate_option
16639+
{
16640+
assert_eq!(collate.to_string(), "'en_US'");
16641+
} else {
16642+
panic!("Expected collate column option, got {collate_option}");
16643+
}
16644+
let default_option = column.options.pop().unwrap();
16645+
if let ColumnOptionDef {
16646+
name: None,
16647+
option: ColumnOption::Default(Expr::Value(value)),
16648+
} = default_option
16649+
{
16650+
assert_eq!(value.to_string(), "'foo'");
16651+
} else {
16652+
panic!("Expected default column option, got {default_option}");
16653+
}
16654+
} else {
16655+
panic!("Expected create table statement");
16656+
}
16657+
}

0 commit comments

Comments
 (0)