mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-20 04:39:49 +00:00
support sqlite's OR clauses in update statements (#1530)
This commit is contained in:
parent
a67a4f3cbe
commit
4c629e8520
6 changed files with 59 additions and 26 deletions
|
@ -505,8 +505,8 @@ impl Display for Insert {
|
||||||
self.table_name.to_string()
|
self.table_name.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(action) = self.or {
|
if let Some(on_conflict) = self.or {
|
||||||
write!(f, "INSERT OR {action} INTO {table_name} ")?;
|
write!(f, "INSERT {on_conflict} INTO {table_name} ")?;
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
|
|
|
@ -2396,6 +2396,8 @@ pub enum Statement {
|
||||||
selection: Option<Expr>,
|
selection: Option<Expr>,
|
||||||
/// RETURNING
|
/// RETURNING
|
||||||
returning: Option<Vec<SelectItem>>,
|
returning: Option<Vec<SelectItem>>,
|
||||||
|
/// SQLite-specific conflict resolution clause
|
||||||
|
or: Option<SqliteOnConflict>,
|
||||||
},
|
},
|
||||||
/// ```sql
|
/// ```sql
|
||||||
/// DELETE
|
/// DELETE
|
||||||
|
@ -3691,8 +3693,13 @@ impl fmt::Display for Statement {
|
||||||
from,
|
from,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
or,
|
||||||
} => {
|
} => {
|
||||||
write!(f, "UPDATE {table}")?;
|
write!(f, "UPDATE ")?;
|
||||||
|
if let Some(or) = or {
|
||||||
|
write!(f, "{or} ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{table}")?;
|
||||||
if !assignments.is_empty() {
|
if !assignments.is_empty() {
|
||||||
write!(f, " SET {}", display_comma_separated(assignments))?;
|
write!(f, " SET {}", display_comma_separated(assignments))?;
|
||||||
}
|
}
|
||||||
|
@ -6304,11 +6311,11 @@ impl fmt::Display for SqliteOnConflict {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use SqliteOnConflict::*;
|
use SqliteOnConflict::*;
|
||||||
match self {
|
match self {
|
||||||
Rollback => write!(f, "ROLLBACK"),
|
Rollback => write!(f, "OR ROLLBACK"),
|
||||||
Abort => write!(f, "ABORT"),
|
Abort => write!(f, "OR ABORT"),
|
||||||
Fail => write!(f, "FAIL"),
|
Fail => write!(f, "OR FAIL"),
|
||||||
Ignore => write!(f, "IGNORE"),
|
Ignore => write!(f, "OR IGNORE"),
|
||||||
Replace => write!(f, "REPLACE"),
|
Replace => write!(f, "OR REPLACE"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11042,24 +11042,7 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parse an INSERT statement
|
/// Parse an INSERT statement
|
||||||
pub fn parse_insert(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_insert(&mut self) -> Result<Statement, ParserError> {
|
||||||
let or = if !dialect_of!(self is SQLiteDialect) {
|
let or = self.parse_conflict_clause();
|
||||||
None
|
|
||||||
} else if self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]) {
|
|
||||||
Some(SqliteOnConflict::Replace)
|
|
||||||
} else if self.parse_keywords(&[Keyword::OR, Keyword::ROLLBACK]) {
|
|
||||||
Some(SqliteOnConflict::Rollback)
|
|
||||||
} else if self.parse_keywords(&[Keyword::OR, Keyword::ABORT]) {
|
|
||||||
Some(SqliteOnConflict::Abort)
|
|
||||||
} else if self.parse_keywords(&[Keyword::OR, Keyword::FAIL]) {
|
|
||||||
Some(SqliteOnConflict::Fail)
|
|
||||||
} else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) {
|
|
||||||
Some(SqliteOnConflict::Ignore)
|
|
||||||
} else if self.parse_keyword(Keyword::REPLACE) {
|
|
||||||
Some(SqliteOnConflict::Replace)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let priority = if !dialect_of!(self is MySqlDialect | GenericDialect) {
|
let priority = if !dialect_of!(self is MySqlDialect | GenericDialect) {
|
||||||
None
|
None
|
||||||
} else if self.parse_keyword(Keyword::LOW_PRIORITY) {
|
} else if self.parse_keyword(Keyword::LOW_PRIORITY) {
|
||||||
|
@ -11218,6 +11201,24 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_conflict_clause(&mut self) -> Option<SqliteOnConflict> {
|
||||||
|
if self.parse_keywords(&[Keyword::OR, Keyword::REPLACE]) {
|
||||||
|
Some(SqliteOnConflict::Replace)
|
||||||
|
} else if self.parse_keywords(&[Keyword::OR, Keyword::ROLLBACK]) {
|
||||||
|
Some(SqliteOnConflict::Rollback)
|
||||||
|
} else if self.parse_keywords(&[Keyword::OR, Keyword::ABORT]) {
|
||||||
|
Some(SqliteOnConflict::Abort)
|
||||||
|
} else if self.parse_keywords(&[Keyword::OR, Keyword::FAIL]) {
|
||||||
|
Some(SqliteOnConflict::Fail)
|
||||||
|
} else if self.parse_keywords(&[Keyword::OR, Keyword::IGNORE]) {
|
||||||
|
Some(SqliteOnConflict::Ignore)
|
||||||
|
} else if self.parse_keyword(Keyword::REPLACE) {
|
||||||
|
Some(SqliteOnConflict::Replace)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_insert_partition(&mut self) -> Result<Option<Vec<Expr>>, ParserError> {
|
pub fn parse_insert_partition(&mut self) -> Result<Option<Vec<Expr>>, ParserError> {
|
||||||
if self.parse_keyword(Keyword::PARTITION) {
|
if self.parse_keyword(Keyword::PARTITION) {
|
||||||
self.expect_token(&Token::LParen)?;
|
self.expect_token(&Token::LParen)?;
|
||||||
|
@ -11253,6 +11254,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
|
pub fn parse_update(&mut self) -> Result<Statement, ParserError> {
|
||||||
|
let or = self.parse_conflict_clause();
|
||||||
let table = self.parse_table_and_joins()?;
|
let table = self.parse_table_and_joins()?;
|
||||||
self.expect_keyword(Keyword::SET)?;
|
self.expect_keyword(Keyword::SET)?;
|
||||||
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
|
let assignments = self.parse_comma_separated(Parser::parse_assignment)?;
|
||||||
|
@ -11279,6 +11281,7 @@ impl<'a> Parser<'a> {
|
||||||
from,
|
from,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
or,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -443,6 +443,7 @@ fn parse_update_set_from() {
|
||||||
])),
|
])),
|
||||||
}),
|
}),
|
||||||
returning: None,
|
returning: None,
|
||||||
|
or: None,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -457,6 +458,7 @@ fn parse_update_with_table_alias() {
|
||||||
from: _from,
|
from: _from,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
or: None,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TableWithJoins {
|
TableWithJoins {
|
||||||
|
@ -505,6 +507,25 @@ fn parse_update_with_table_alias() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_update_or() {
|
||||||
|
let expect_or_clause = |sql: &str, expected_action: SqliteOnConflict| match verified_stmt(sql) {
|
||||||
|
Statement::Update { or, .. } => assert_eq!(or, Some(expected_action)),
|
||||||
|
other => unreachable!("Expected update with or, got {:?}", other),
|
||||||
|
};
|
||||||
|
expect_or_clause(
|
||||||
|
"UPDATE OR REPLACE t SET n = n + 1",
|
||||||
|
SqliteOnConflict::Replace,
|
||||||
|
);
|
||||||
|
expect_or_clause(
|
||||||
|
"UPDATE OR ROLLBACK t SET n = n + 1",
|
||||||
|
SqliteOnConflict::Rollback,
|
||||||
|
);
|
||||||
|
expect_or_clause("UPDATE OR ABORT t SET n = n + 1", SqliteOnConflict::Abort);
|
||||||
|
expect_or_clause("UPDATE OR FAIL t SET n = n + 1", SqliteOnConflict::Fail);
|
||||||
|
expect_or_clause("UPDATE OR IGNORE t SET n = n + 1", SqliteOnConflict::Ignore);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_select_with_table_alias_as() {
|
fn parse_select_with_table_alias_as() {
|
||||||
// AS is optional
|
// AS is optional
|
||||||
|
|
|
@ -1970,6 +1970,7 @@ fn parse_update_with_joins() {
|
||||||
from: _from,
|
from: _from,
|
||||||
selection,
|
selection,
|
||||||
returning,
|
returning,
|
||||||
|
or: None,
|
||||||
} => {
|
} => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
TableWithJoins {
|
TableWithJoins {
|
||||||
|
|
|
@ -465,6 +465,7 @@ fn parse_update_tuple_row_values() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sqlite().verified_stmt("UPDATE x SET (a, b) = (1, 2)"),
|
sqlite().verified_stmt("UPDATE x SET (a, b) = (1, 2)"),
|
||||||
Statement::Update {
|
Statement::Update {
|
||||||
|
or: None,
|
||||||
assignments: vec![Assignment {
|
assignments: vec![Assignment {
|
||||||
target: AssignmentTarget::Tuple(vec![
|
target: AssignmentTarget::Tuple(vec![
|
||||||
ObjectName(vec![Ident::new("a"),]),
|
ObjectName(vec![Ident::new("a"),]),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue