Skip to content

Commit 7dd8592

Browse files
committed
feat: Support ROLLBACK TO, RELEASE
Signed-off-by: Alex Qyoun-ae <4062971+MazterQyou@users.noreply.github.com>
1 parent e14d5bf commit 7dd8592

File tree

4 files changed

+73
-6
lines changed

4 files changed

+73
-6
lines changed

src/ast/mod.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,11 @@ pub enum Statement {
11061106
/// `COMMIT [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
11071107
Commit { chain: bool },
11081108
/// `ROLLBACK [ TRANSACTION | WORK ] [ AND [ NO ] CHAIN ]`
1109-
Rollback { chain: bool },
1109+
/// `ROLLBACK [ TRANSACTION | WORK ] TO [ SAVEPOINT ] name`
1110+
Rollback {
1111+
savepoint: Option<Ident>,
1112+
chain: bool,
1113+
},
11101114
/// CREATE SCHEMA
11111115
CreateSchema {
11121116
schema_name: ObjectName,
@@ -1184,6 +1188,8 @@ pub enum Statement {
11841188
},
11851189
/// SAVEPOINT -- define a new savepoint within the current transaction
11861190
Savepoint { name: Ident },
1191+
/// RELEASE -- release a previously defined savepoint
1192+
Release { name: Ident },
11871193
// MERGE INTO statement, based on Snowflake. See <https://docs.snowflake.com/en/sql-reference/sql/merge.html>
11881194
Merge {
11891195
// Specifies the table to merge
@@ -1956,8 +1962,17 @@ impl fmt::Display for Statement {
19561962
Statement::Commit { chain } => {
19571963
write!(f, "COMMIT{}", if *chain { " AND CHAIN" } else { "" },)
19581964
}
1959-
Statement::Rollback { chain } => {
1960-
write!(f, "ROLLBACK{}", if *chain { " AND CHAIN" } else { "" },)
1965+
Statement::Rollback { savepoint, chain } => {
1966+
write!(
1967+
f,
1968+
"ROLLBACK{}{}",
1969+
if let Some(savepoint) = savepoint {
1970+
format!(" TO {}", savepoint)
1971+
} else {
1972+
"".to_string()
1973+
},
1974+
if *chain { " AND CHAIN" } else { "" },
1975+
)
19611976
}
19621977
Statement::CreateSchema {
19631978
schema_name,
@@ -2049,6 +2064,10 @@ impl fmt::Display for Statement {
20492064
write!(f, "SAVEPOINT ")?;
20502065
write!(f, "{}", name)
20512066
}
2067+
Statement::Release { name } => {
2068+
write!(f, "RELEASE ")?;
2069+
write!(f, "{}", name)
2070+
}
20522071
Statement::Merge {
20532072
table,
20542073
source,

src/parser.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ impl<'a> Parser<'a> {
186186
// by at least PostgreSQL and MySQL.
187187
Keyword::BEGIN => Ok(self.parse_begin()?),
188188
Keyword::SAVEPOINT => Ok(self.parse_savepoint()?),
189+
Keyword::RELEASE => Ok(self.parse_release()?),
189190
Keyword::COMMIT => Ok(self.parse_commit()?),
190191
Keyword::ROLLBACK => Ok(self.parse_rollback()?),
191192
Keyword::ASSERT => Ok(self.parse_assert()?),
@@ -390,6 +391,12 @@ impl<'a> Parser<'a> {
390391
Ok(Statement::Savepoint { name })
391392
}
392393

394+
pub fn parse_release(&mut self) -> Result<Statement, ParserError> {
395+
let _ = self.parse_keyword(Keyword::SAVEPOINT);
396+
let name = self.parse_identifier()?;
397+
Ok(Statement::Release { name })
398+
}
399+
393400
/// Parse an expression prefix
394401
pub fn parse_prefix(&mut self) -> Result<Expr, ParserError> {
395402
// PostgreSQL allows any string literal to be preceded by a type name, indicating that the
@@ -4654,19 +4661,27 @@ impl<'a> Parser<'a> {
46544661
}
46554662

46564663
pub fn parse_commit(&mut self) -> Result<Statement, ParserError> {
4664+
let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]);
46574665
Ok(Statement::Commit {
46584666
chain: self.parse_commit_rollback_chain()?,
46594667
})
46604668
}
46614669

46624670
pub fn parse_rollback(&mut self) -> Result<Statement, ParserError> {
4671+
let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]);
4672+
let savepoint = if self.parse_keyword(Keyword::TO) {
4673+
let _ = self.parse_keyword(Keyword::SAVEPOINT);
4674+
Some(self.parse_identifier()?)
4675+
} else {
4676+
None
4677+
};
46634678
Ok(Statement::Rollback {
4679+
savepoint,
46644680
chain: self.parse_commit_rollback_chain()?,
46654681
})
46664682
}
46674683

46684684
pub fn parse_commit_rollback_chain(&mut self) -> Result<bool, ParserError> {
4669-
let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]);
46704685
if self.parse_keyword(Keyword::AND) {
46714686
let chain = !self.parse_keyword(Keyword::NO);
46724687
self.expect_keyword(Keyword::CHAIN)?;

tests/sqlparser_common.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4474,12 +4474,28 @@ fn parse_commit() {
44744474
#[test]
44754475
fn parse_rollback() {
44764476
match verified_stmt("ROLLBACK") {
4477-
Statement::Rollback { chain: false } => (),
4477+
Statement::Rollback {
4478+
savepoint: None,
4479+
chain: false,
4480+
} => (),
44784481
_ => unreachable!(),
44794482
}
44804483

44814484
match verified_stmt("ROLLBACK AND CHAIN") {
4482-
Statement::Rollback { chain: true } => (),
4485+
Statement::Rollback {
4486+
savepoint: None,
4487+
chain: true,
4488+
} => (),
4489+
_ => unreachable!(),
4490+
}
4491+
4492+
match verified_stmt("ROLLBACK TO foo") {
4493+
Statement::Rollback {
4494+
savepoint: Some(ident),
4495+
chain: false,
4496+
} => {
4497+
assert_eq!(ident.value, "foo")
4498+
}
44834499
_ => unreachable!(),
44844500
}
44854501

@@ -4490,6 +4506,11 @@ fn parse_rollback() {
44904506
one_statement_parses_to("ROLLBACK TRANSACTION AND CHAIN", "ROLLBACK AND CHAIN");
44914507
one_statement_parses_to("ROLLBACK WORK", "ROLLBACK");
44924508
one_statement_parses_to("ROLLBACK TRANSACTION", "ROLLBACK");
4509+
one_statement_parses_to("ROLLBACK WORK TO foo", "ROLLBACK TO foo");
4510+
one_statement_parses_to("ROLLBACK TRANSACTION TO foo", "ROLLBACK TO foo");
4511+
one_statement_parses_to("ROLLBACK TO SAVEPOINT foo", "ROLLBACK TO foo");
4512+
one_statement_parses_to("ROLLBACK WORK TO SAVEPOINT foo", "ROLLBACK TO foo");
4513+
one_statement_parses_to("ROLLBACK TRANSACTION TO SAVEPOINT foo", "ROLLBACK TO foo");
44934514
}
44944515

44954516
#[test]

tests/sqlparser_postgres.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,18 @@ fn test_savepoint() {
13621362
}
13631363
}
13641364

1365+
#[test]
1366+
fn test_release() {
1367+
match pg().verified_stmt("RELEASE test1") {
1368+
Statement::Release { name } => {
1369+
assert_eq!(Ident::new("test1"), name);
1370+
}
1371+
_ => unreachable!(),
1372+
}
1373+
1374+
pg_and_generic().one_statement_parses_to("RELEASE SAVEPOINT foo", "RELEASE foo");
1375+
}
1376+
13651377
#[test]
13661378
fn parse_comments() {
13671379
match pg().verified_stmt("COMMENT ON COLUMN tab.name IS 'comment'") {

0 commit comments

Comments
 (0)