Skip to content

Commit 1ec4828

Browse files
AvivDavid-SatoriVedin
authored andcommitted
Add support for parsing RAISERROR (apache#1656)
1 parent 762789b commit 1ec4828

File tree

5 files changed

+128
-0
lines changed

5 files changed

+128
-0
lines changed

src/ast/mod.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3496,6 +3496,38 @@ pub enum Statement {
34963496
///
34973497
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
34983498
SetSessionParam(SetSessionParamKind),
3499+
/// RaiseError (MSSQL)
3500+
/// RAISERROR ( { msg_id | msg_str | @local_variable }
3501+
/// { , severity , state }
3502+
/// [ , argument [ , ...n ] ] )
3503+
/// [ WITH option [ , ...n ] ]
3504+
/// See <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/raiserror-transact-sql?view=sql-server-ver16>
3505+
RaisError {
3506+
message: Box<Expr>,
3507+
severity: Box<Expr>,
3508+
state: Box<Expr>,
3509+
arguments: Vec<Expr>,
3510+
options: Vec<RaisErrorOption>,
3511+
},
3512+
}
3513+
3514+
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3515+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3516+
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
3517+
pub enum RaisErrorOption {
3518+
Log,
3519+
NoWait,
3520+
SetError,
3521+
}
3522+
3523+
impl fmt::Display for RaisErrorOption {
3524+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3525+
match self {
3526+
RaisErrorOption::Log => write!(f, "LOG"),
3527+
RaisErrorOption::NoWait => write!(f, "NOWAIT"),
3528+
RaisErrorOption::SetError => write!(f, "SETERROR"),
3529+
}
3530+
}
34993531
}
35003532

