You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/10/14 17:11:24 UTC

(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2626-dacdbc99cd16c335fccd353ba41f6c18a7cd73b8 created (now 159c667f)

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

github-merge-queue[bot] pushed a change to branch gh-readonly-queue/main/pr-2626-dacdbc99cd16c335fccd353ba41f6c18a7cd73b8
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


      at 159c667f Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)

This branch includes the following new commits:

     new 159c667f Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org


(datafusion-sqlparser-rs) 01/01: Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)

Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-2626-dacdbc99cd16c335fccd353ba41f6c18a7cd73b8
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git

commit 159c667f5808d02e4212896463bdb7d69eb62575
Author: Zvonimir <zv...@datadoghq.com>
AuthorDate: Wed Oct 14 17:11:03 2026 +0000

    Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)
    
    Co-authored-by: Claude Opus 5.5 <no...@anthropic.com>
---
 src/ast/dml.rs              | 32 +++++++++++++++++++++
 src/ast/mod.rs              |  4 +--
 src/ast/spans.rs            |  1 +
 src/dialect/snowflake.rs    |  1 +
 src/keywords.rs             |  1 +
 src/parser/mod.rs           | 25 +++++++++++++++-
 tests/sqlparser_postgres.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 130 insertions(+), 3 deletions(-)

diff --git a/src/ast/dml.rs b/src/ast/dml.rs
index 291fc9fa..c8d55ee6 100644
--- a/src/ast/dml.rs
+++ b/src/ast/dml.rs
@@ -37,6 +37,29 @@ use super::{
     Values,
 };
 
+/// The `OVERRIDING` clause of a PostgreSQL `INSERT`: whether values supplied for an identity
+/// column are used instead of the values its sequence would generate.
+///
+/// See <https://www.postgresql.org/docs/current/sql-insert.html>
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum InsertOverriding {
+    /// `OVERRIDING SYSTEM VALUE`
+    System,
+    /// `OVERRIDING USER VALUE`
+    User,
+}
+
+impl Display for InsertOverriding {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            InsertOverriding::System => write!(f, "OVERRIDING SYSTEM VALUE"),
+            InsertOverriding::User => write!(f, "OVERRIDING USER VALUE"),
+        }
+    }
+}
+
 /// INSERT statement.
 #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -87,6 +110,10 @@ pub struct Insert {
     pub partitioned: Option<Vec<Expr>>,
     /// Columns defined after PARTITION
     pub after_columns: Vec<Ident>,
+    /// PostgreSQL `OVERRIDING { SYSTEM | USER } VALUE`, between the column list and the source.
+    ///
+    /// See <https://www.postgresql.org/docs/current/sql-insert.html>
+    pub overriding: Option<InsertOverriding>,
     /// whether the insert has the table keyword (Hive)
     pub has_table_keyword: bool,
     /// ON INSERT
@@ -225,6 +252,11 @@ impl Display for Insert {
             SpaceOrNewline.fmt(f)?;
         }
 
