This is an automated email from the ASF dual-hosted git repository.

iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new e3e88290 Add support for `RAISE` statement (#1766)
e3e88290 is described below

commit e3e88290cd44df48e9bde2e931985193218449fc
Author: Ifeanyi Ubah <[email protected]>
AuthorDate: Tue Mar 18 15:19:51 2025 +0100

    Add support for `RAISE` statement (#1766)
---
 src/ast/mod.rs            | 56 +++++++++++++++++++++++++++++++++++++++++++++++
 src/ast/spans.rs          | 28 +++++++++++++++++++-----
 src/keywords.rs           |  2 ++
 src/parser/mod.rs         | 20 +++++++++++++++++
 tests/sqlparser_common.rs | 23 +++++++++++++++++++
 5 files changed, 124 insertions(+), 5 deletions(-)

diff --git a/src/ast/mod.rs b/src/ast/mod.rs
index 69f2e57f..6dc4f5b2 100644
--- a/src/ast/mod.rs
+++ b/src/ast/mod.rs
@@ -2256,6 +2256,57 @@ impl fmt::Display for ConditionalStatements {
     }
 }
 
+/// A `RAISE` statement.
+///
+/// Examples:
+/// ```sql
+/// RAISE USING MESSAGE = 'error';
+///
+/// RAISE myerror;
+/// ```
+///
+/// 
[BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#raise)
+/// 
[Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/raise)
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub struct RaiseStatement {
+    pub value: Option<RaiseStatementValue>,
+}
+
+impl fmt::Display for RaiseStatement {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let RaiseStatement { value } = self;
+
+        write!(f, "RAISE")?;
+        if let Some(value) = value {
+            write!(f, " {value}")?;
+        }
+
+        Ok(())
+    }
+}
+
+/// Represents the error value of a [RaiseStatement].
+#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
+#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
+pub enum RaiseStatementValue {
+    /// `RAISE USING MESSAGE = 'error'`
+    UsingMessage(Expr),
+    /// `RAISE myerror`
+    Expr(Expr),
+}
+
+impl fmt::Display for RaiseStatementValue {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            RaiseStatementValue::Expr(expr) => write!(f, "{expr}"),
+            RaiseStatementValue::UsingMessage(expr) => write!(f, "USING 
MESSAGE = {expr}"),
+        }
+    }
+}
+
 /// Represents an expression assignment within a variable `DECLARE` statement.
 ///
 /// Examples:
