mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-07-07 17:04:59 +00:00
Add support for parsing RAISERROR (#1656)
This commit is contained in:
parent
9105cae261
commit
474150006f
5 changed files with 128 additions and 0 deletions
|
@ -3441,6 +3441,38 @@ pub enum Statement {
|
|||
///
|
||||
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
|
||||
SetSessionParam(SetSessionParamKind),
|
||||
/// RaiseError (MSSQL)
|
||||
/// RAISERROR ( { msg_id | msg_str | @local_variable }
|
||||
/// { , severity , state }
|
||||
/// [ , argument [ , ...n ] ] )
|
||||
/// [ WITH option [ , ...n ] ]
|
||||
/// See <https://learn.microsoft.com/en-us/sql/t-sql/language-elements/raiserror-transact-sql?view=sql-server-ver16>
|
||||
RaisError {
|
||||
message: Box<Expr>,
|
||||
severity: Box<Expr>,
|
||||
state: Box<Expr>,
|
||||
arguments: Vec<Expr>,
|
||||
options: Vec<RaisErrorOption>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||
pub enum RaisErrorOption {
|
||||
Log,
|
||||
NoWait,
|
||||
SetError,
|
||||
}
|
||||
|
||||
impl fmt::Display for RaisErrorOption {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RaisErrorOption::Log => write!(f, "LOG"),
|
||||
RaisErrorOption::NoWait => write!(f, "NOWAIT"),
|
||||
RaisErrorOption::SetError => write!(f, "SETERROR"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Statement {
|
||||
|
@ -5026,6 +5058,24 @@ impl fmt::Display for Statement {
|
|||
Statement::RenameTable(rename_tables) => {
|
||||
write!(f, "RENAME TABLE {}", display_comma_separated(rename_tables))
|
||||
}
|
||||
Statement::RaisError {
|
||||
message,
|
||||
severity,
|
||||
state,
|
||||
arguments,
|
||||
options,
|
||||
} => {
|
||||
write!(f, "RAISERROR({message}, {severity}, {state}")?;
|
||||
if !arguments.is_empty() {
|
||||
write!(f, ", {}", display_comma_separated(arguments))?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
if !options.is_empty() {
|
||||
write!(f, " WITH {}", display_comma_separated(options))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Statement::List(command) => write!(f, "LIST {command}"),
|
||||
Statement::Remove(command) => write!(f, "REMOVE {command}"),
|
||||
Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),
|
||||
|
|
|
@ -495,6 +495,7 @@ impl Spanned for Statement {
|
|||
Statement::LoadData { .. } => Span::empty(),
|
||||
Statement::UNLISTEN { .. } => Span::empty(),
|
||||
Statement::RenameTable { .. } => Span::empty(),
|
||||
Statement::RaisError { .. } => Span::empty(),
|
||||
Statement::List(..) | Statement::Remove(..) => Span::empty(),
|
||||
Statement::SetSessionParam { .. } => Span::empty(),
|
||||
}
|
||||
|
|
|
@ -468,6 +468,7 @@ define_keywords!(
|
|||
LOCATION,
|
||||
LOCK,
|
||||
LOCKED,
|
||||
LOG,
|
||||
LOGIN,
|
||||
LOGS,
|
||||
LONGBLOB,
|
||||
|
@ -636,6 +637,7 @@ define_keywords!(
|
|||
QUARTER,
|
||||
QUERY,
|
||||
QUOTE,
|
||||
RAISERROR,
|
||||
RANGE,
|
||||
RANK,
|
||||
RAW,
|
||||
|
@ -728,6 +730,7 @@ define_keywords!(
|
|||
SESSION,
|
||||
SESSION_USER,
|
||||
SET,
|
||||
SETERROR,
|
||||
SETS,
|
||||
SETTINGS,
|
||||
SHARE,
|
||||
|
|
|
@ -579,6 +579,7 @@ impl<'a> Parser<'a> {
|
|||
Keyword::SAVEPOINT => self.parse_savepoint(),
|
||||
Keyword::RELEASE => self.parse_release(),
|
||||
Keyword::COMMIT => self.parse_commit(),
|
||||
Keyword::RAISERROR => Ok(self.parse_raiserror()?),
|
||||
Keyword::ROLLBACK => self.parse_rollback(),
|
||||
Keyword::ASSERT => self.parse_assert(),
|
||||
// `PREPARE`, `EXECUTE` and `DEALLOCATE` are Postgres-specific
|
||||
|
@ -13150,6 +13151,46 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parse a 'RAISERROR' statement
|
||||
pub fn parse_raiserror(&mut self) -> Result<Statement, ParserError> {
|
||||
self.expect_token(&Token::LParen)?;
|
||||
let message = Box::new(self.parse_expr()?);
|
||||
self.expect_token(&Token::Comma)?;
|
||||
let severity = Box::new(self.parse_expr()?);
|
||||
self.expect_token(&Token::Comma)?;
|
||||
let state = Box::new(self.parse_expr()?);
|
||||
let arguments = if self.consume_token(&Token::Comma) {
|
||||
self.parse_comma_separated(Parser::parse_expr)?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
self.expect_token(&Token::RParen)?;
|
||||
let options = if self.parse_keyword(Keyword::WITH) {
|
||||
self.parse_comma_separated(Parser::parse_raiserror_option)?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
Ok(Statement::RaisError {
|
||||
message,
|
||||
severity,
|
||||
state,
|
||||
arguments,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_raiserror_option(&mut self) -> Result<RaisErrorOption, ParserError> {
|
||||
match self.expect_one_of_keywords(&[Keyword::LOG, Keyword::NOWAIT, Keyword::SETERROR])? {
|
||||
Keyword::LOG => Ok(RaisErrorOption::Log),
|
||||
Keyword::NOWAIT => Ok(RaisErrorOption::NoWait),
|
||||
Keyword::SETERROR => Ok(RaisErrorOption::SetError),
|
||||
_ => self.expected(
|
||||
"LOG, NOWAIT OR SETERROR raiserror option",
|
||||
self.peek_token(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_deallocate(&mut self) -> Result<Statement, ParserError> {
|
||||
let prepare = self.parse_keyword(Keyword::PREPARE);
|
||||
let name = self.parse_identifier()?;
|
||||
|
|
|
@ -1250,6 +1250,39 @@ fn parse_mssql_declare() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_raiserror() {
|
||||
let sql = r#"RAISERROR('This is a test', 16, 1)"#;
|
||||
let s = ms().verified_stmt(sql);
|
||||
assert_eq!(
|
||||
s,
|
||||
Statement::RaisError {
|
||||
message: Box::new(Expr::Value(Value::SingleQuotedString(
|
||||
"This is a test".to_string()
|
||||
))),
|
||||
severity: Box::new(Expr::Value(Value::Number("16".parse().unwrap(), false))),
|
||||
state: Box::new(Expr::Value(Value::Number("1".parse().unwrap(), false))),
|
||||
arguments: vec![],
|
||||
options: vec![],
|
||||
}
|
||||
);
|
||||
|
||||
let sql = r#"RAISERROR('This is a test', 16, 1) WITH NOWAIT"#;
|
||||
let _ = ms().verified_stmt(sql);
|
||||
|
||||
let sql = r#"RAISERROR('This is a test', 16, 1, 'ARG') WITH SETERROR, LOG"#;
|
||||
let _ = ms().verified_stmt(sql);
|
||||
|
||||
let sql = r#"RAISERROR(N'This is message %s %d.', 10, 1, N'number', 5)"#;
|
||||
let _ = ms().verified_stmt(sql);
|
||||
|
||||
let sql = r#"RAISERROR(N'<<%*.*s>>', 10, 1, 7, 3, N'abcde')"#;
|
||||
let _ = ms().verified_stmt(sql);
|
||||
|
||||
let sql = r#"RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState)"#;
|
||||
let _ = ms().verified_stmt(sql);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_use() {
|
||||
let valid_object_names = [
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue