This is an automated email from the ASF dual-hosted git repository.

alamb 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 8badcdc2 Add SQLite "ON CONFLICT" column option in CREATE TABLE 
statements (#1442)
8badcdc2 is described below

commit 8badcdc2008bea4b5973c9dd12351a7cef29d8ab
Author: nucccc <[email protected]>
AuthorDate: Mon Oct 7 22:20:55 2024 +0200

    Add SQLite "ON CONFLICT" column option in CREATE TABLE statements (#1442)
    
    Co-authored-by: hulk <[email protected]>
    Co-authored-by: Ifeanyi Ubah <[email protected]>
---
 src/ast/ddl.rs            |  8 ++++++++
 src/parser/mod.rs         | 13 +++++++++++++
 tests/sqlparser_sqlite.rs | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+)

diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index 6eafc4da..0677e63b 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -33,6 +33,7 @@ use crate::ast::{
     display_comma_separated, display_separated, DataType, Expr, Ident, 
MySQLColumnPosition,
     ObjectName, OrderByExpr, ProjectionSelect, SequenceOptions, SqlOption, 
Value,
 };
+use crate::keywords::Keyword;
 use crate::tokenizer::Token;
 
 /// An `ALTER TABLE` (`Statement::AlterTable`) operation
@@ -1186,6 +1187,9 @@ pub enum ColumnOption {
     /// ```
     /// [MS SQL Server]: 
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql-identity-property
     Identity(Option<IdentityProperty>),
+    /// SQLite specific: ON CONFLICT option on column definition
+    /// <https://www.sqlite.org/lang_conflict.html>
+    OnConflict(Keyword),
 }
 
 impl fmt::Display for ColumnOption {
@@ -1294,6 +1298,10 @@ impl fmt::Display for ColumnOption {
                 }
                 Ok(())
             }
+            OnConflict(keyword) => {
+                write!(f, "ON CONFLICT {:?}", keyword)?;
+                Ok(())
+            }
         }
     }
 }
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 4e67524a..39173b63 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6224,6 +6224,19 @@ impl<'a> Parser<'a> {
                 None
             };
             Ok(Some(ColumnOption::Identity(property)))
+        } else if dialect_of!(self is SQLiteDialect | GenericDialect)
+            && self.parse_keywords(&[Keyword::ON, Keyword::CONFLICT])
+        {
+            // Support ON CONFLICT for SQLite
+            Ok(Some(ColumnOption::OnConflict(
+                self.expect_one_of_keywords(&[
+                    Keyword::ROLLBACK,
+                    Keyword::ABORT,
+                    Keyword::FAIL,
+                    Keyword::IGNORE,
+                    Keyword::REPLACE,
+                ])?,
+            )))
         } else {
             Ok(None)
         }
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index d7fd3b89..b5427fb3 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -22,6 +22,7 @@
 #[macro_use]
 mod test_utils;
 
+use sqlparser::keywords::Keyword;
 use test_utils::*;
 
 use sqlparser::ast::SelectItem::UnnamedExpr;
@@ -281,6 +282,46 @@ fn parse_create_table_gencol() {
     sqlite_and_generic().verified_stmt("CREATE TABLE t1 (a INT, b INT AS (a * 
2) STORED)");
 }
 
+#[test]
+fn parse_create_table_on_conflict_col() {
+    for keyword in [
+        Keyword::ROLLBACK,
+        Keyword::ABORT,
+        Keyword::FAIL,
+        Keyword::IGNORE,
+        Keyword::REPLACE,
+    ] {
+        let sql = format!("CREATE TABLE t1 (a INT, b INT ON CONFLICT {:?})", 
keyword);
+        match sqlite_and_generic().verified_stmt(&sql) {
+            Statement::CreateTable(CreateTable { columns, .. }) => {
+                assert_eq!(
+                    vec![ColumnOptionDef {
+                        name: None,
+                        option: ColumnOption::OnConflict(keyword),
+                    }],
+                    columns[1].options
+                );
+            }
+            _ => unreachable!(),
+        }
+    }
+}
+
+#[test]
+fn test_parse_create_table_on_conflict_col_err() {
+    let sql_err = "CREATE TABLE t1 (a INT, b INT ON CONFLICT BOH)";
+    let err = sqlite_and_generic()
+        .parse_sql_statements(sql_err)
+        .unwrap_err();
+    assert_eq!(
+        err,
+        ParserError::ParserError(
+            "Expected: one of ROLLBACK or ABORT or FAIL or IGNORE or REPLACE, 
found: BOH"
+                .to_string()
+        )
+    );
+}
+
 #[test]
 fn parse_create_table_untyped() {
     sqlite().verified_stmt("CREATE TABLE t1 (a, b AS (a * 2), c NOT NULL)");


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to