@@ -2827,6 +2878,8 @@ pub enum Statement {
     Case(CaseStatement),
     /// An `IF` statement.
     If(IfStatement),
+    /// A `RAISE` statement.
+    Raise(RaiseStatement),
     /// ```sql
     /// CALL <function>
     /// ```
@@ -4142,6 +4195,9 @@ impl fmt::Display for Statement {
             Statement::If(stmt) => {
                 write!(f, "{stmt}")
             }
+            Statement::Raise(stmt) => {
+                write!(f, "{stmt}")
+            }
             Statement::AttachDatabase {
                 schema_name,
                 database_file_name,
diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 783248a7..65d43c10 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -32,11 +32,11 @@ use super::{
     JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause, 
MatchRecognizePattern, Measure,
     NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, 
OnConflictAction,
     OnInsert, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource, 
ProjectionSelect,
-    Query, ReferentialAction, RenameSelectItem, ReplaceSelectElement, 
ReplaceSelectItem, Select,
-    SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript, 
SymbolDefinition, TableAlias,
-    TableAliasColumnDef, TableConstraint, TableFactor, TableObject, 
TableOptionsClustered,
-    TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
-    WildcardAdditionalOptions, With, WithFill,
+    Query, RaiseStatement, RaiseStatementValue, ReferentialAction, 
RenameSelectItem,
+    ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, 
SetExpr, SqlOption,
+    Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, 
TableConstraint,
+    TableFactor, TableObject, TableOptionsClustered, TableWithJoins, 
UpdateTableFromKind, Use,
+    Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill,
 };
 
 /// Given an iterator of spans, return the [Span::union] of all spans.
@@ -337,6 +337,7 @@ impl Spanned for Statement {
             } => source.span(),
             Statement::Case(stmt) => stmt.span(),
             Statement::If(stmt) => stmt.span(),
+            Statement::Raise(stmt) => stmt.span(),
             Statement::Call(function) => function.span(),
             Statement::Copy {
                 source,
@@ -782,6 +783,23 @@ impl Spanned for ConditionalStatements {
     }
 }
 
+impl Spanned for RaiseStatement {
+    fn span(&self) -> Span {
+        let RaiseStatement { value } = self;
+
+        union_spans(value.iter().map(|value| value.span()))
+    }
+}
+
+impl Spanned for RaiseStatementValue {
+    fn span(&self) -> Span {
+        match self {
+            RaiseStatementValue::UsingMessage(expr) => expr.span(),
+            RaiseStatementValue::Expr(expr) => expr.span(),
+        }
+    }
+}
+
 /// # partial span
 ///
 /// Missing spans:
diff --git a/src/keywords.rs b/src/keywords.rs
index 974230f1..7b9c8bf2 100644
--- a/src/keywords.rs
+++ b/src/keywords.rs
@@ -533,6 +533,7 @@ define_keywords!(
     MEDIUMTEXT,
     MEMBER,
     MERGE,
+    MESSAGE,
     METADATA,
     METHOD,
     METRIC,
@@ -695,6 +696,7 @@ define_keywords!(
     QUARTER,
     QUERY,
     QUOTE,
+    RAISE,
     RAISERROR,
     RANGE,
     RANK,
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 0d8edc05..ee50cd04 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -536,6 +536,10 @@ impl<'a> Parser<'a> {
                     self.prev_token();
                     self.parse_if_stmt()
                 }
+                Keyword::RAISE => {
+                    self.prev_token();
+                    self.parse_raise_stmt()
+                }
                 Keyword::SELECT | Keyword::WITH | Keyword::VALUES | 
Keyword::FROM => {
                     self.prev_token();
                     self.parse_query().map(Statement::Query)
@@ -719,6 +723,22 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Parse a `RAISE` statement.
+    ///
+    /// See [Statement::Raise]
+    pub fn parse_raise_stmt(&mut self) -> Result<Statement, ParserError> {
+        self.expect_keyword_is(Keyword::RAISE)?;
+
+        let value = if self.parse_keywords(&[Keyword::USING, 
Keyword::MESSAGE]) {
+            self.expect_token(&Token::Eq)?;
+            Some(RaiseStatementValue::UsingMessage(self.parse_expr()?))
+        } else {
+            self.maybe_parse(|parser| 
parser.parse_expr().map(RaiseStatementValue::Expr))?
+        };
+
+        Ok(Statement::Raise(RaiseStatement { value }))
+    }
+
     pub fn parse_comment(&mut self) -> Result<Statement, ParserError> {
         let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
 
diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs
index c65cc6b5..c8df7cab 100644
--- a/tests/sqlparser_common.rs
+++ b/tests/sqlparser_common.rs
@@ -14298,6 +14298,29 @@ fn parse_if_statement() {
     );
 }
 
+#[test]
+fn parse_raise_statement() {
+    let sql = "RAISE USING MESSAGE = 42";
+    let Statement::Raise(stmt) = verified_stmt(sql) else {
+        unreachable!()
+    };
+    assert_eq!(
+        Some(RaiseStatementValue::UsingMessage(Expr::value(number("42")))),
+        stmt.value
+    );
+
+    verified_stmt("RAISE USING MESSAGE = 'error'");
+    verified_stmt("RAISE myerror");
+    verified_stmt("RAISE 42");
+    verified_stmt("RAISE using");
+    verified_stmt("RAISE");
+
+    assert_eq!(
+        ParserError::ParserError("Expected: =, found: error".to_string()),
+        parse_sql_statements("RAISE USING MESSAGE error").unwrap_err()
+    );
+}
+
 #[test]
 fn test_lambdas() {
     let dialects = all_dialects_where(|d| d.supports_lambda_functions());


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to