This is an automated email from the ASF dual-hosted git repository. iffyio pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push: new 60a5c8d4 Fix column definition `COLLATE` parsing (#1986) 60a5c8d4 is described below commit 60a5c8d42aa97500654b04ab28b4cd5f5de9cfd8 Author: Michael Victor Zink <michae...@readyset.io> AuthorDate: Wed Aug 13 02:05:15 2025 -0700 Fix column definition `COLLATE` parsing (#1986) --- src/dialect/postgresql.rs | 6 ++++- src/parser/mod.rs | 27 ++-------------------- tests/sqlparser_common.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/src/dialect/postgresql.rs b/src/dialect/postgresql.rs index 207f4787..e861cc51 100644 --- a/src/dialect/postgresql.rs +++ b/src/dialect/postgresql.rs @@ -110,7 +110,11 @@ impl Dialect for PostgreSqlDialect { // we only return some custom value here when the behaviour (not merely the numeric value) differs // from the default implementation match token.token { - Token::Word(w) if w.keyword == Keyword::COLLATE => Some(Ok(COLLATE_PREC)), + Token::Word(w) + if w.keyword == Keyword::COLLATE && !parser.in_column_definition_state() => + { + Some(Ok(COLLATE_PREC)) + } Token::LBracket => Some(Ok(BRACKET_PREC)), Token::Arrow | Token::LongArrow diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 2c5f1b9e..3d476254 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -1722,7 +1722,7 @@ impl<'a> Parser<'a> { _ => self.expected_at("an expression", next_token_index), }?; - if self.parse_keyword(Keyword::COLLATE) { + if !self.in_column_definition_state() && self.parse_keyword(Keyword::COLLATE) { Ok(Expr::Collate { expr: Box::new(expr), collation: self.parse_object_name(false)?, @@ -3372,6 +3372,7 @@ impl<'a> Parser<'a> { self.advance_token(); let tok = self.get_current_token(); + debug!("infix: {tok:?}"); let tok_index = self.get_current_index(); let span = tok.span; let regular_binary_operator = match &tok.token { @@ -17822,30 +17823,6 @@ mod tests { assert!(Parser::parse_sql(&MySqlDialect {}, sql).is_err()); } - #[test] - fn test_parse_not_null_in_column_options() { - let canonical = concat!( - "CREATE TABLE foo (", - "abc INT DEFAULT (42 IS NOT NULL) NOT NULL,", - " def INT,", - " def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,", - " CHECK (abc IS NOT NULL)", - ")" - ); - all_dialects().verified_stmt(canonical); - all_dialects().one_statement_parses_to( - concat!( - "CREATE TABLE foo (", - "abc INT DEFAULT (42 NOT NULL) NOT NULL,", - " def INT,", - " def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,", - " CHECK (abc NOT NULL)", - ")" - ), - canonical, - ); - } - #[test] fn test_placeholder_invalid_whitespace() { for w in [" ", "/*invalid*/"] { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 06d9cf14..4b9d748f 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -16598,3 +16598,60 @@ fn parse_create_view_if_not_exists() { res.unwrap_err() ); } + +#[test] +fn test_parse_not_null_in_column_options() { + let canonical = concat!( + "CREATE TABLE foo (", + "abc INT DEFAULT (42 IS NOT NULL) NOT NULL,", + " def INT,", + " def_null BOOL GENERATED ALWAYS AS (def IS NOT NULL) STORED,", + " CHECK (abc IS NOT NULL)", + ")" + ); + all_dialects().verified_stmt(canonical); + all_dialects().one_statement_parses_to( + concat!( + "CREATE TABLE foo (", + "abc INT DEFAULT (42 NOT NULL) NOT NULL,", + " def INT,", + " def_null BOOL GENERATED ALWAYS AS (def NOT NULL) STORED,", + " CHECK (abc NOT NULL)", + ")" + ), + canonical, + ); +} + +#[test] +fn test_parse_default_with_collate_column_option() { + let sql = "CREATE TABLE foo (abc TEXT DEFAULT 'foo' COLLATE 'en_US')"; + let stmt = all_dialects().verified_stmt(sql); + if let Statement::CreateTable(CreateTable { mut columns, .. }) = stmt { + let mut column = columns.pop().unwrap(); + assert_eq!(&column.name.value, "abc"); + assert_eq!(column.data_type, DataType::Text); + let collate_option = column.options.pop().unwrap(); + if let ColumnOptionDef { + name: None, + option: ColumnOption::Collation(collate), + } = collate_option + { + assert_eq!(collate.to_string(), "'en_US'"); + } else { + panic!("Expected collate column option, got {collate_option}"); + } + let default_option = column.options.pop().unwrap(); + if let ColumnOptionDef { + name: None, + option: ColumnOption::Default(Expr::Value(value)), + } = default_option + { + assert_eq!(value.to_string(), "'foo'"); + } else { + panic!("Expected default column option, got {default_option}"); + } + } else { + panic!("Expected create table statement"); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@datafusion.apache.org For additional commands, e-mail: commits-h...@datafusion.apache.org