Skip to content

Commit 7c3f6e0

Browse files
iffyioayman-sigma
authored andcommitted
Add support for RAISE statement (apache#1766)
1 parent 1654c63 commit 7c3f6e0

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
@@ -2274,6 +2274,57 @@ impl fmt::Display for ConditionalStatements {
22742274
}
22752275
}
22762276

2277+
/// A `RAISE` statement.
2278+
///
2279+
/// Examples:
2280+
/// ```sql
2281+
/// RAISE USING MESSAGE = 'error';
2282+
///
2283+
/// RAISE myerror;
2284+
/// ```
2285+
///
2286+
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/procedural-language#raise)
2287+
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/snowflake-scripting/raise)
2288+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2289+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2290+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2291+
pub struct RaiseStatement {
2292+
pub value: Option<RaiseStatementValue>,
2293+
}
2294+
2295+
impl fmt::Display for RaiseStatement {
2296+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2297+
let RaiseStatement { value } = self;
2298+
2299+
write!(f, "RAISE")?;
2300+
if let Some(value) = value {
2301+
write!(f, " {value}")?;
2302+
}
2303+
2304+
Ok(())
2305+
}
2306+
}
2307+
2308+
/// Represents the error value of a [RaiseStatement].
2309+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2310+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2311+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
2312+
pub enum RaiseStatementValue {
2313+
/// `RAISE USING MESSAGE = 'error'`
2314+
UsingMessage(Expr),
2315+
/// `RAISE myerror`
2316+
Expr(Expr),
2317+
}
2318+
2319+
impl fmt::Display for RaiseStatementValue {
2320+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2321+
match self {
2322+
RaiseStatementValue::Expr(expr) => write!(f, "{expr}"),
2323+
RaiseStatementValue::UsingMessage(expr) => write!(f, "USING MESSAGE = {expr}"),
2324+
}
2325+
}
2326+
}
2327+
22772328
/// Represents an expression assignment within a variable `DECLARE` statement.
22782329
///
22792330
/// Examples:
@@ -2845,6 +2896,8 @@ pub enum Statement {
28452896
Case(CaseStatement),
28462897
/// An `IF` statement.
28472898
If(IfStatement),
2899+
/// A `RAISE` statement.
2900+
Raise(RaiseStatement),
28482901
/// ```sql
28492902
/// CALL <function>
28502903
/// ```
@@ -4160,6 +4213,9 @@ impl fmt::Display for Statement {
41604213
Statement::If(stmt) => {
41614214
write!(f, "{stmt}")
41624215
}
4216+
Statement::Raise(stmt) => {
4217+
write!(f, "{stmt}")
4218+
}
41634219
Statement::AttachDatabase {
41644220
schema_name,
41654221
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
@@ -14301,6 +14301,29 @@ fn parse_if_statement() {
1430114301
);
1430214302
}
1430314303

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

0 commit comments

Comments
 (0)