You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/02/10 14:48:50 UTC
(datafusion-sqlparser-rs) branch gh-readonly-queue/main/pr-2202-75f6f4b17ae316694e877ce15ee81f692ba297a3 created (now 3a42e652)
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a change to branch gh-readonly-queue/main/pr-2202-75f6f4b17ae316694e877ce15ee81f692ba297a3
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
at 3a42e652 MSSQL: Support `THROW` statement (#2202)
This branch includes the following new commits:
new 3a42e652 MSSQL: Support `THROW` statement (#2202)
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org
(datafusion-sqlparser-rs) 01/01: MSSQL: Support `THROW` statement (#2202)
Posted by gi...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch gh-readonly-queue/main/pr-2202-75f6f4b17ae316694e877ce15ee81f692ba297a3
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 3a42e6527d9072d953dd01e2ba3e3fc91cc0063d
Author: Guan-Ming (Wesley) Chiu <10...@users.noreply.github.com>
AuthorDate: Tue Feb 10 22:48:27 2026 +0800
MSSQL: Support `THROW` statement (#2202)
Signed-off-by: Guan-Ming (Wesley) Chiu <10...@users.noreply.github.com>
Co-authored-by: Ifeanyi Ubah <78...@users.noreply.github.com>
---
src/ast/mod.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++
src/ast/spans.rs | 1 +
src/keywords.rs | 1 +
src/parser/mod.rs | 28 ++++++++++++++++++++++++++++
tests/sqlparser_mssql.rs | 37 +++++++++++++++++++++++++++++++++++++
5 files changed, 111 insertions(+)
diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 65568b77..601af1bd 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -2818,6 +2818,41 @@ impl fmt::Display for RaiseStatementValue {
}
}
+/// A MSSQL `THROW` statement.
+///
+/// ```sql
+/// THROW [ error_number, message, state ]
+/// ```
+///
+/// [MSSQL](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/throw-transact-sql)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct ThrowStatement {
+ /// Error number expression.
+ pub error_number: Option<Box<Expr>>,
+ /// Error message expression.
+ pub message: Option<Box<Expr>>,
+ /// State expression.
+ pub state: Option<Box<Expr>>,
+}
+
+impl fmt::Display for ThrowStatement {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let ThrowStatement {
+ error_number,
+ message,
+ state,
+ } = self;
+
+ write!(f, "THROW")?;
+ if let (Some(error_number), Some(message), Some(state)) = (error_number, message, state) {
+ write!(f, " {error_number}, {message}, {state}")?;
+ }
+ Ok(())
+ }
+}
+
/// Represents an expression assignment within a variable `DECLARE` statement.
///
/// Examples:
@@ -4700,6 +4735,8 @@ pub enum Statement {
/// Additional `WITH` options for RAISERROR.
options: Vec<RaisErrorOption>,
},
+ /// A MSSQL `THROW` statement.
+ Throw(ThrowStatement),
/// ```sql
/// PRINT msg_str | @local_variable | string_expr
/// ```
@@ -6157,6 +6194,7 @@ impl fmt::Display for Statement {
}
Ok(())
}
+ Statement::Throw(s) => write!(f, "{s}"),
Statement::Print(s) => write!(f, "{s}"),
Statement::Return(r) => write!(f, "{r}"),
Statement::List(command) => write!(f, "LIST {command}"),
@@ -11687,6 +11725,12 @@ impl From<RaiseStatement> for Statement {
}
}
+impl From<ThrowStatement> for Statement {
+ fn from(t: ThrowStatement) -> Self {
+ Self::Throw(t)
+ }
+}
+
impl From<Function> for Statement {
fn from(f: Function) -> Self {
Self::Call(f)
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 8354cea6..f4bdf85a 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -481,6 +481,7 @@ impl Spanned for Statement {
Statement::UNLISTEN { .. } => Span::empty(),
Statement::RenameTable { .. } => Span::empty(),
Statement::RaisError { .. } => Span::empty(),
+ Statement::Throw(_) => Span::empty(),
Statement::Print { .. } => Span::empty(),
Statement::Return { .. } => Span::empty(),
Statement::List(..) | Statement::Remove(..) => Span::empty(),
diff --git a/src/keywords.rs b/src/keywords.rs
index f84f4d21..7950b191 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -1029,6 +1029,7 @@ define_keywords!(
TEXT,
TEXTFILE,
THEN,
+ THROW,
TIES,
TIME,
TIMEFORMAT,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 2d702978..7a2bda8a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -670,6 +670,10 @@ impl<'a> Parser<'a> {
Keyword::RELEASE => self.parse_release(),
Keyword::COMMIT => self.parse_commit(),
Keyword::RAISERROR => Ok(self.parse_raiserror()?),
+ Keyword::THROW => {
+ self.prev_token();
+ self.parse_throw().map(Into::into)
+ }
Keyword::ROLLBACK => self.parse_rollback(),
Keyword::ASSERT => self.parse_assert(),
// `PREPARE`, `EXECUTE` and `DEALLOCATE` are Postgres-specific
@@ -18296,6 +18300,30 @@ impl<'a> Parser<'a> {
}
}
+ /// Parse a MSSQL `THROW` statement.
+ ///
+ /// See [Statement::Throw]
+ pub fn parse_throw(&mut self) -> Result<ThrowStatement, ParserError> {
+ self.expect_keyword_is(Keyword::THROW)?;
+
+ let error_number = self.maybe_parse(|p| p.parse_expr().map(Box::new))?;
+ let (message, state) = if error_number.is_some() {
+ self.expect_token(&Token::Comma)?;
+ let message = Box::new(self.parse_expr()?);
+ self.expect_token(&Token::Comma)?;
+ let state = Box::new(self.parse_expr()?);
+ (Some(message), Some(state))
+ } else {
+ (None, None)
+ };
+
+ Ok(ThrowStatement {
+ error_number,
+ message,
+ state,
+ })
+ }
+
/// Parse a SQL `DEALLOCATE` statement
pub fn parse_deallocate(&mut self) -> Result<Statement, ParserError> {
let prepare = self.parse_keyword(Keyword::PREPARE);
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index 84b8658b..82e6f462 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -1665,6 +1665,43 @@ fn test_parse_raiserror() {
let _ = ms().verified_stmt(sql);
}
+#[test]
+fn test_parse_throw() {
+ // THROW with arguments
+ let sql = r#"THROW 51000, 'Record does not exist.', 1"#;
+ let s = ms().verified_stmt(sql);
+ assert_eq!(
+ s,
+ Statement::Throw(ThrowStatement {
+ error_number: Some(Box::new(Expr::Value(
+ (Value::Number("51000".parse().unwrap(), false)).with_empty_span()
+ ))),
+ message: Some(Box::new(Expr::Value(
+ (Value::SingleQuotedString("Record does not exist.".to_string())).with_empty_span()
+ ))),
+ state: Some(Box::new(Expr::Value(
+ (Value::Number("1".parse().unwrap(), false)).with_empty_span()
+ ))),
+ })
+ );
+
+ // THROW with variable references
+ let sql = r#"THROW @ErrorNumber, @ErrorMessage, @ErrorState"#;
+ let _ = ms().verified_stmt(sql);
+
+ // Re-throw (no arguments)
+ let sql = r#"THROW"#;
+ let s = ms().verified_stmt(sql);
+ assert_eq!(
+ s,
+ Statement::Throw(ThrowStatement {
+ error_number: None,
+ message: None,
+ state: None,
+ })
+ );
+}
+
#[test]
fn parse_use() {
let valid_object_names = [
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org