diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 62d4cc935..7c6f28ee3 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -956,6 +956,8 @@ pub enum Statement { /// A SQL query that specifies what to explain statement: Box, }, + /// SAVEPOINT -- define a new savepoint within the current transaction + Savepoint { name: Ident }, // MERGE INTO statement, based on Snowflake. See Merge { // Specifies the table to merge @@ -1619,6 +1621,10 @@ impl fmt::Display for Statement { write!(f, "NULL") } } + Statement::Savepoint { name } => { + write!(f, "SAVEPOINT ")?; + write!(f, "{}", name) + } Statement::Merge { table, source, diff --git a/src/parser.rs b/src/parser.rs index 187e24b05..3389ab8d1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -179,6 +179,7 @@ impl<'a> Parser<'a> { // standard `START TRANSACTION` statement. It is supported // by at least PostgreSQL and MySQL. Keyword::BEGIN => Ok(self.parse_begin()?), + Keyword::SAVEPOINT => Ok(self.parse_savepoint()?), Keyword::COMMIT => Ok(self.parse_commit()?), Keyword::ROLLBACK => Ok(self.parse_rollback()?), Keyword::ASSERT => Ok(self.parse_assert()?), @@ -367,6 +368,11 @@ impl<'a> Parser<'a> { Ok(Statement::Assert { condition, message }) } + pub fn parse_savepoint(&mut self) -> Result { + let name = self.parse_identifier()?; + Ok(Statement::Savepoint { name }) + } + /// Parse an expression prefix pub fn parse_prefix(&mut self) -> Result { // PostgreSQL allows any string literal to be preceded by a type name, indicating that the diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 750b49869..b0bda1438 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -871,6 +871,16 @@ fn test_transaction_statement() { ); } +#[test] +fn test_savepoint() { + match pg().verified_stmt("SAVEPOINT test1") { + Statement::Savepoint { name } => { + assert_eq!(Ident::new("test1"), name); + } + _ => unreachable!(), + } +} + #[test] fn parse_comments() { match pg().verified_stmt("COMMENT ON COLUMN tab.name IS 'comment'") {