From 4520b0f426404999fd278c69f78f80adbf8c4af5 Mon Sep 17 00:00:00 2001 From: "Guan-Ming (Wesley) Chiu" <105915352+guan404ming@users.noreply.github.com> Date: Mon, 9 Feb 2026 12:39:49 +0800 Subject: [PATCH] MSSQL: Add support for TRAN shorthand Signed-off-by: Guan-Ming (Wesley) Chiu <105915352+guan404ming@users.noreply.github.com> --- src/ast/mod.rs | 6 +++++- src/dialect/mssql.rs | 8 ++++++-- src/keywords.rs | 1 + src/parser/mod.rs | 15 +++++++++------ tests/sqlparser_mssql.rs | 28 ++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 601af1bd5..a5d610b69 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -6369,7 +6369,7 @@ impl Display for CascadeOption { } } -/// Transaction started with [ TRANSACTION | WORK ] +/// Transaction started with [ TRANSACTION | WORK | TRAN ] #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "visitor", derive(Visit, VisitMut))] @@ -6378,6 +6378,9 @@ pub enum BeginTransactionKind { Transaction, /// Alternate `WORK` keyword. Work, + /// MSSQL shorthand `TRAN` keyword. + /// See + Tran, } impl Display for BeginTransactionKind { @@ -6385,6 +6388,7 @@ impl Display for BeginTransactionKind { match self { BeginTransactionKind::Transaction => write!(f, "TRANSACTION"), BeginTransactionKind::Work => write!(f, "WORK"), + BeginTransactionKind::Tran => write!(f, "TRAN"), } } } diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs index e763165d5..a2127f0da 100644 --- a/src/dialect/mssql.rs +++ b/src/dialect/mssql.rs @@ -151,8 +151,12 @@ impl Dialect for MsSqlDialect { let is_block = parser .maybe_parse(|p| { if p.parse_transaction_modifier().is_some() - || p.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]) - .is_some() + || p.parse_one_of_keywords(&[ + Keyword::TRANSACTION, + Keyword::WORK, + Keyword::TRAN, + ]) + .is_some() || matches!(p.peek_token_ref().token, Token::SemiColon | Token::EOF) { p.expected("statement", p.peek_token()) diff --git a/src/keywords.rs b/src/keywords.rs index 7950b1918..f1dbcd937 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -1051,6 +1051,7 @@ define_keywords!( TOTP, TRACE, TRAILING, + TRAN, TRANSACTION, TRANSIENT, TRANSLATE, diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 7a2bda8ac..dcd8925b4 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -18099,11 +18099,14 @@ impl<'a> Parser<'a> { /// Parse a 'BEGIN' statement pub fn parse_begin(&mut self) -> Result { let modifier = self.parse_transaction_modifier(); - let transaction = match self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]) { - Some(Keyword::TRANSACTION) => Some(BeginTransactionKind::Transaction), - Some(Keyword::WORK) => Some(BeginTransactionKind::Work), - _ => None, - }; + let transaction = + match self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK, Keyword::TRAN]) + { + Some(Keyword::TRANSACTION) => Some(BeginTransactionKind::Transaction), + Some(Keyword::WORK) => Some(BeginTransactionKind::Work), + Some(Keyword::TRAN) => Some(BeginTransactionKind::Tran), + _ => None, + }; Ok(Statement::StartTransaction { modes: self.parse_transaction_modes()?, begin: true, @@ -18237,7 +18240,7 @@ impl<'a> Parser<'a> { /// Parse an optional `AND [NO] CHAIN` clause for `COMMIT` and `ROLLBACK` statements pub fn parse_commit_rollback_chain(&mut self) -> Result { - let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK]); + let _ = self.parse_one_of_keywords(&[Keyword::TRANSACTION, Keyword::WORK, Keyword::TRAN]); if self.parse_keyword(Keyword::AND) { let chain = !self.parse_keyword(Keyword::NO); self.expect_keyword_is(Keyword::CHAIN)?; diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 82e6f4621..cf9ae8980 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -2665,3 +2665,31 @@ fn parse_mssql_begin_end_block() { _ => panic!("Expected StartTransaction, got: {stmt:?}"), } } + +/// MSSQL supports `TRAN` as shorthand for `TRANSACTION`. +/// See +#[test] +fn parse_mssql_tran_shorthand() { + // BEGIN TRAN + let sql = "BEGIN TRAN"; + let stmt = ms().verified_stmt(sql); + match &stmt { + Statement::StartTransaction { + begin, + transaction, + has_end_keyword, + .. + } => { + assert!(begin); + assert_eq!(*transaction, Some(BeginTransactionKind::Tran)); + assert!(!has_end_keyword); + } + _ => panic!("Expected StartTransaction, got: {stmt:?}"), + } + + // COMMIT TRAN normalizes to COMMIT (same as COMMIT TRANSACTION) + ms().one_statement_parses_to("COMMIT TRAN", "COMMIT"); + + // ROLLBACK TRAN normalizes to ROLLBACK (same as ROLLBACK TRANSACTION) + ms().one_statement_parses_to("ROLLBACK TRAN", "ROLLBACK"); +}