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]

Reply via email to