mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +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>
|
/// See <https://learn.microsoft.com/en-us/sql/t-sql/statements/set-statements-transact-sql>
|
||||||
SetSessionParam(SetSessionParamKind),
|
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 {
|
impl fmt::Display for Statement {
|
||||||
|
@ -5026,6 +5058,24 @@ impl fmt::Display for Statement {
|
||||||
Statement::RenameTable(rename_tables) => {
|
Statement::RenameTable(rename_tables) => {
|
||||||
write!(f, "RENAME TABLE {}", display_comma_separated(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::List(command) => write!(f, "LIST {command}"),
|
||||||
Statement::Remove(command) => write!(f, "REMOVE {command}"),
|
Statement::Remove(command) => write!(f, "REMOVE {command}"),
|
||||||
Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),
|
Statement::SetSessionParam(kind) => write!(f, "SET {kind}"),
|
||||||
|
|
|
@ -495,6 +495,7 @@ impl Spanned for Statement {
|
||||||
Statement::LoadData { .. } => Span::empty(),
|
Statement::LoadData { .. } => Span::empty(),
|
||||||
Statement::UNLISTEN { .. } => Span::empty(),
|
Statement::UNLISTEN { .. } => Span::empty(),
|
||||||
Statement::RenameTable { .. } => Span::empty(),
|
Statement::RenameTable { .. } => Span::empty(),
|
||||||
|
Statement::RaisError { .. } => Span::empty(),
|
||||||
Statement::List(..) | Statement::Remove(..) => Span::empty(),
|
Statement::List(..) | Statement::Remove(..) => Span::empty(),
|
||||||
Statement::SetSessionParam { .. } => Span::empty(),
|
Statement::SetSessionParam { .. } => Span::empty(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -468,6 +468,7 @@ define_keywords!(
|
||||||
LOCATION,
|
LOCATION,
|
||||||
LOCK,
|
LOCK,
|
||||||
LOCKED,
|
LOCKED,
|
||||||
|
LOG,
|
||||||
LOGIN,
|
LOGIN,
|
||||||
LOGS,
|
LOGS,
|
||||||
LONGBLOB,
|
LONGBLOB,
|
||||||
|
@ -636,6 +637,7 @@ define_keywords!(
|
||||||
QUARTER,
|
QUARTER,
|
||||||
QUERY,
|
QUERY,
|
||||||
QUOTE,
|
QUOTE,
|
||||||
|
RAISERROR,
|
||||||
RANGE,
|
RANGE,
|
||||||
RANK,
|
RANK,
|
||||||
RAW,
|
RAW,
|
||||||
|
@ -728,6 +730,7 @@ define_keywords!(
|
||||||
SESSION,
|
SESSION,
|
||||||
SESSION_USER,
|
SESSION_USER,
|
||||||
SET,
|
SET,
|
||||||
|
SETERROR,
|
||||||
SETS,
|
SETS,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
SHARE,
|
SHARE,
|
||||||
|
|
|
@ -579,6 +579,7 @@ impl<'a> Parser<'a> {
|
||||||
Keyword::SAVEPOINT => self.parse_savepoint(),
|
Keyword::SAVEPOINT => self.parse_savepoint(),
|
||||||
Keyword::RELEASE => self.parse_release(),
|
Keyword::RELEASE => self.parse_release(),
|
||||||
Keyword::COMMIT => self.parse_commit(),
|
Keyword::COMMIT => self.parse_commit(),
|
||||||
|
Keyword::RAISERROR => Ok(self.parse_raiserror()?),
|
||||||
Keyword::ROLLBACK => self.parse_rollback(),
|
Keyword::ROLLBACK => self.parse_rollback(),
|
||||||
Keyword::ASSERT => self.parse_assert(),
|
Keyword::ASSERT => self.parse_assert(),
|
||||||
// `PREPARE`, `EXECUTE` and `DEALLOCATE` are Postgres-specific
|
// `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> {
|
pub fn parse_deallocate(&mut self) -> Result<Statement, ParserError> {
|
||||||
let prepare = self.parse_keyword(Keyword::PREPARE);
|
let prepare = self.parse_keyword(Keyword::PREPARE);
|
||||||
let name = self.parse_identifier()?;
|
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]
|
#[test]
|
||||||
fn parse_use() {
|
fn parse_use() {
|
||||||
let valid_object_names = [
|
let valid_object_names = [
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue