Skip to content

Commit 632ba4c

Browse files
authored
Fix the parsing error in MSSQL for multiple statements that include DECLARE statements (#1497)
1 parent 3a8369a commit 632ba4c

File tree

2 files changed

+119
-46
lines changed

2 files changed

+119
-46
lines changed

src/parser/mod.rs

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5321,55 +5321,61 @@ impl<'a> Parser<'a> {
53215321
/// ```
53225322
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/declare-local-variable-transact-sql?view=sql-server-ver16
53235323
pub fn parse_mssql_declare(&mut self) -> Result<Statement, ParserError> {
5324-
let mut stmts = vec![];
5325-
5326-
loop {
5327-
let name = {
5328-
let ident = self.parse_identifier(false)?;
5329-
if !ident.value.starts_with('@') {
5330-
Err(ParserError::TokenizerError(
5331-
"Invalid MsSql variable declaration.".to_string(),
5332-
))
5333-
} else {
5334-
Ok(ident)
5335-
}
5336-
}?;
5324+
let stmts = self.parse_comma_separated(Parser::parse_mssql_declare_stmt)?;
53375325

5338-
let (declare_type, data_type) = match self.peek_token().token {
5339-
Token::Word(w) => match w.keyword {
5340-
Keyword::CURSOR => {
5341-
self.next_token();
5342-
(Some(DeclareType::Cursor), None)
5343-
}
5344-
Keyword::AS => {
5345-
self.next_token();
5346-
(None, Some(self.parse_data_type()?))
5347-
}
5348-
_ => (None, Some(self.parse_data_type()?)),
5349-
},
5350-
_ => (None, Some(self.parse_data_type()?)),
5351-
};
5326+
Ok(Statement::Declare { stmts })
5327+
}
53525328

5353-
let assignment = self.parse_mssql_variable_declaration_expression()?;
5329+
/// Parse the body of a [MsSql] `DECLARE`statement.
5330+
///
5331+
/// Syntax:
5332+
/// ```text
5333+
// {
5334+
// { @local_variable [AS] data_type [ = value ] }
5335+
// | { @cursor_variable_name CURSOR }
5336+
// } [ ,...n ]
5337+
/// ```
5338+
/// [MsSql]: https://learn.microsoft.com/en-us/sql/t-sql/language-elements/declare-local-variable-transact-sql?view=sql-server-ver16
5339+
pub fn parse_mssql_declare_stmt(&mut self) -> Result<Declare, ParserError> {
5340+
let name = {
5341+
let ident = self.parse_identifier(false)?;
5342+
if !ident.value.starts_with('@') {
5343+
Err(ParserError::TokenizerError(
5344+
"Invalid MsSql variable declaration.".to_string(),
5345+
))
5346+
} else {
5347+
Ok(ident)
5348+
}
5349+
}?;
53545350

5355-
stmts.push(Declare {
5356-
names: vec![name],
5357-
data_type,
5358-
assignment,
5359-
declare_type,
5360-
binary: None,
5361-
sensitive: None,
5362-
scroll: None,
5363-
hold: None,
5364-
for_query: None,
5365-
});
5351+
let (declare_type, data_type) = match self.peek_token().token {
5352+
Token::Word(w) => match w.keyword {
5353+
Keyword::CURSOR => {
5354+
self.next_token();
5355+
(Some(DeclareType::Cursor), None)
5356+
}
5357+
Keyword::AS => {
5358+
self.next_token();
5359+
(None, Some(self.parse_data_type()?))
5360+
}
5361+
_ => (None, Some(self.parse_data_type()?)),
5362+
},
5363+
_ => (None, Some(self.parse_data_type()?)),
5364+
};
53665365

5367-
if self.next_token() != Token::Comma {
5368-
break;
5369-
}
5370-
}
5366+
let assignment = self.parse_mssql_variable_declaration_expression()?;
53715367

5372-
Ok(Statement::Declare { stmts })
5368+
Ok(Declare {
5369+
names: vec![name],
5370+
data_type,
5371+
assignment,
5372+
declare_type,
5373+
binary: None,
5374+
sensitive: None,
5375+
scroll: None,
5376+
hold: None,
5377+
for_query: None,
5378+
})
53735379
}
53745380

53755381
/// Parses the assigned expression in a variable declaration.

tests/sqlparser_mssql.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use sqlparser::ast::DeclareAssignment::MsSqlAssignment;
2929
use sqlparser::ast::Value::SingleQuotedString;
3030
use sqlparser::ast::*;
3131
use sqlparser::dialect::{GenericDialect, MsSqlDialect};
32-
use sqlparser::parser::{Parser, ParserError};
32+
use sqlparser::parser::ParserError;
3333

3434
#[test]
3535
fn parse_mssql_identifiers() {
@@ -910,7 +910,7 @@ fn parse_substring_in_select() {
910910
#[test]
911911
fn parse_mssql_declare() {
912912
let sql = "DECLARE @foo CURSOR, @bar INT, @baz AS TEXT = 'foobar';";
913-
let ast = Parser::parse_sql(&MsSqlDialect {}, sql).unwrap();
913+
let ast = ms().parse_sql_statements(sql).unwrap();
914914

915915
assert_eq!(
916916
vec![Statement::Declare {
@@ -963,6 +963,73 @@ fn parse_mssql_declare() {
963963
}],
964964
ast
965965
);
966+
967+
let sql = "DECLARE @bar INT;SET @bar = 2;SELECT @bar * 4";
968+
let ast = ms().parse_sql_statements(sql).unwrap();
969+
assert_eq!(
970+
vec![
971+
Statement::Declare {
972+
stmts: vec![Declare {
973+
names: vec![Ident {
974+
value: "@bar".to_string(),
975+
quote_style: None
976+
}],
977+
data_type: Some(Int(None)),
978+
assignment: None,
979+
declare_type: None,
980+
binary: None,
981+
sensitive: None,
982+
scroll: None,
983+
hold: None,
984+
for_query: None
985+
}]
986+
},
987+
Statement::SetVariable {
988+
local: false,
989+
hivevar: false,
990+
variables: OneOrManyWithParens::One(ObjectName(vec![Ident::new("@bar")])),
991+
value: vec![Expr::Value(Value::Number("2".parse().unwrap(), false))],
992+
},
993+
Statement::Query(Box::new(Query {
994+
with: None,
995+
limit: None,
996+
limit_by: vec![],
997+
offset: None,
998+
fetch: None,
999+
locks: vec![],
1000+
for_clause: None,
1001+
order_by: None,
1002+
settings: None,
1003+
format_clause: None,
1004+
body: Box::new(SetExpr::Select(Box::new(Select {
1005+
distinct: None,
1006+
top: None,
1007+
top_before_distinct: false,
1008+
projection: vec![SelectItem::UnnamedExpr(Expr::BinaryOp {
1009+
left: Box::new(Expr::Identifier(Ident::new("@bar"))),
1010+
op: BinaryOperator::Multiply,
1011+
right: Box::new(Expr::Value(Value::Number("4".parse().unwrap(), false))),
1012+
})],
1013+
into: None,
1014+
from: vec![],
1015+
lateral_views: vec![],
1016+
prewhere: None,
1017+
selection: None,
1018+
group_by: GroupByExpr::Expressions(vec![], vec![]),
1019+
cluster_by: vec![],
1020+
distribute_by: vec![],
1021+
sort_by: vec![],
1022+
having: None,
1023+
named_window: vec![],
1024+
window_before_qualify: false,
1025+
qualify: None,
1026+
value_table_mode: None,
1027+
connect_by: None,
1028+
})))
1029+
}))
1030+
],
1031+
ast
1032+
);
9661033
}
9671034

9681035
#[test]

0 commit comments

Comments
 (0)