Skip to content

Commit fef1e35

Browse files
zvonimir-ddclaude
andauthored
Postgres: support OVERRIDING { SYSTEM | USER } VALUE in INSERT (#2626)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 7cac9e1 commit fef1e35

7 files changed

Lines changed: 130 additions & 3 deletions

File tree

‎src/ast/dml.rs‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ use super::{
3737
Values,
3838
};
3939

40+
/// The `OVERRIDING` clause of a PostgreSQL `INSERT`: whether values supplied for an identity
41+
/// column are used instead of the values its sequence would generate.
42+
///
43+
/// See <https://www.postgresql.org/docs/current/sql-insert.html>
44+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
45+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
46+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
47+
pub enum InsertOverriding {
48+
/// `OVERRIDING SYSTEM VALUE`
49+
System,
50+
/// `OVERRIDING USER VALUE`
51+
User,
52+
}
53+
54+
impl Display for InsertOverriding {
55+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56+
match self {
57+
InsertOverriding::System => write!(f, "OVERRIDING SYSTEM VALUE"),
58+
InsertOverriding::User => write!(f, "OVERRIDING USER VALUE"),
59+
}
60+
}
61+
}
62+
4063
/// INSERT statement.
4164
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
4265
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@@ -87,6 +110,10 @@ pub struct Insert {
87110
pub partitioned: Option<Vec<Expr>>,
88111
/// Columns defined after PARTITION
89112
pub after_columns: Vec<Ident>,
113+
/// PostgreSQL `OVERRIDING { SYSTEM | USER } VALUE`, between the column list and the source.
114+
///
115+
/// See <https://www.postgresql.org/docs/current/sql-insert.html>
116+
pub overriding: Option<InsertOverriding>,
90117
/// whether the insert has the table keyword (Hive)
91118
pub has_table_keyword: bool,
92119
/// ON INSERT
@@ -225,6 +252,11 @@ impl Display for Insert {
225252
SpaceOrNewline.fmt(f)?;
226253
}
227254

255+
if let Some(overriding) = &self.overriding {
256+
write!(f, "{overriding}")?;
257+
SpaceOrNewline.fmt(f)?;
258+
}
259+
228260
if let Some(output) = &self.output {
229261
write!(f, "{output}")?;
230262
SpaceOrNewline.fmt(f)?;

‎src/ast/mod.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ pub use self::ddl::{
8888
UserDefinedTypeStorage, ViewColumnDef, WithData,
8989
};
9090
pub use self::dml::{
91-
Delete, Insert, Merge, MergeAction, MergeClause, MergeClauseKind, MergeInsertExpr,
92-
MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, MultiTableInsertIntoClause,
91+
Delete, Insert, InsertOverriding, Merge, MergeAction, MergeClause, MergeClauseKind,
92+
MergeInsertExpr, MergeInsertKind, MergeUpdateExpr, MergeUpdateKind, MultiTableInsertIntoClause,
9393
MultiTableInsertType, MultiTableInsertValue, MultiTableInsertValues,
9494
MultiTableInsertWhenClause, OutputClause, Update,
9595
};

‎src/ast/spans.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,6 +1363,7 @@ impl Spanned for Insert {
13631363
source,
13641364
partitioned,
13651365
after_columns,
1366+
overriding: _, // enum, postgres specific
13661367
has_table_keyword: _, // bool
13671368
on,
13681369
returning,

‎src/dialect/snowflake.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,7 @@ fn parse_multi_table_insert(
19061906
assignments: vec![],
19071907
partitioned: None,
19081908
after_columns: vec![],
1909+
overriding: None,
19091910
has_table_keyword: false,
19101911
on: None,
19111912
returning: None,

‎src/keywords.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ define_keywords!(
762762
OVERLAPS,
763763
OVERLAY,
764764
OVERRIDE,
765+
OVERRIDING,
765766
OVERWRITE,
766767
OWNED,
767768
OWNER,

‎src/parser/mod.rs‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18705,9 +18705,12 @@ impl<'a> Parser<'a> {
1870518705
let table = self.parse_keyword(Keyword::TABLE);
1870618706
let table_object = self.parse_table_object()?;
1870718707

18708-
// `BY NAME` is an INSERT clause, not a table alias.
18708+
// `BY NAME` and `OVERRIDING { SYSTEM | USER } VALUE` are INSERT clauses, not table
18709+
// aliases.
1870918710
let table_alias = if self.dialect.supports_insert_table_alias()
1871018711
&& !self.peek_keywords(&[Keyword::BY, Keyword::NAME])
18712+
&& !self.peek_keywords(&[Keyword::OVERRIDING, Keyword::SYSTEM])
18713+
&& !self.peek_keywords(&[Keyword::OVERRIDING, Keyword::USER])
1871118714
&& !self.peek_sub_query()
1871218715
&& self
1871318716
.peek_one_of_keywords(&[Keyword::DEFAULT, Keyword::VALUES])
@@ -18732,6 +18735,7 @@ impl<'a> Parser<'a> {
1873218735
let is_mysql = dialect_of!(self is MySqlDialect);
1873318736

1873418737
let mut by_name = false;
18738+
let mut overriding = None;
1873518739
let (columns, partitioned, after_columns, output, source, assignments) = if self
1873618740
.parse_keywords(&[Keyword::DEFAULT, Keyword::VALUES])
1873718741
{
@@ -18754,6 +18758,8 @@ impl<'a> Parser<'a> {
1875418758
Default::default()
1875518759
};
1875618760

18761+
overriding = self.parse_insert_overriding()?;
18762+
1875718763
let output = self.maybe_parse_output_clause()?;
1875818764

1875918765
let (source, assignments) = if self.peek_keyword(Keyword::FORMAT)
@@ -18871,6 +18877,7 @@ impl<'a> Parser<'a> {
1887118877
partitioned,
1887218878
columns,
1887318879
after_columns,
18880+
overriding,
1887418881
source,
1887518882
assignments,
1887618883
has_table_keyword: table,
@@ -18959,6 +18966,22 @@ impl<'a> Parser<'a> {
1895918966
}
1896018967
}
1896118968

18969+
/// Parse PostgreSQL's `OVERRIDING { SYSTEM | USER } VALUE` in an `INSERT`, if present.
18970+
fn parse_insert_overriding(&mut self) -> Result<Option<InsertOverriding>, ParserError> {
18971+
if !self.parse_keyword(Keyword::OVERRIDING) {
18972+
return Ok(None);
18973+
}
18974+
let overriding = if self.parse_keyword(Keyword::SYSTEM) {
18975+
InsertOverriding::System
18976+
} else if self.parse_keyword(Keyword::USER) {
18977+
InsertOverriding::User
18978+
} else {
18979+
return self.expected_ref("SYSTEM or USER", self.peek_token_ref());
18980+
};
18981+
self.expect_keyword_is(Keyword::VALUE)?;
18982+
Ok(Some(overriding))
18983+
}
18984+
1896218985
/// Parse an optional `PARTITION (...)` clause for INSERT statements.
1896318986
pub fn parse_insert_partition(&mut self) -> Result<Option<Vec<Expr>>, ParserError> {
1896418987
if self.parse_keyword(Keyword::PARTITION) {

‎tests/sqlparser_postgres.rs‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6165,6 +6165,7 @@ fn test_simple_postgres_insert_with_alias() {
61656165
assignments: vec![],
61666166
partitioned: None,
61676167
after_columns: vec![],
6168+
overriding: None,
61686169
has_table_keyword: false,
61696170
on: None,
61706171
returning: None,
@@ -6249,6 +6250,7 @@ fn test_simple_postgres_insert_with_alias() {
62496250
assignments: vec![],
62506251
partitioned: None,
62516252
after_columns: vec![],
6253+
overriding: None,
62526254
has_table_keyword: false,
62536255
on: None,
62546256
returning: None,
@@ -6331,6 +6333,7 @@ fn test_simple_insert_with_quoted_alias() {
63316333
assignments: vec![],
63326334
partitioned: None,
63336335
after_columns: vec![],
6336+
overriding: None,
63346337
has_table_keyword: false,
63356338
on: None,
63366339
returning: None,
@@ -9996,6 +9999,72 @@ fn parse_trim_from_without_characters() {
99969999
pg().one_statement_parses_to("SELECT TRIM(FROM ' x ')", "SELECT TRIM(' x ')");
999710000
}
999810001

10002+
#[test]
10003+
fn parse_insert_overriding() {
10004+
for (sql, expected) in [
10005+
(
10006+
"INSERT INTO t (id, a) OVERRIDING SYSTEM VALUE VALUES (1, 'x')",
10007+
InsertOverriding::System,
10008+
),
10009+
(
10010+
"INSERT INTO t (id, a) OVERRIDING USER VALUE VALUES (1, 'x')",
10011+
InsertOverriding::User,
10012+
),
10013+
(
10014+
"INSERT INTO t (id, a) OVERRIDING SYSTEM VALUE SELECT id, a FROM u",
10015+
InsertOverriding::System,
10016+
),
10017+
(
10018+
"INSERT INTO t (id) OVERRIDING USER VALUE VALUES (1) ON CONFLICT DO NOTHING RETURNING id",
10019+
InsertOverriding::User,
10020+
),
10021+
] {
10022+
match pg_and_generic().verified_stmt(sql) {
10023+
Statement::Insert(Insert { overriding, .. }) => assert_eq!(overriding, Some(expected)),
10024+
statement => panic!("Expected INSERT statement, got: {statement:?}"),
10025+
}
10026+
}
10027+
10028+
// Without a column list, PostgreSQL's implicit table alias must not swallow `OVERRIDING`.
10029+
for sql in [
10030+
"INSERT INTO t OVERRIDING SYSTEM VALUE VALUES (1, 'x')",
10031+
"INSERT INTO t OVERRIDING USER VALUE SELECT * FROM u",
10032+
] {
10033+
match pg().verified_stmt(sql) {
10034+
Statement::Insert(Insert {
10035+
table_alias,
10036+
overriding,
10037+
..
10038+
}) => {
10039+
assert_eq!(table_alias, None);
10040+
assert!(overriding.is_some());
10041+
}
10042+
statement => panic!("Expected INSERT statement, got: {statement:?}"),
10043+
}
10044+
}
10045+
pg().verified_stmt("INSERT INTO t AS x (id) OVERRIDING SYSTEM VALUE VALUES (1)");
10046+
10047+
// An INSERT without the clause has none.
10048+
match pg_and_generic().verified_stmt("INSERT INTO t (id) VALUES (1)") {
10049+
Statement::Insert(Insert { overriding, .. }) => assert_eq!(overriding, None),
10050+
statement => panic!("Expected INSERT statement, got: {statement:?}"),
10051+
}
10052+
10053+
// `OVERRIDING` takes `SYSTEM` or `USER`, then `VALUE`, and is followed by a query: PostgreSQL's
10054+
// grammar does not allow it before `DEFAULT VALUES`.
10055+
for sql in [
10056+
"INSERT INTO t (id) OVERRIDING VALUE VALUES (1)",
10057+
"INSERT INTO t (id) OVERRIDING SYSTEM VALUES (1)",
10058+
"INSERT INTO t (id) OVERRIDING DEFAULT VALUE VALUES (1)",
10059+
"INSERT INTO t OVERRIDING SYSTEM VALUE DEFAULT VALUES",
10060+
] {
10061+
assert!(
10062+
pg_and_generic().parse_sql_statements(sql).is_err(),
10063+
"{sql} should not parse"
10064+
);
10065+
}
10066+
}
10067+
999910068
#[test]
1000010069
fn parse_insert_by_name_keywords_as_table_and_alias() {
1000110070
// Without a table name, `BY NAME` is not an INSERT BY NAME clause. PostgreSQL

0 commit comments

Comments
 (0)