Skip to content

Commit e3e8829

Browse files
authored
Add support for RAISE statement (#1766)
1 parent da58928 commit e3e8829

File tree

5 files changed

+124
-5
lines changed

5 files changed

+124
-5
lines changed

src/ast/mod.rs

+56
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,57 @@ impl fmt::Display for ConditionalStatements {
22562256
}
22572257
}
22582258

2259+
/// A `RAISE` statement.
2260+
///
2261+
/// Examples:
2262+
/// ```sql
2263+
/// RAISE USING MESSAGE = 'error';
2264+
///
2265+
/// RAISE myerror;
2266+
/// ```
2267+
///
2268+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#raise)
2269+
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/raise)
2270+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2271+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2272+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2273+
pub struct RaiseStatement {
2274+
pub value: Option<RaiseStatementValue>,
2275+
}
2276+
2277+
impl fmt::Display for RaiseStatement {
2278+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2279+
let RaiseStatement { value } = self;
2280+
2281+
write!(f, "RAISE")?;
2282+
if let Some(value) = value {
2283+
write!(f, " {value}")?;
2284+
}
2285+
2286+
Ok(())
2287+
}
2288+
}
2289+
2290+
/// Represents the error value of a [RaiseStatement].
2291+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2292+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2293+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2294+
pub enum RaiseStatementValue {
2295+
/// `RAISE USING MESSAGE = 'error'`
2296+
UsingMessage(Expr),
2297+
/// `RAISE myerror`
2298+
Expr(Expr),
2299+
}
2300+
2301+
impl fmt::Display for RaiseStatementValue {
2302+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2303+
match self {
2304+
RaiseStatementValue::Expr(expr) => write!(f, "{expr}"),
2305+
RaiseStatementValue::UsingMessage(expr) => write!(f, "USING MESSAGE = {expr}"),
2306+
}
2307+
}
2308+
}
2309+
22592310
/// Represents an expression assignment within a variable `DECLARE` statement.
22602311
///
22612312
/// Examples:
@@ -2827,6 +2878,8 @@ pub enum Statement {
28272878
Case(CaseStatement),
28282879
/// An `IF` statement.
28292880
If(IfStatement),
2881+
/// A `RAISE` statement.
2882+
Raise(RaiseStatement),
28302883
/// ```sql
28312884
/// CALL <function>
28322885
/// ```
@@ -4142,6 +4195,9 @@ impl fmt::Display for Statement {
41424195
Statement::If(stmt) => {
41434196
write!(f, "{stmt}")
41444197
}
4198+
Statement::Raise(stmt) => {
4199+
write!(f, "{stmt}")
4200+
}
41454201
Statement::AttachDatabase {
41464202
schema_name,
41474203
database_file_name,

src/ast/spans.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ use super::{
3232
JoinOperator, JsonPath, JsonPathElem, LateralView, LimitClause, MatchRecognizePattern, Measure,
3333
NamedWindowDefinition, ObjectName, ObjectNamePart, Offset, OnConflict, OnConflictAction,
3434
OnInsert, OrderBy, OrderByExpr, OrderByKind, Partition, PivotValueSource, ProjectionSelect,
35-
Query, ReferentialAction, RenameSelectItem, ReplaceSelectElement, ReplaceSelectItem, Select,
36-
SelectInto, SelectItem, SetExpr, SqlOption, Statement, Subscript, SymbolDefinition, TableAlias,
37-
TableAliasColumnDef, TableConstraint, TableFactor, TableObject, TableOptionsClustered,
38-
TableWithJoins, UpdateTableFromKind, Use, Value, Values, ViewColumnDef,
39-
WildcardAdditionalOptions, With, WithFill,
35+
Query, RaiseStatement, RaiseStatementValue, ReferentialAction, RenameSelectItem,
36+
ReplaceSelectElement, ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SqlOption,
37+
Statement, Subscript, SymbolDefinition, TableAlias, TableAliasColumnDef, TableConstraint,
38+
TableFactor, TableObject, TableOptionsClustered, TableWithJoins, UpdateTableFromKind, Use,
39+
Value, Values, ViewColumnDef, WildcardAdditionalOptions, With, WithFill,
4040
};
4141

4242
/// Given an iterator of spans, return the [Span::union] of all spans.
@@ -337,6 +337,7 @@ impl Spanned for Statement {
337337
} => source.span(),
338338
Statement::Case(stmt) => stmt.span(),
339339
Statement::If(stmt) => stmt.span(),
340+
Statement::Raise(stmt) => stmt.span(),
340341
Statement::Call(function) => function.span(),
341342
Statement::Copy {
342343
source,
@@ -782,6 +783,23 @@ impl Spanned for ConditionalStatements {
782783
}
783784
}
784785

786+
impl Spanned for RaiseStatement {
787+
fn span(&self) -> Span {
788+
let RaiseStatement { value } = self;
789+
790+
union_spans(value.iter().map(|value| value.span()))
791+
}
792+
}
793+
794+
impl Spanned for RaiseStatementValue {
795+
fn span(&self) -> Span {
796+
match self {
797+
RaiseStatementValue::UsingMessage(expr) => expr.span(),
798+
RaiseStatementValue::Expr(expr) => expr.span(),
799+
}
800+
}
801+
}
802+
785803
/// # partial span
786804
///
787805
/// Missing spans:

src/keywords.rs

+2
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ define_keywords!(
533533
MEDIUMTEXT,
534534
MEMBER,
535535
MERGE,
536+
MESSAGE,
536537
METADATA,
537538
METHOD,
538539
METRIC,
@@ -695,6 +696,7 @@ define_keywords!(
695696
QUARTER,
696697
QUERY,
697698
QUOTE,
699+
RAISE,
698700
RAISERROR,
699701
RANGE,
700702
RANK,

src/parser/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,10 @@ impl<'a> Parser<'a> {
536536
self.prev_token();
537537
self.parse_if_stmt()
538538
}
539+
Keyword::RAISE => {
540+
self.prev_token();
541+
self.parse_raise_stmt()
542+
}
539543
Keyword::SELECT | Keyword::WITH | Keyword::VALUES | Keyword::FROM => {
540544
self.prev_token();
541545
self.parse_query().map(Statement::Query)
@@ -719,6 +723,22 @@ impl<'a> Parser<'a> {
719723
})
720724
}
721725

726+
/// Parse a `RAISE` statement.
727+
///
728+
/// See [Statement::Raise]
729+
pub fn parse_raise_stmt(&mut self) -> Result<Statement, ParserError> {
730+
self.expect_keyword_is(Keyword::RAISE)?;
731+
732+
let value = if self.parse_keywords(&[Keyword::USING, Keyword::MESSAGE]) {
733+
self.expect_token(&Token::Eq)?;
734+
Some(RaiseStatementValue::UsingMessage(self.parse_expr()?))
735+
} else {
736+
self.maybe_parse(|parser| parser.parse_expr().map(RaiseStatementValue::Expr))?
737+
};
738+
739+
Ok(Statement::Raise(RaiseStatement { value }))
740+
}
741+
722742
pub fn parse_comment(&mut self) -> Result<Statement, ParserError> {
723743
let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);
724744

tests/sqlparser_common.rs

+23
Original file line numberDiff line numberDiff line change
@@ -14298,6 +14298,29 @@ fn parse_if_statement() {
1429814298
);
1429914299
}
1430014300

14301+
#[test]
14302+
fn parse_raise_statement() {
14303+
let sql = "RAISE USING MESSAGE = 42";
14304+
let Statement::Raise(stmt) = verified_stmt(sql) else {
14305+
unreachable!()
14306+
};
14307+
assert_eq!(
14308+
Some(RaiseStatementValue::UsingMessage(Expr::value(number("42")))),
14309+
stmt.value
14310+
);
14311+
14312+
verified_stmt("RAISE USING MESSAGE = 'error'");
14313+
verified_stmt("RAISE myerror");
14314+
verified_stmt("RAISE 42");
14315+
verified_stmt("RAISE using");
14316+
verified_stmt("RAISE");
14317+
14318+
assert_eq!(
14319+
ParserError::ParserError("Expected: =, found: error".to_string()),
14320+
parse_sql_statements("RAISE USING MESSAGE error").unwrap_err()
14321+
);
14322+
}
14323+
1430114324
#[test]
1430214325
fn test_lambdas() {
1430314326
let dialects = all_dialects_where(|d| d.supports_lambda_functions());

0 commit comments

Comments
 (0)