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

Reply via email to