+        if let Some(overriding) = &self.overriding {
+            write!(f, "{overriding}")?;
+            SpaceOrNewline.fmt(f)?;
+        }
+
         if let Some(output) = &self.output {
             write!(f, "{output}")?;
             SpaceOrNewline.fmt(f)?;
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 9d3ee77e..fcd013aa 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -88,8 +88,8 @@ pub use self::ddl::{
     UserDefinedTypeStorage, ViewColumnDef, WithData,
 };
 pub use self::dml::{
-    Delete, Insert, Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr,
-    MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, MultiTableInsertIntoClause,
+    Delete, Insert, InsertOverriding, Merge, MergeAction, MergeClause, MergeClauseKind,
+    MergeInsertExpr, MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, MultiTableInsertIntoClause,
     MultiTableInsertType, MultiTableInsertValue, MultiTableInsertValues,
     MultiTableInsertWhenClause, OutputClause, Update,
 };
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index cae24f95..6c4a11c9 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -1363,6 +1363,7 @@ impl Spanned for Insert {
             source,
             partitioned,
             after_columns,
+            overriding: _,        // enum, postgres specific
             has_table_keyword: _, // bool
             on,
             returning,
diff --git a/src/dialect/snowflake.rs b/src/dialect/snowflake.rs
index 3ebc1686..a25f2863 100644
--- a/src/dialect/snowflake.rs
+++ b/src/dialect/snowflake.rs
@@ -1906,6 +1906,7 @@ fn parse_multi_table_insert(
         assignments: vec![],
         partitioned: None,
         after_columns: vec![],
+        overriding: None,
         has_table_keyword: false,
         on: None,
         returning: None,
diff --git a/src/keywords.rs b/src/keywords.rs
index deae7bbd..e25cb34c 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -762,6 +762,7 @@ define_keywords!(
     OVERLAPS,
     OVERLAY,
     OVERRIDE,
+    OVERRIDING,
     OVERWRITE,
     OWNED,
     OWNER,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 6daad0f6..e7f26c1a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -18672,9 +18672,12 @@ impl<'a> Parser<'a> {
             let table = self.parse_keyword(Keyword::TABLE);
             let table_object = self.parse_table_object()?;
 
-            // `BY NAME` is an INSERT clause, not a table alias.
+            // `BY NAME` and `OVERRIDING { SYSTEM | USER } VALUE` are INSERT clauses, not table
+            // aliases.
             let table_alias = if self.dialect.supports_insert_table_alias()
                 && !self.peek_keywords(&[Keyword::BY, Keyword::NAME])
+                && !self.peek_keywords(&[Keyword::OVERRIDING, Keyword::SYSTEM])
+                && !self.peek_keywords(&[Keyword::OVERRIDING, Keyword::USER])
                 && !self.peek_sub_query()
                 && self
                     .peek_one_of_keywords(&[Keyword::DEFAULT, Keyword::VALUES])
@@ -18699,6 +18702,7 @@ impl<'a> Parser<'a> {
             let is_mysql = dialect_of!(self is MySqlDialect);
 
             let mut by_name = false;
+            let mut overriding = None;
             let (columns, partitioned, after_columns, output, source, assignments) = if self
                 .parse_keywords(&[Keyword::DEFAULT, Keyword::VALUES])
             {
@@ -18721,6 +18725,8 @@ impl<'a> Parser<'a> {
                     Default::default()
                 };
 
+                overriding = self.parse_insert_overriding()?;
+
                 let output = self.maybe_parse_output_clause()?;
 
                 let (source, assignments) = if self.peek_keyword(Keyword::FORMAT)
@@ -18838,6 +18844,7 @@ impl<'a> Parser<'a> {
                 partitioned,
                 columns,
                 after_columns,
+                overriding,
                 source,
                 assignments,
                 has_table_keyword: table,
@@ -18926,6 +18933,22 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parse PostgreSQL's `OVERRIDING { SYSTEM | USER } VALUE` in an `INSERT`, if present.
+    fn parse_insert_overriding(&mut self) -> Result<Option<InsertOverriding>, ParserError> {
+        if !self.parse_keyword(Keyword::OVERRIDING) {
+            return Ok(None);
+        }
+        let overriding = if self.parse_keyword(Keyword::SYSTEM) {
+            InsertOverriding::System
+        } else if self.parse_keyword(Keyword::USER) {
+            InsertOverriding::User
+        } else {
+            return self.expected_ref("SYSTEM or USER", self.peek_token_ref());
+        };
+        self.expect_keyword_is(Keyword::VALUE)?;
+        Ok(Some(overriding))
+    }
+
     /// Parse an optional `PARTITION (...)` clause for INSERT statements.
     pub fn parse_insert_partition(&mut self) -> Result<Option<Vec<Expr>>, ParserError> {
         if self.parse_keyword(Keyword::PARTITION) {
diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs
index fb998510..dbc61db8 100644
--- a/tests/sqlparser_postgres.rs
+++ b/tests/sqlparser_postgres.rs
@@ -6146,6 +6146,7 @@ fn test_simple_postgres_insert_with_alias() {
             assignments: vec![],
             partitioned: None,
             after_columns: vec![],
+            overriding: None,
             has_table_keyword: false,
             on: None,
             returning: None,
@@ -6230,6 +6231,7 @@ fn test_simple_postgres_insert_with_alias() {
             assignments: vec![],
             partitioned: None,
             after_columns: vec![],
+            overriding: None,
             has_table_keyword: false,
             on: None,
             returning: None,
@@ -6312,6 +6314,7 @@ fn test_simple_insert_with_quoted_alias() {
             assignments: vec![],
             partitioned: None,
             after_columns: vec![],
+            overriding: None,
             has_table_keyword: false,
             on: None,
             returning: None,
@@ -10037,6 +10040,72 @@ fn parse_trim_from_without_characters() {
     pg().one_statement_parses_to("SELECT TRIM(FROM ' x ')", "SELECT TRIM(' x ')");
 }
 
+#[test]
+fn parse_insert_overriding() {
+    for (sql, expected) in [
+        (
+            "INSERT INTO t (id, a) OVERRIDING SYSTEM VALUE VALUES (1, 'x')",
+            InsertOverriding::System,
+        ),
+        (
+            "INSERT INTO t (id, a) OVERRIDING USER VALUE VALUES (1, 'x')",
+            InsertOverriding::User,
+        ),
+        (
+            "INSERT INTO t (id, a) OVERRIDING SYSTEM VALUE SELECT id, a FROM u",
+            InsertOverriding::System,
+        ),
+        (
+            "INSERT INTO t (id) OVERRIDING USER VALUE VALUES (1) ON CONFLICT DO NOTHING RETURNING id",
+            InsertOverriding::User,
+        ),
+    ] {
+        match pg_and_generic().verified_stmt(sql) {
+            Statement::Insert(Insert { overriding, .. }) => assert_eq!(overriding, Some(expected)),
+            statement => panic!("Expected INSERT statement, got: {statement:?}"),
+        }
+    }
+
+    // Without a column list, PostgreSQL's implicit table alias must not swallow `OVERRIDING`.
+    for sql in [
+        "INSERT INTO t OVERRIDING SYSTEM VALUE VALUES (1, 'x')",
+        "INSERT INTO t OVERRIDING USER VALUE SELECT * FROM u",
+    ] {
+        match pg().verified_stmt(sql) {
+            Statement::Insert(Insert {
+                table_alias,
+                overriding,
+                ..
+            }) => {
+                assert_eq!(table_alias, None);
+                assert!(overriding.is_some());
+            }
+            statement => panic!("Expected INSERT statement, got: {statement:?}"),
+        }
+    }
+    pg().verified_stmt("INSERT INTO t AS x (id) OVERRIDING SYSTEM VALUE VALUES (1)");
+
+    // An INSERT without the clause has none.
+    match pg_and_generic().verified_stmt("INSERT INTO t (id) VALUES (1)") {
+        Statement::Insert(Insert { overriding, .. }) => assert_eq!(overriding, None),
+        statement => panic!("Expected INSERT statement, got: {statement:?}"),
+    }
+
+    // `OVERRIDING` takes `SYSTEM` or `USER`, then `VALUE`, and is followed by a query: PostgreSQL's
+    // grammar does not allow it before `DEFAULT VALUES`.
+    for sql in [
+        "INSERT INTO t (id) OVERRIDING VALUE VALUES (1)",
+        "INSERT INTO t (id) OVERRIDING SYSTEM VALUES (1)",
+        "INSERT INTO t (id) OVERRIDING DEFAULT VALUE VALUES (1)",
+        "INSERT INTO t OVERRIDING SYSTEM VALUE DEFAULT VALUES",
+    ] {
+        assert!(
+            pg_and_generic().parse_sql_statements(sql).is_err(),
+            "{sql} should not parse"
+        );
+    }
+}
+
 #[test]
 fn parse_insert_by_name_keywords_as_table_and_alias() {
     // Without a table name, `BY NAME` is not an INSERT BY NAME clause. PostgreSQL


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org