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]