-
Notifications
You must be signed in to change notification settings - Fork 597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for MSSQL IF/ELSE statements. #1791
Conversation
These are syntactically quite different from the already supported IF ... THEN ... ELSEIF ... END IF statements. Hence IfStatement is now an enum with two variants and statement parsing is overridden for the MSSQL dialect in order to parse IF statements differently for MSSQL. Thereby fix spans for if/case AST nodes by including start/end tokens, if present.
src/ast/mod.rs
Outdated
/// ``` | ||
/// | ||
/// [MSSQL](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/if-else-transact-sql?view=sql-server-ver16) | ||
MsSqlIfElse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to merge the representation to be shared by both? Something like this roughly I'm thinking
enum StatementBlock {
Expr(Expr),
Statements(Vec<Statements>),
Begin(Vec<Statements>)
}
pub struct IfStatement {
pub condition: Expr,
pub if_block: StatementBlock,
pub elseif_blocks: Vec<StatementBlock>,
pub else_block: Option<StatementBlock>,
}
Ideally we avoid introducing dialect specific nodes in the AST
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your feedback. I pushed further changes to avoid the dialect-specific AST nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @romanb! Left a minor comment, otherwise this looks good to me!
src/ast/spans.rs
Outdated
has_end_case: _, | ||
case_token: AttachedToken(start), | ||
end_case_token: AttachedToken(end), | ||
.. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this and ConditionalStatement
Spanned impl could we explicitly list the remaining fields so that the let
match is exhaustive? So that we're forced to revisit this part of the code if new fields are added/modified
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, I did that! Thanks again for the review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great improvement! However, I noticed a difficulty with my code. This SQL fails to parse:
It works if you add a semi-colon for the declare statement, though. Either syntax executes as expected in SQL Server directly. What would it take to make it parse okay even without the semi-colon? |
To parse multiple top-level statements for MSSQL with optional semicolons, you can use the let mut stmts = Vec::new();
loop {
if let Token::EOF = parser.peek_token_ref().token {
break;
}
stmts.push(parser.parse_statement()?);
while let Token::SemiColon = parser.peek_token_ref().token {
parser.advance_token();
}
} I also did it similarly in this PR when parsing the statements within |
Interesting. Of course, I should have also shared my Rust code. I'm doing Also, I was trying to simplify the example SQL to a minimum reproducible example, but my original scenario is this kind of code inside of a SP. For example:
This also demonstrates the difficulty. I will adjust my Rust logic to the approach you suggested and see if I can make it work -- thank you! I still view this as a very surprising library behavior, though, especially since SQL Server itself accepts/parses/executes the identical file without issue. |
@aharpervc I see your difficulty. While working on this PR I did notice that a more general custom parsing for begin/end for the MSSQL dialect is probably necessary as well (e.g. by overriding If your example statement for the stored procedure does not parse, I would suggest to open an issue as a starting point. The problem of parsing multiple top-level statements with optional semicolons for MSSQL may also warrant another issue - I'm personally just sticking to the code I mentioned above to work around that problem for now, not least because even in SQL server, the use of semicolons is very much encouraged (quoting from the docs: Realistically though, I doubt the enforcement of semicolons will ever happen in SQL server and it is definitely desirable for this library to be fully capable of parsing with optional semicolons when using the MSSQL dialect out-of-the-box. I can only suggest to open new issues (or even PRs, if possible) for the remaining problems. |
Done: #1800 |
This PR is a follow-up to #1741. In particular, it addresses the parsing of IF/ELSE statements for MSSQL. These are syntactically quite different from the already supported IF ... THEN ... ELSEIF ... END IF statements, see the language reference.
The following are the main changes in this PR:
IfStatement
is now an enum with two variants.IF
statements differently for MSSQL.