Skip to content

Commit 4bd4227

Browse files
committed
add support for sqlite's OR clauses in update statements
fix apache#1529
1 parent 724a1d1 commit 4bd4227

File tree

5 files changed

+64
-19
lines changed

5 files changed

+64
-19
lines changed

src/ast/mod.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2396,6 +2396,8 @@ pub enum Statement {
23962396
selection: Option<Expr>,
23972397
/// RETURNING
23982398
returning: Option<Vec<SelectItem>>,
2399+
/// SQLite-specific conflict resolution clause
2400+
or: Option<SqliteOnConflict>,
23992401
},
24002402
/// ```sql
24012403
/// DELETE
@@ -3691,8 +3693,13 @@ impl fmt::Display for Statement {
36913693
from,
36923694
selection,
36933695
returning,
3696+
or,
36943697
} => {
3695-
write!(f, "UPDATE {table}")?;
3698+
write!(f, "UPDATE ")?;
3699+
if let Some(or) = or {
3700+
write!(f, "{or} ")?;
3701+
}
3702+
write!(f, "{table}")?;
36963703
if !assignments.is_empty() {
36973704
write!(f, " SET {}", display_comma_separated(assignments))?;
36983705
}

src/parser/mod.rs

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11032,24 +11032,7 @@ impl<'a> Parser<'a> {
1103211032

1103311033
/// Parse an INSERT statement
1103411034
pub fn parse_insert(&mut self) -> Result<Statement, ParserError> {
11035-
let or = if !dialect_of!(self is SQLiteDialect) {
11036-
None
11037-
} else if self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]) {
11038-
Some(SqliteOnConflict::Replace)
11039-
} else if self.parse_keywords(&[Keyword::OR, Keyword::ROLLBACK]) {
11040-
Some(SqliteOnConflict::Rollback)
11041-
} else if self.parse_keywords(&[Keyword::OR, Keyword::ABORT]) {
11042-
Some(SqliteOnConflict::Abort)
11043-
} else if self.parse_keywords(&[Keyword::OR, Keyword::FAIL]) {
11044-
Some(SqliteOnConflict::Fail)
11045-
} else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) {
11046-
Some(SqliteOnConflict::Ignore)
11047-
} else if self.parse_keyword(Keyword::REPLACE) {
11048-
Some(SqliteOnConflict::Replace)
11049-
} else {
11050-
None
11051-
};
11052-
11035+
let or = self.parse_conflict_clause();
1105311036
let priority = if !dialect_of!(self is MySqlDialect | GenericDialect) {
1105411037
None
1105511038
} else if self.parse_keyword(Keyword::LOW_PRIORITY) {
@@ -11208,6 +11191,24 @@ impl<'a> Parser<'a> {
1120811191
}
1120911192
}
1121011193

11194+
fn parse_conflict_clause(&mut self) -> Option<SqliteOnConflict> {
11195+
if self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]) {
11196+
Some(SqliteOnConflict::Replace)
11197+
} else if self.parse_keywords(&[Keyword::OR, Keyword::ROLLBACK]) {
11198+
Some(SqliteOnConflict::Rollback)
11199+
} else if self.parse_keywords(&[Keyword::OR, Keyword::ABORT]) {
11200+
Some(SqliteOnConflict::Abort)
11201+
} else if self.parse_keywords(&[Keyword::OR, Keyword::FAIL]) {
11202+
Some(SqliteOnConflict::Fail)
11203+
} else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) {
11204+
Some(SqliteOnConflict::Ignore)
11205+
} else if self.parse_keyword(Keyword::REPLACE) {
11206+
Some(SqliteOnConflict::Replace)
11207+
} else {
11208+
None
11209+
}
11210+
}
11211+
1121111212
pub fn parse_insert_partition(&mut self) -> Result<Option<Vec<Expr>>, ParserError> {
1121211213
if self.parse_keyword(Keyword::PARTITION) {
1121311214
self.expect_token(&Token::LParen)?;
@@ -11243,6 +11244,7 @@ impl<'a> Parser<'a> {
1124311244
}
1124411245

1124511246
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
11247+
let or = self.parse_conflict_clause();
1124611248
let table = self.parse_table_and_joins()?;
1124711249
self.expect_keyword(Keyword::SET)?;
1124811250
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
@@ -11269,6 +11271,7 @@ impl<'a> Parser<'a> {
1126911271
from,
1127011272
selection,
1127111273
returning,
11274+
or,
1127211275
})
1127311276
}
1127411277

tests/sqlparser_common.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ fn parse_update_set_from() {
443443
])),
444444
}),
445445
returning: None,
446+
or: None,
446447
}
447448
);
448449
}
@@ -457,6 +458,7 @@ fn parse_update_with_table_alias() {
457458
from: _from,
458459
selection,
459460
returning,
461+
or: None,
460462
} => {
461463
assert_eq!(
462464
TableWithJoins {
@@ -505,6 +507,37 @@ fn parse_update_with_table_alias() {
505507
}
506508
}
507509

510+
#[test]
511+
fn parse_update_or() {
512+
let dialect = SQLiteDialect {};
513+
514+
let check = |sql: &str, expected_action: Option<SqliteOnConflict>| match Parser::parse_sql(
515+
&dialect, sql,
516+
)
517+
.unwrap()
518+
.pop()
519+
.unwrap()
520+
{
521+
Statement::Update { or, .. } => assert_eq!(or, expected_action),
522+
_ => panic!("{}", sql),
523+
};
524+
525+
let sql = "UPDATE OR REPLACE t SET n = n + 1";
526+
check(sql, Some(SqliteOnConflict::Replace));
527+
528+
let sql = "UPDATE OR ROLLBACK t SET n = n + 1";
529+
check(sql, Some(SqliteOnConflict::Rollback));
530+
531+
let sql = "UPDATE OR ABORT t SET n = n + 1";
532+
check(sql, Some(SqliteOnConflict::Abort));
533+
534+
let sql = "UPDATE OR FAIL t SET n = n + 1";
535+
check(sql, Some(SqliteOnConflict::Fail));
536+
537+
let sql = "UPDATE OR IGNORE t SET n = n + 1";
538+
check(sql, Some(SqliteOnConflict::Ignore));
539+
}
540+
508541
#[test]
509542
fn parse_select_with_table_alias_as() {
510543
// AS is optional

tests/sqlparser_mysql.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,7 @@ fn parse_update_with_joins() {
19701970
from: _from,
19711971
selection,
19721972
returning,
1973+
or: None,
19731974
} => {
19741975
assert_eq!(
19751976
TableWithJoins {

tests/sqlparser_sqlite.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ fn parse_update_tuple_row_values() {
465465
assert_eq!(
466466
sqlite().verified_stmt("UPDATE x SET (a, b) = (1, 2)"),
467467
Statement::Update {
468+
or: None,
468469
assignments: vec![Assignment {
469470
target: AssignmentTarget::Tuple(vec![
470471
ObjectName(vec![Ident::new("a"),]),

0 commit comments

Comments
 (0)