This is an automated email from the ASF dual-hosted git repository.
github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
The following commit(s) were added to refs/heads/main by this push:
new bd7f70e8 MSSQL: prevent statement-starting keywords from being
consumed as implicit aliases (#2233)
bd7f70e8 is described below
commit bd7f70e82048cab324dba6224fb3dd17757d8477
Author: Yoabot <[email protected]>
AuthorDate: Thu Feb 26 12:11:53 2026 +0100
MSSQL: prevent statement-starting keywords from being consumed as implicit
aliases (#2233)
---
src/dialect/mssql.rs | 56 +++++++++++++++++++++++++++++++++++++++++++-----
tests/sqlparser_mssql.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/src/dialect/mssql.rs b/src/dialect/mssql.rs
index 42e05858..8ad765dd 100644
--- a/src/dialect/mssql.rs
+++ b/src/dialect/mssql.rs
@@ -129,9 +129,30 @@ impl Dialect for MsSqlDialect {
fn is_select_item_alias(&self, explicit: bool, kw: &Keyword, parser: &mut
Parser) -> bool {
match kw {
- // List of keywords that cannot be used as select item aliases in
MSSQL
- // regardless of whether the alias is explicit or implicit
- Keyword::IF | Keyword::ELSE => false,
+ // List of keywords that cannot be used as select item (column)
aliases in MSSQL
+ // regardless of whether the alias is explicit or implicit.
+ //
+ // These are T-SQL statement-starting keywords; allowing them as
implicit aliases
+ // causes the parser to consume the keyword as an alias for the
previous expression,
+ // then fail on the token that follows (e.g. `TABLE`, `@var`,
`sp_name`, …).
+ Keyword::IF
+ | Keyword::ELSE
+ | Keyword::DECLARE
+ | Keyword::EXEC
+ | Keyword::EXECUTE
+ | Keyword::INSERT
+ | Keyword::UPDATE
+ | Keyword::DELETE
+ | Keyword::DROP
+ | Keyword::CREATE
+ | Keyword::ALTER
+ | Keyword::TRUNCATE
+ | Keyword::PRINT
+ | Keyword::WHILE
+ | Keyword::RETURN
+ | Keyword::THROW
+ | Keyword::RAISERROR
+ | Keyword::MERGE => false,
_ => explicit || self.is_column_alias(kw, parser),
}
}
@@ -139,8 +160,33 @@ impl Dialect for MsSqlDialect {
fn is_table_factor_alias(&self, explicit: bool, kw: &Keyword, parser: &mut
Parser) -> bool {
match kw {
// List of keywords that cannot be used as table aliases in MSSQL
- // regardless of whether the alias is explicit or implicit
- Keyword::IF | Keyword::ELSE => false,
+ // regardless of whether the alias is explicit or implicit.
+ //
+ // These are T-SQL statement-starting keywords. Without blocking
them here,
+ // a bare `SELECT * FROM t` followed by a newline and one of these
keywords
+ // would cause the parser to consume the keyword as a table alias
for `t`,
+ // then fail on the token that follows (e.g. `@var`, `sp_name`,
`TABLE`, …).
+ //
+ // `SET` is already covered by the global
`RESERVED_FOR_TABLE_ALIAS` list;
+ // the keywords below are MSSQL-specific additions.
+ Keyword::IF
+ | Keyword::ELSE
+ | Keyword::DECLARE
+ | Keyword::EXEC
+ | Keyword::EXECUTE
+ | Keyword::INSERT
+ | Keyword::UPDATE
+ | Keyword::DELETE
+ | Keyword::DROP
+ | Keyword::CREATE
+ | Keyword::ALTER
+ | Keyword::TRUNCATE
+ | Keyword::PRINT
+ | Keyword::WHILE
+ | Keyword::RETURN
+ | Keyword::THROW
+ | Keyword::RAISERROR
+ | Keyword::MERGE => false,
_ => explicit || self.is_table_alias(kw, parser),
}
}
diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs
index b5fd1e77..6c8412a4 100644
--- a/tests/sqlparser_mssql.rs
+++ b/tests/sqlparser_mssql.rs
@@ -2730,3 +2730,56 @@ fn parse_mssql_tran_shorthand() {
// ROLLBACK TRAN normalizes to ROLLBACK (same as ROLLBACK TRANSACTION)
ms().one_statement_parses_to("ROLLBACK TRAN", "ROLLBACK");
}
+
+#[test]
+fn test_tsql_statement_keywords_not_implicit_aliases() {
+ // T-SQL statement-starting keywords must never be consumed as implicit
+ // aliases for a preceding SELECT item or table reference when using
+ // newline-delimited multi-statement scripts.
+
+ // Without the fix, the parser would consume a statement-starting keyword
+ // as an implicit alias for the preceding SELECT item or table reference,
+ // then fail on the next token. Verify parsing succeeds and each input
+ // produces the expected number of statements.
+
+ // Keywords that should not become implicit column aliases
+ let col_alias_cases: &[(&str, usize)] = &[
+ ("select 1\ndeclare @x as int", 2),
+ ("select 1\nexec sp_who", 2),
+ ("select 1\ninsert into t values (1)", 2),
+ ("select 1\nupdate t set col=1", 2),
+ ("select 1\ndelete from t", 2),
+ ("select 1\ndrop table t", 2),
+ ("select 1\ncreate table t (id int)", 2),
+ ("select 1\nalter table t add col int", 2),
+ ("select 1\nreturn", 2),
+ ];
+ for (sql, expected) in col_alias_cases {
+ let stmts = tsql()
+ .parse_sql_statements(sql)
+ .unwrap_or_else(|e| panic!("failed to parse {sql:?}: {e}"));
+ assert_eq!(
+ stmts.len(),
+ *expected,
+ "expected {expected} stmts for: {sql:?}"
+ );
+ }
+
+ // Keywords that should not become implicit table aliases
+ let tbl_alias_cases: &[(&str, usize)] = &[
+ ("select * from t\ndeclare @x as int", 2),
+ ("select * from t\ndrop table t", 2),
+ ("select * from t\ncreate table u (id int)", 2),
+ ("select * from t\nexec sp_who", 2),
+ ];
+ for (sql, expected) in tbl_alias_cases {
+ let stmts = tsql()
+ .parse_sql_statements(sql)
+ .unwrap_or_else(|e| panic!("failed to parse {sql:?}: {e}"));
+ assert_eq!(
+ stmts.len(),
+ *expected,
+ "expected {expected} stmts for: {sql:?}"
+ );
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]