You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by lu...@apache.org on 2026/10/02 19:59:23 UTC
(datafusion-sqlparser-rs) 01/01: SQLite: Reject VALUE as a synonym of VALUES
This is an automated email from the ASF dual-hosted git repository.
LucaCappelletti94 pushed a commit to branch upstream/sqlite-insert-value
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 9d231b96456f164c3a21a58c966e2f7f63acd72d
Author: LucaCappelletti94 <ca...@gmail.com>
AuthorDate: Fri Oct 2 21:59:12 2026 +0200
SQLite: Reject VALUE as a synonym of VALUES
---
src/dialect/mod.rs | 5 +++++
src/dialect/sqlite.rs | 5 +++++
src/parser/mod.rs | 4 +++-
tests/sqlparser_common.rs | 4 +++-
tests/sqlparser_sqlite.rs | 14 ++++++++++++++
5 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs
index 2beb5655..078766c3 100644
--- a/src/dialect/mod.rs
+++ b/src/dialect/mod.rs
@@ -1457,6 +1457,11 @@ pub trait Dialect: Debug + Any {
false
}
+ /// Returns true if the dialect accepts `VALUE` as a synonym of `VALUES`.
+ fn supports_singular_value_keyword(&self) -> bool {
+ true
+ }
+
/// Returns true if this dialect supports `SET` statements without an explicit
/// assignment operator such as `=`. For example: `SET SHOWPLAN_XML ON`.
fn supports_set_stmt_without_operator(&self) -> bool {
diff --git a/src/dialect/sqlite.rs b/src/dialect/sqlite.rs
index 6f9ec0d2..92ce4024 100644
--- a/src/dialect/sqlite.rs
+++ b/src/dialect/sqlite.rs
@@ -142,4 +142,9 @@ impl Dialect for SQLiteDialect {
fn supports_national_string_literal(&self) -> bool {
false
}
+
+ /// See <https://sqlite.org/lang_insert.html>
+ fn supports_singular_value_keyword(&self) -> bool {
+ false
+ }
}
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 1a46c6e5..d37d35c2 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -15303,7 +15303,9 @@ impl<'a> Parser<'a> {
} else if self.parse_keyword(Keyword::VALUES) {
let is_mysql = dialect_of!(self is MySqlDialect);
SetExpr::Values(self.parse_values(is_mysql, false)?)
- } else if self.parse_keyword(Keyword::VALUE) {
+ } else if self.dialect.supports_singular_value_keyword()
+ && self.parse_keyword(Keyword::VALUE)
+ {
let is_mysql = dialect_of!(self is MySqlDialect);
SetExpr::Values(self.parse_values(is_mysql, true)?)
} else if self.parse_keyword(Keyword::TABLE) {
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index 8e08c657..ec5a5ba6 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -161,7 +161,9 @@ fn parse_insert_values() {
expected_rows: &[Parens<Vec<Expr>>],
expected_value_keyword: bool,
) {
- match verified_stmt(sql) {
+ let dialects =
+ all_dialects_where(|d| !expected_value_keyword || d.supports_singular_value_keyword());
+ match dialects.verified_stmt(sql) {
Statement::Insert(Insert {
table: table_name,
columns,
diff --git a/tests/sqlparser_sqlite.rs b/tests/sqlparser_sqlite.rs
index b8fad7e9..b9b7c019 100644
--- a/tests/sqlparser_sqlite.rs
+++ b/tests/sqlparser_sqlite.rs
@@ -1024,6 +1024,20 @@ fn parse_n_prefix_not_national_string() {
all_dialects_where(|d| d.supports_national_string_literal()).verified_stmt("SELECT N'hello'");
}
+#[test]
+fn parse_singular_value_keyword_rejected() {
+ for sql in [
+ "INSERT INTO t VALUE (1)",
+ "INSERT INTO t (a) VALUE (1)",
+ "SELECT * FROM (VALUE (1))",
+ ] {
+ assert!(sqlite().parse_sql_statements(sql).is_err(), "{sql}");
+ }
+ sqlite().verified_stmt("INSERT INTO t (a) VALUES (1)");
+ all_dialects_where(|d| d.supports_singular_value_keyword())
+ .verified_stmt("INSERT INTO t (a) VALUE (1)");
+}
+
fn sqlite() -> TestedDialects {
TestedDialects::new(vec![Box::new(SQLiteDialect {})])
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org