From b557d173539968add5928fe21ff268c44f437c58 Mon Sep 17 00:00:00 2001 From: Dependabot Date: Fri, 17 Apr 2026 22:31:25 +0000 Subject: [PATCH 1/3] Merged PR 2053371: [SECURITY] Bump dotnet-sdk from 8.0.419 to 8.0.420 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index d65b2d5..6312649 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.419", + "version": "8.0.420", "rollForward": "latestMajor" }, "msbuild-sdks": { From 12d23beae859b7d582c321d75dc4855e05c511db Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Mon, 27 Apr 2026 14:59:23 +0000 Subject: [PATCH 2/3] Merged PR 2040726: Fix invalid OVER clause parsing - reject OVER([col]) syntax # Fix invalid OVER clause parsing - reject OVER([col]) syntax ## Summary Fixed a parser bug where invalid OVER clause syntax like `COUNT(*) OVER([col])` was incorrectly accepted. The parser now properly rejects OVER clauses that contain only an identifier in parentheses without PARTITION BY or ORDER BY clauses. ## Problem The parser was accepting invalid syntax such as: ```sql SELECT COUNT(*) OVER([col]) FROM t1 SELECT SUM(Amount) OVER(MyColumn) FROM t1 ``` This is invalid because an OVER clause with parentheses must contain one of: - `PARTITION BY` clause - `ORDER BY` clause - Window frame clause - Or be empty: `OVER()` Valid window name references (introduced in SQL Server 2022) must be written WITHOUT parentheses: ```sql SELECT SUM(c1) OVER Win1 FROM t1 WINDOW Win1 AS (PARTITION BY c1) ``` Additionally, partial window specifications CAN include a window name inside parentheses, but ONLY when combined with other clauses: ```sql SELECT SUM(c1) OVER (Win1 ORDER BY c2) FROM t1 WINDOW Win1 AS (PARTITION BY c1) ``` ## Root Cause In SQL Server 2022 (TSql160), support was added for the WINDOW clause feature, which allows referencing named windows. The grammar rule `overClauseBeginning` was modified to accept an optional identifier inside parentheses to support partial window specifications like `OVER (Win1 PARTITION BY ...)`. However, the rule `overClauseNoOrderBy` (used by aggregate functions like COUNT, SUM, AVG) was still using `overClauseBeginning`, which meant it would accept `OVER(identifier)` and interpret the identifier as a window name, even though no other clauses were present. This resulted in invalid syntax being accepted. ## Solution Created a new grammar rule `overClauseBeginningNoWindowName` that does not allow window name identifiers inside parentheses. Modified `overClauseNoOrderBy` to use this new rule instead of `overClauseBeginning`. The new rule uses explicit alternatives instead of an optional clause to ensure ANTLR properly rejects identifiers that aren't followed by the `BY` keyword: ```antlr overClauseBeginningNoWindowName: OVER LeftParenthesis ( Identifier { Match("PARTITION") } BY expressionList | /* empty - allow OVER() with no PARTITION BY */ ) ``` This ensures that when parsing `OVER([col])`, the parser will: 1. Try to match the PARTITION BY alternative 2. See the identifier but realize it's not followed by BY 3. Try the empty alternative 4. Fail because `[col]` is present when nothing was expected 5. Generate an error ## Files Modified - `SqlScriptDom/Parser/TSql/TSql160.g` - Added `overClauseBeginningNoWindowName` rule and updated `overClauseNoOrderBy` - `SqlScriptDom/Parser/TSql/TSql170.g` - Same changes as TSql160.g - `SqlScriptDom/Parser/TSql/TSql180.g` - Same changes as TSql180.g - `Test/SqlDom/ParserErrorsTests.cs` - Added `InvalidOverClauseNegative... --- SqlScriptDom/Parser/TSql/TSql160.g | 26 +++++++++++++- SqlScriptDom/Parser/TSql/TSql170.g | 26 +++++++++++++- SqlScriptDom/Parser/TSql/TSql180.g | 26 +++++++++++++- .../Baselines160/WindowClauseTests160.sql | 14 +++++++- Test/SqlDom/Only160SyntaxTests.cs | 2 +- Test/SqlDom/ParserErrorsTests.cs | 35 +++++++++++++++++++ .../TestScripts/WindowClauseTests160.sql | 10 ++++++ 7 files changed, 134 insertions(+), 5 deletions(-) diff --git a/SqlScriptDom/Parser/TSql/TSql160.g b/SqlScriptDom/Parser/TSql/TSql160.g index ed4fe5f..c45d6ff 100644 --- a/SqlScriptDom/Parser/TSql/TSql160.g +++ b/SqlScriptDom/Parser/TSql/TSql160.g @@ -31967,6 +31967,11 @@ overClause returns [OverClause vResult] )? tRParen:RightParenthesis { + // Window name inside parentheses requires at least one clause (PARTITION BY, ORDER BY, or window frame) + if (vResult.WindowName != null && vResult.Partitions.Count == 0 && vResult.OrderByClause == null && vResult.WindowFrameClause == null) + { + ThrowParseErrorException("SQL46010", tRParen, TSqlParserResource.SQL46010Message, vResult.WindowName.Value); + } UpdateTokenInfo(vResult,tRParen); } | vResult = overClauseWithWindow @@ -31989,7 +31994,7 @@ overClauseWithWindow returns [OverClause vResult = FragmentFactory.CreateFragmen overClauseNoOrderBy returns [OverClause vResult] : - vResult = overClauseBeginning + vResult = overClauseBeginningNoWindowName tRParen:RightParenthesis { UpdateTokenInfo(vResult,tRParen); @@ -32021,6 +32026,25 @@ overClauseBeginning returns [OverClause vResult = FragmentFactory.CreateFragment )? ; +overClauseBeginningNoWindowName returns [OverClause vResult = FragmentFactory.CreateFragment()] + : + tOver:Over + { + UpdateTokenInfo(vResult,tOver); + } + LeftParenthesis + ( + (Identifier By) => + tPartition:Identifier + { + Match(tPartition, CodeGenerationSupporter.Partition); + } + By expressionList[vResult, vResult.Partitions] + | + /* empty - allow OVER() with no PARTITION BY */ + ) + ; + windowFrameClause returns [WindowFrameClause vResult = FragmentFactory.CreateFragment()] : tRowsRange:Identifier diff --git a/SqlScriptDom/Parser/TSql/TSql170.g b/SqlScriptDom/Parser/TSql/TSql170.g index 28673c8..65bb5a9 100644 --- a/SqlScriptDom/Parser/TSql/TSql170.g +++ b/SqlScriptDom/Parser/TSql/TSql170.g @@ -32956,6 +32956,11 @@ overClause returns [OverClause vResult] )? tRParen:RightParenthesis { + // Window name inside parentheses requires at least one clause (PARTITION BY, ORDER BY, or window frame) + if (vResult.WindowName != null && vResult.Partitions.Count == 0 && vResult.OrderByClause == null && vResult.WindowFrameClause == null) + { + ThrowParseErrorException("SQL46010", tRParen, TSqlParserResource.SQL46010Message, vResult.WindowName.Value); + } UpdateTokenInfo(vResult,tRParen); } | vResult = overClauseWithWindow @@ -32978,7 +32983,7 @@ overClauseWithWindow returns [OverClause vResult = FragmentFactory.CreateFragmen overClauseNoOrderBy returns [OverClause vResult] : - vResult = overClauseBeginning + vResult = overClauseBeginningNoWindowName tRParen:RightParenthesis { UpdateTokenInfo(vResult,tRParen); @@ -33010,6 +33015,25 @@ overClauseBeginning returns [OverClause vResult = FragmentFactory.CreateFragment )? ; +overClauseBeginningNoWindowName returns [OverClause vResult = FragmentFactory.CreateFragment()] + : + tOver:Over + { + UpdateTokenInfo(vResult,tOver); + } + LeftParenthesis + ( + (Identifier By) => + tPartition:Identifier + { + Match(tPartition, CodeGenerationSupporter.Partition); + } + By expressionList[vResult, vResult.Partitions] + | + /* empty - allow OVER() with no PARTITION BY */ + ) + ; + windowFrameClause returns [WindowFrameClause vResult = FragmentFactory.CreateFragment()] : tRowsRange:Identifier diff --git a/SqlScriptDom/Parser/TSql/TSql180.g b/SqlScriptDom/Parser/TSql/TSql180.g index 59ed7b8..70ddca4 100644 --- a/SqlScriptDom/Parser/TSql/TSql180.g +++ b/SqlScriptDom/Parser/TSql/TSql180.g @@ -32956,6 +32956,11 @@ overClause returns [OverClause vResult] )? tRParen:RightParenthesis { + // Window name inside parentheses requires at least one clause (PARTITION BY, ORDER BY, or window frame) + if (vResult.WindowName != null && vResult.Partitions.Count == 0 && vResult.OrderByClause == null && vResult.WindowFrameClause == null) + { + ThrowParseErrorException("SQL46010", tRParen, TSqlParserResource.SQL46010Message, vResult.WindowName.Value); + } UpdateTokenInfo(vResult,tRParen); } | vResult = overClauseWithWindow @@ -32978,7 +32983,7 @@ overClauseWithWindow returns [OverClause vResult = FragmentFactory.CreateFragmen overClauseNoOrderBy returns [OverClause vResult] : - vResult = overClauseBeginning + vResult = overClauseBeginningNoWindowName tRParen:RightParenthesis { UpdateTokenInfo(vResult,tRParen); @@ -33010,6 +33015,25 @@ overClauseBeginning returns [OverClause vResult = FragmentFactory.CreateFragment )? ; +overClauseBeginningNoWindowName returns [OverClause vResult = FragmentFactory.CreateFragment()] + : + tOver:Over + { + UpdateTokenInfo(vResult,tOver); + } + LeftParenthesis + ( + (Identifier By) => + tPartition:Identifier + { + Match(tPartition, CodeGenerationSupporter.Partition); + } + By expressionList[vResult, vResult.Partitions] + | + /* empty - allow OVER() with no PARTITION BY */ + ) + ; + windowFrameClause returns [WindowFrameClause vResult = FragmentFactory.CreateFragment()] : tRowsRange:Identifier diff --git a/Test/SqlDom/Baselines160/WindowClauseTests160.sql b/Test/SqlDom/Baselines160/WindowClauseTests160.sql index 3c08bcf..20d9fee 100644 --- a/Test/SqlDom/Baselines160/WindowClauseTests160.sql +++ b/Test/SqlDom/Baselines160/WindowClauseTests160.sql @@ -103,4 +103,16 @@ SELECT Sum(t.c1) OVER Win1 FROM t1 AS t GROUP BY t.c1 WINDOW Win1 AS (PARTITION BY t.c1) -ORDER BY t.c1; \ No newline at end of file +ORDER BY t.c1; + + +GO +SELECT COUNT(*) OVER Win1 +FROM tb1 +WINDOW Win1 AS (PARTITION BY c1); + + +GO +SELECT COUNT(*) OVER (Win1 ORDER BY c1) +FROM tb1 +WINDOW Win1 AS (PARTITION BY c1); \ No newline at end of file diff --git a/Test/SqlDom/Only160SyntaxTests.cs b/Test/SqlDom/Only160SyntaxTests.cs index 966e51d..9feb868 100644 --- a/Test/SqlDom/Only160SyntaxTests.cs +++ b/Test/SqlDom/Only160SyntaxTests.cs @@ -20,7 +20,7 @@ public partial class SqlDomTests new ParserTest160("ExpressionTests160.sql", nErrors80: 1, nErrors90: 0, nErrors100: 0, nErrors110: 0, nErrors120: 0, nErrors130: 0, nErrors140: 0, nErrors150: 0), new ParserTest160("CreateUserFromExternalProvider160.sql", nErrors80: 2, nErrors90: 1, nErrors100: 1, nErrors110: 1, nErrors120: 1, nErrors130: 1, nErrors140: 1, nErrors150: 1), new ParserTest160("CreateExternalTableStatementTests160.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 2, nErrors140: 2, nErrors150: 2), - new ParserTest160("WindowClauseTests160.sql", nErrors80: 14, nErrors90: 13, nErrors100: 13, nErrors110: 13, nErrors120: 13, nErrors130: 13, nErrors140: 13, nErrors150: 13), + new ParserTest160("WindowClauseTests160.sql", nErrors80: 16, nErrors90: 15, nErrors100: 15, nErrors110: 15, nErrors120: 15, nErrors130: 15, nErrors140: 15, nErrors150: 15), new ParserTest160("CreateExternalDataSourceStatementTests160.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 0, nErrors140: 0, nErrors150: 0), new ParserTest160("CreateDatabaseTests160.sql", nErrors80: 4, nErrors90: 4, nErrors100: 4, nErrors110: 4, nErrors120: 4, nErrors130: 4, nErrors140: 4, nErrors150: 4), new ParserTest160("CreateLedgerTableTests160.sql", nErrors80: 14, nErrors90: 14, nErrors100: 14, nErrors110: 14, nErrors120: 14, nErrors130: 14, nErrors140: 14, nErrors150: 14), diff --git a/Test/SqlDom/ParserErrorsTests.cs b/Test/SqlDom/ParserErrorsTests.cs index 5c88f7c..ce5ab88 100644 --- a/Test/SqlDom/ParserErrorsTests.cs +++ b/Test/SqlDom/ParserErrorsTests.cs @@ -2156,6 +2156,41 @@ public void IgnoreOrRecpectNullsSyntaxNegativeTest() new ParserErrorInfo(41, "SQL46010", "NULLS")); } + /// + /// Negative tests for invalid OVER clause syntax. + /// Tests for issue: Invalid OVER clause parses successfully + /// OVER clause with just a column reference in parentheses should fail. + /// + [TestMethod] + [Priority(0)] + [SqlStudioTestCategory(Category.UnitTest)] + public void InvalidOverClauseNegativeTest() + { + // OVER clause with just an identifier in parentheses is invalid + // Valid syntax is either OVER identifier (window name reference without parens) + // or OVER (PARTITION BY ...) or OVER (ORDER BY ...) or OVER () + // The error occurs at the closing paren when no clauses follow the window name + // Note: Error message shows the identifier value without quotes + // + ParserTestUtils.ErrorTest160("SELECT COUNT(*) OVER([col]) FROM t1", + new ParserErrorInfo(26, "SQL46010", "col")); + ParserTestUtils.ErrorTest170("SELECT COUNT(*) OVER([col]) FROM t1", + new ParserErrorInfo(26, "SQL46010", "col")); + ParserTestUtils.ErrorTest180("SELECT COUNT(*) OVER([col]) FROM t1", + new ParserErrorInfo(26, "SQL46010", "col")); + + // Another variant with a regular identifier + ParserTestUtils.ErrorTest160("SELECT SUM(Amount) OVER(MyColumn) FROM t1", + new ParserErrorInfo(32, "SQL46010", "MyColumn")); + ParserTestUtils.ErrorTest170("SELECT SUM(Amount) OVER(MyColumn) FROM t1", + new ParserErrorInfo(32, "SQL46010", "MyColumn")); + + // This should also fail for aggregate functions + ParserTestUtils.ErrorTest160("SELECT AVG(Value) OVER(col1) FROM t1", + new ParserErrorInfo(27, "SQL46010", "col1")); + } + + /// /// Negative tests for IS [NOT] DISTINCT FROM syntax. /// diff --git a/Test/SqlDom/TestScripts/WindowClauseTests160.sql b/Test/SqlDom/TestScripts/WindowClauseTests160.sql index 51ca862..cc0fcff 100644 --- a/Test/SqlDom/TestScripts/WindowClauseTests160.sql +++ b/Test/SqlDom/TestScripts/WindowClauseTests160.sql @@ -77,4 +77,14 @@ SELECT Sum(t.c1) OVER Win1 FROM t1 t GROUP BY t.c1 WINDOW Win1 AS (PARTITION BY t.c1) ORDER BY t.c1 +GO + +-- checking COUNT(*) with WINDOW clause and window name reference (without parentheses) +SELECT COUNT(*) OVER Win1 FROM tb1 +WINDOW Win1 AS (PARTITION BY c1) +GO + +-- checking COUNT(*) with partial window specification (window name inside parentheses) +SELECT COUNT(*) OVER (Win1 ORDER BY c1) FROM tb1 +WINDOW Win1 AS (PARTITION BY c1) GO \ No newline at end of file From 27c82d6c7048213d7a536cbdec1bb34b94110d47 Mon Sep 17 00:00:00 2001 From: Leila Lali Date: Fri, 1 May 2026 19:06:31 +0000 Subject: [PATCH 3/3] Merged PR 2072841: Adding release notes for 180.18.1 Adding release notes for 180.18.1 ---- #### AI description (iteration 1) #### PR Classification Documentation update adding release notes for version 180.18.1 of Microsoft.SqlServer.TransactSql.ScriptDom. #### PR Summary This pull request adds comprehensive release notes for version 180.18.1, documenting bug fixes, dependency updates, and changes to the SQL script generator. - `/release-notes/180/180.18.1.md`: Documents platform support for .NET Framework 4.7.2, .NET 8, and .NET Standard 2.0+ - `/release-notes/180/180.18.1.md`: Lists five parser bug fixes including TRIM clause parsing, DATEADD/DATEDIFF/DATEPART function argument handling, and OVER clause validation - `/release-notes/180/180.18.1.md`: Notes .NET SDK update to version 8.0.420 and script generator improvement for semicolon placement before trailing comments --- release-notes/180/180.18.1.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 release-notes/180/180.18.1.md diff --git a/release-notes/180/180.18.1.md b/release-notes/180/180.18.1.md new file mode 100644 index 0000000..345bdba --- /dev/null +++ b/release-notes/180/180.18.1.md @@ -0,0 +1,31 @@ +# Release Notes + +## Microsoft.SqlServer.TransactSql.ScriptDom 180.18.1 +This update brings the following changes over the previous release: + +### Target Platform Support + +* .NET Framework 4.7.2 (Windows x86, Windows x64) +* .NET 8 (Windows x86, Windows x64, Linux, macOS) +* .NET Standard 2.0+ (Windows x86, Windows x64, Linux, macOS) + +### Dependencies +* Updates .NET SDK to latest patch version 8.0.420 + +#### .NET Framework +#### .NET Core + +### New Features + +### Fixed +* TRIM with FROM clause in RETURN statement fails to parse [#188](https://github.com/microsoft/SqlScriptDOM/issues/188) +* DATEADD/DATEDIFF/DATEPART/DATENAME first argument parsed as ColumnReferenceExpression instead of datepart keyword [#196](https://github.com/microsoft/SqlScriptDOM/issues/196) +* DAY used as argument for DATEADD() is interpreted as ColumnReferenceExpression [#124](https://github.com/microsoft/SqlScriptDOM/issues/124) +* TSql160Parser misidentifies interval parameter in DATEDIFF function as ColumnReferenceExpression [#98](https://github.com/microsoft/SqlScriptDOM/issues/98) +* Invalid OVER clause parses successfully [#195](https://github.com/microsoft/SqlScriptDOM/issues/195) + +### Changes +* Updates the Transact-SQL script generator to ensure that semicolons are correctly placed before any trailing comments + +### Known Issues +* None \ No newline at end of file