35013533
impl fmt::Display for Statement {
@@ -5206,6 +5238,24 @@ impl fmt::Display for Statement {
52065238
Statement::RenameTable(rename_tables) => {
52075239
write!(f, "RENAME TABLE {}", display_comma_separated(rename_tables))
52085240
}
5241+
Statement::RaisError {
5242+
message,
5243+
severity,
5244+
state,
5245+
arguments,
5246+
options,
5247+
} => {
5248+
write!(f, "RAISERROR({message}, {severity}, {state}")?;
5249+
if !arguments.is_empty() {
5250+
write!(f, ", {}", display_comma_separated(arguments))?;
5251+
}
5252+
write!(f, ")")?;
5253+
if !options.is_empty() {
5254+
write!(f, " WITH {}", display_comma_separated(options))?;
5255+
}
5256+
Ok(())
5257+
}
5258+
52095259
Statement::List(command) => write!(f, "LIST {command}"),
52105260
Statement::Remove(command) => write!(f, "REMOVE {command}"),
52115261
Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ impl Spanned for Statement {
522522
Statement::LoadData { .. } => Span::empty(),
523523
Statement::UNLISTEN { .. } => Span::empty(),
524524
Statement::RenameTable { .. } => Span::empty(),
525+
Statement::RaisError { .. } => Span::empty(),
525526
Statement::List(..) | Statement::Remove(..) => Span::empty(),
526527
Statement::SetSessionParam { .. } => Span::empty(),
527528
}

src/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ define_keywords!(
473473
LOCATION,
474474
LOCK,
475475
LOCKED,
476+
LOG,
476477
LOGIN,
477478
LOGS,
478479
LONGBLOB,
@@ -643,6 +644,7 @@ define_keywords!(
643644
QUARTER,
644645
QUERY,
645646
QUOTE,
647+
RAISERROR,
646648
RANGE,
647649
RANK,
648650
RAW,
@@ -735,6 +737,7 @@ define_keywords!(
735737
SESSION,
736738
SESSION_USER,
737739
SET,
740+
SETERROR,
738741
SETS,
739742
SETTINGS,
740743
SHARE,

src/parser/mod.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ impl<'a> Parser<'a> {
579579
Keyword::SAVEPOINT => self.parse_savepoint(),
580580
Keyword::RELEASE => self.parse_release(),
581581
Keyword::COMMIT => self.parse_commit(),
582+
Keyword::RAISERROR => Ok(self.parse_raiserror()?),
582583
Keyword::ROLLBACK => self.parse_rollback(),
583584
Keyword::ASSERT => self.parse_assert(),
584585
// `PREPARE`, `EXECUTE` and `DEALLOCATE` are Postgres-specific
@@ -13150,6 +13151,46 @@ impl<'a> Parser<'a> {
1315013151
}
1315113152
}
1315213153

13154+
/// Parse a 'RAISERROR' statement
13155+
pub fn parse_raiserror(&mut self) -> Result<Statement, ParserError> {
13156+
self.expect_token(&Token::LParen)?;
13157+
let message = Box::new(self.parse_expr()?);
13158+
self.expect_token(&Token::Comma)?;
13159+
let severity = Box::new(self.parse_expr()?);
13160+
self.expect_token(&Token::Comma)?;
13161+
let state = Box::new(self.parse_expr()?);
13162+
let arguments = if self.consume_token(&Token::Comma) {
13163+
self.parse_comma_separated(Parser::parse_expr)?
13164+
} else {
13165+
vec![]
13166+
};
13167+
self.expect_token(&Token::RParen)?;
13168+
let options = if self.parse_keyword(Keyword::WITH) {
13169+
self.parse_comma_separated(Parser::parse_raiserror_option)?
13170+
} else {
13171+
vec![]
13172+
};
13173+
Ok(Statement::RaisError {
13174+
message,
13175+
severity,
13176+
state,
13177+
arguments,
13178+
options,
13179+
})
13180+
}
13181+
13182+
pub fn parse_raiserror_option(&mut self) -> Result<RaisErrorOption, ParserError> {
13183+
match self.expect_one_of_keywords(&[Keyword::LOG, Keyword::NOWAIT, Keyword::SETERROR])? {
13184+
Keyword::LOG => Ok(RaisErrorOption::Log),
13185+
Keyword::NOWAIT => Ok(RaisErrorOption::NoWait),
13186+
Keyword::SETERROR => Ok(RaisErrorOption::SetError),
13187+
_ => self.expected(
13188+
"LOG, NOWAIT OR SETERROR raiserror option",
13189+
self.peek_token(),
13190+
),
13191+
}
13192+
}
13193+
1315313194
pub fn parse_deallocate(&mut self) -> Result<Statement, ParserError> {
1315413195
let prepare = self.parse_keyword(Keyword::PREPARE);
1315513196
let name = self.parse_identifier()?;

tests/sqlparser_mssql.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,6 +1250,39 @@ fn parse_mssql_declare() {
12501250
);
12511251
}
12521252

1253+
#[test]
1254+
fn test_parse_raiserror() {
1255+
let sql = r#"RAISERROR('This is a test', 16, 1)"#;
1256+
let s = ms().verified_stmt(sql);
1257+
assert_eq!(
1258+
s,
1259+
Statement::RaisError {
1260+
message: Box::new(Expr::Value(Value::SingleQuotedString(
1261+
"This is a test".to_string()
1262+
))),
1263+
severity: Box::new(Expr::Value(Value::Number("16".parse().unwrap(), false))),
1264+
state: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
1265+
arguments: vec![],
1266+
options: vec![],
1267+
}
1268+
);
1269+
1270+
let sql = r#"RAISERROR('This is a test', 16, 1) WITH NOWAIT"#;
1271+
let _ = ms().verified_stmt(sql);
1272+
1273+
let sql = r#"RAISERROR('This is a test', 16, 1, 'ARG') WITH SETERROR, LOG"#;
1274+
let _ = ms().verified_stmt(sql);
1275+
1276+
let sql = r#"RAISERROR(N'This is message %s %d.', 10, 1, N'number', 5)"#;
1277+
let _ = ms().verified_stmt(sql);
1278+
1279+
let sql = r#"RAISERROR(N'<<%*.*s>>', 10, 1, 7, 3, N'abcde')"#;
1280+
let _ = ms().verified_stmt(sql);
1281+
1282+
let sql = r#"RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)"#;
1283+
let _ = ms().verified_stmt(sql);
1284+
}
1285+
12531286
#[test]
12541287
fn parse_use() {
12551288
let valid_object_names = [

0 commit comments

Comments
 (0)