From 7e2e560de3287fe0c77614af151cc40d8374872f Mon Sep 17 00:00:00 2001 From: Shiv Prashant Sood Date: Tue, 12 Aug 2025 00:46:38 +0000 Subject: [PATCH 1/8] Merged PR 1756293: [MSJSON] json_arrayagg support for scriptdom ## Description This pull request introduces full support for the JSON_ARRAYAGG function in ScriptDom by extending the T-SQL grammar and code generation, along with updated test cases to validate the new functionality. Json_ArrayAgg with options NULL ON NULL/ABSENT ON NULL and RETURNING JSON are supported. Added relevant test for all options. ## Code Change - [ ] The [Common checklist](https://msdata.visualstudio.com/SQLToolsAndLibraries/_git/Common?path=/Templates/PR%20Checklist%20for%20SQLToolsAndLibraries.md&version=GBmain&_a=preview) has been reviewed and followed - [x] Code changes are accompanied by appropriate unit tests - [x] Identified and included SMEs needed to review code changes - [x] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=make-the-changes-in) here to make changes in the code ## Testing - [x] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=to-extend-the-tests-do-the-following%3A) here to add new tests for your feature ## Additional Information - **`TSql170.g`**: Added a new grammar rule (`jsonArrayAggBuiltInFunctionCall`) and integrated it into the built-in function call productions. - **`SqlScriptGeneratorVisitor.FunctionCall.cs`**: Implemented code generation logic for JSON_ARRAYAGG. - **`CodeGenerationSupporter.cs`**: Defined a new constant for JSON_ARRAYAGG. - **Test updates**: Expanded test scripts and adjusted expected error counts in `JsonFunctionTests170.sql` and `Only170SyntaxTests.cs` to cover JSON_ARRAYAGG scenarios. Related work items: #4519570 --- .../Parser/TSql/CodeGenerationSupporter.cs | 1 + SqlScriptDom/Parser/TSql/TSql170.g | 29 +++++++++++++++++++ .../SqlScriptGeneratorVisitor.FunctionCall.cs | 11 +++++++ .../Baselines170/JsonFunctionTests170.sql | 24 ++++++++++++++- Test/SqlDom/Only170SyntaxTests.cs | 3 +- Test/SqlDom/ParserErrorsTests.cs | 29 +++++++++++++++++++ .../TestScripts/JsonFunctionTests170.sql | 23 +++++++++++++++ 7 files changed, 117 insertions(+), 3 deletions(-) diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs index 1106636..3fde5de 100644 --- a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs +++ b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs @@ -523,6 +523,7 @@ internal static class CodeGenerationSupporter internal const string JsonArray = "JSON_ARRAY"; internal const string JsonObject = "JSON_OBJECT"; internal const string JsonObjectAgg = "JSON_OBJECTAGG"; + internal const string JsonArrayAgg = "JSON_ARRAYAGG"; internal const string Keep = "KEEP"; internal const string KeepDefaults = "KEEPDEFAULTS"; internal const string KeepFixed = "KEEPFIXED"; diff --git a/SqlScriptDom/Parser/TSql/TSql170.g b/SqlScriptDom/Parser/TSql/TSql170.g index a8f9bf2..86d46ee 100644 --- a/SqlScriptDom/Parser/TSql/TSql170.g +++ b/SqlScriptDom/Parser/TSql/TSql170.g @@ -32785,6 +32785,9 @@ builtInFunctionCall returns [FunctionCall vResult = FragmentFactory.CreateFragme | {(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonObjectAgg)}? jsonObjectAggBuiltInFunctionCall[vResult] + | + {(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArrayAgg)}? + jsonArrayAggBuiltInFunctionCall[vResult] | {(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.Trim) && (NextTokenMatches(CodeGenerationSupporter.Leading) | NextTokenMatches(CodeGenerationSupporter.Trailing) | NextTokenMatches(CodeGenerationSupporter.Both))}? @@ -32829,6 +32832,32 @@ jsonArrayBuiltInFunctionCall [FunctionCall vParent] } ; +jsonArrayAggBuiltInFunctionCall [FunctionCall vParent] +{ + ScalarExpression vExpression; +} + : ( + vExpression=expression + { + AddAndUpdateTokenInfo(vParent, vParent.Parameters, vExpression); + } + ) + ( + jsonNullClauseFunction[vParent] + | + /* empty */ + ) + ( + jsonReturningClause[vParent] + | + /* empty */ + ) + tRParen:RightParenthesis + { + UpdateTokenInfo(vParent, tRParen); + } + ; + jsonObjectBuiltInFunctionCall [FunctionCall vParent] { } diff --git a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.FunctionCall.cs b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.FunctionCall.cs index f4e50f9..0daaff0 100644 --- a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.FunctionCall.cs +++ b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.FunctionCall.cs @@ -72,6 +72,17 @@ public override void ExplicitVisit(FunctionCall node) GenerateSymbol(TSqlTokenType.RightParenthesis); } else if (node.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArray) + { + GenerateCommaSeparatedList(node.Parameters); + if (node.Parameters?.Count > 0 && node?.AbsentOrNullOnNull?.Count > 0) //If there are values and null on null or absent on null present then generate space in between them + GenerateSpace(); + GenerateNullOnNullOrAbsentOnNull(node?.AbsentOrNullOnNull); + if (node.ReturnType?.Count > 0) //If there are values and null on null or absent on null present then generate space in between them + GenerateSpace(); + GenerateReturnType(node?.ReturnType); + GenerateSymbol(TSqlTokenType.RightParenthesis); + } + else if (node.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArrayAgg) { GenerateCommaSeparatedList(node.Parameters); if (node.Parameters?.Count > 0 && node?.AbsentOrNullOnNull?.Count > 0) //If there are values and null on null or absent on null present then generate space in between them diff --git a/Test/SqlDom/Baselines170/JsonFunctionTests170.sql b/Test/SqlDom/Baselines170/JsonFunctionTests170.sql index 29adc38..67461dd 100644 --- a/Test/SqlDom/Baselines170/JsonFunctionTests170.sql +++ b/Test/SqlDom/Baselines170/JsonFunctionTests170.sql @@ -98,4 +98,26 @@ SELECT JSON_OBJECTAGG('name':'b' NULL ON NULL RETURNING JSON); SELECT JSON_OBJECTAGG('name':'b' ABSENT ON NULL RETURNING JSON); SELECT JSON_OBJECTAGG('name':'b' RETURNING JSON); - + +SELECT JSON_ARRAYAGG('name'); + +SELECT JSON_ARRAYAGG('a'); + +SELECT JSON_ARRAYAGG('a' NULL ON NULL); + +SELECT JSON_ARRAYAGG('a' NULL ON NULL RETURNING JSON); + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name NULL ON NULL) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name NULL ON NULL RETURNING JSON) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; diff --git a/Test/SqlDom/Only170SyntaxTests.cs b/Test/SqlDom/Only170SyntaxTests.cs index a339cf7..40dae01 100644 --- a/Test/SqlDom/Only170SyntaxTests.cs +++ b/Test/SqlDom/Only170SyntaxTests.cs @@ -16,14 +16,13 @@ public partial class SqlDomTests new ParserTest170("CreateColumnStoreIndexTests170.sql", nErrors80: 3, nErrors90: 3, nErrors100: 3, nErrors110: 3, nErrors120: 3, nErrors130: 0, nErrors140: 0, nErrors150: 0, nErrors160: 0), new ParserTest170("RegexpTests170.sql", nErrors80: 0, nErrors90: 0, nErrors100: 0, nErrors110: 0, nErrors120: 0, nErrors130: 0, nErrors140: 0, nErrors150: 0, nErrors160: 0), new ParserTest170("AiGenerateChunksTests170.sql", nErrors80: 21, nErrors90: 18, nErrors100: 17, nErrors110: 17, nErrors120: 17, nErrors130: 17, nErrors140: 17, nErrors150: 17, nErrors160: 17), - new ParserTest170("JsonFunctionTests170.sql", nErrors80: 9, nErrors90: 8, nErrors100: 30, nErrors110: 30, nErrors120: 30, nErrors130: 30, nErrors140: 30, nErrors150: 30, nErrors160: 30), + new ParserTest170("JsonFunctionTests170.sql", nErrors80: 9, nErrors90: 8, nErrors100: 34, nErrors110: 34, nErrors120: 34, nErrors130: 34, nErrors140: 34, nErrors150: 34, nErrors160: 34), new ParserTest170("AiGenerateEmbeddingsTests170.sql", nErrors80: 12, nErrors90: 9, nErrors100: 9, nErrors110: 9, nErrors120: 9, nErrors130: 9, nErrors140: 9, nErrors150: 9, nErrors160: 9), new ParserTest170("CreateExternalModelStatementTests170.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 4, nErrors140: 4, nErrors150: 4, nErrors160: 4), new ParserTest170("AlterExternalModelStatementTests170.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 5, nErrors140: 5, nErrors150: 5, nErrors160: 5), new ParserTest170("DropExternalModelStatementTests170.sql", nErrors80: 1, nErrors90: 1, nErrors100: 1, nErrors110: 1, nErrors120: 1, nErrors130: 1, nErrors140: 1, nErrors150: 1, nErrors160: 1), new ParserTest170("VectorFunctionTests170.sql", nErrors80: 1, nErrors90: 1, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 2, nErrors140: 2, nErrors150: 2, nErrors160: 2), new ParserTest170("SecurityStatementExternalModelTests170.sql", nErrors80: 2, nErrors90: 17, nErrors100: 17, nErrors110: 17, nErrors120: 17, nErrors130: 17, nErrors140: 17, nErrors150: 17, nErrors160: 17), - }; private static readonly ParserTest[] SqlAzure170_TestInfos = diff --git a/Test/SqlDom/ParserErrorsTests.cs b/Test/SqlDom/ParserErrorsTests.cs index 6a46317..5327db8 100644 --- a/Test/SqlDom/ParserErrorsTests.cs +++ b/Test/SqlDom/ParserErrorsTests.cs @@ -548,6 +548,35 @@ public void JsonObjectAGGSyntaxNegativeTest() new ParserErrorInfo(44, "SQL46005", "JSON", "INT")); } + /// + /// Negative tests for JSON_ARRAYAGG syntax in functions + /// + [TestMethod] + [Priority(0)] + [SqlStudioTestCategory(Category.UnitTest)] + public void JsonArrayAggSyntaxNegativeTest() + { + // Incorrect placing of colon + ParserTestUtils.ErrorTest160("SELECT JSON_ARRAYAGG('name':'value')", + new ParserErrorInfo(27, "SQL46010", ":")); + + // Incorrect placing of single quotes + ParserTestUtils.ErrorTest160("SELECT JSON_ARRAYAGG('name)", + new ParserErrorInfo(21, "SQL46030", "'name)")); + + // Cannot use incomplete absent on null clause cases + ParserTestUtils.ErrorTest160("SELECT JSON_ARRAYAGG('name', NULL ABSENT ON)", + new ParserErrorInfo(34, "SQL46010", "ABSENT")); + + // one params only + ParserTestUtils.ErrorTest160("SELECT JSON_ARRAYAGG('name', 'value', NULL ON NULL)", + new ParserErrorInfo(43, "SQL46010", "ON")); + + // Cannot use null on null incorrectly + ParserTestUtils.ErrorTest160("SELECT JSON_ARRAYAGG('name', NULL NULL ON)", + new ParserErrorInfo(34, "SQL46010", "NULL")); + } + /// /// Negative tests for Data Masking Alter Column syntax. /// diff --git a/Test/SqlDom/TestScripts/JsonFunctionTests170.sql b/Test/SqlDom/TestScripts/JsonFunctionTests170.sql index d15a477..12eda11 100644 --- a/Test/SqlDom/TestScripts/JsonFunctionTests170.sql +++ b/Test/SqlDom/TestScripts/JsonFunctionTests170.sql @@ -96,3 +96,26 @@ SELECT JSON_OBJECTAGG('name':'b' NULL ON NULL RETURNING JSON); SELECT JSON_OBJECTAGG('name':'b' ABSENT ON NULL RETURNING JSON); SELECT JSON_OBJECTAGG('name':'b' RETURNING JSON); + +SELECT JSON_ARRAYAGG('name'); + +SELECT JSON_ARRAYAGG('a'); + +SELECT JSON_ARRAYAGG('a' NULL ON NULL); + +SELECT JSON_ARRAYAGG('a' NULL ON NULL RETURNING JSON); + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name NULL ON NULL) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; + +SELECT s.session_id, + JSON_ARRAYAGG(s.host_name NULL ON NULL RETURNING JSON) +FROM sys.dm_exec_sessions AS s +WHERE s.is_user_process = 1; From 310b92bb8e17b6c313ca5b7e3029eb03d3df8755 Mon Sep 17 00:00:00 2001 From: Sai Avishkar Sreerama Date: Wed, 20 Aug 2025 19:31:17 +0000 Subject: [PATCH 2/8] Merged PR 1777076: Adding missing event CREATE_JSON_INDEX # Pull Request Template for ScriptDom ## Description Adding missing JSON index event to the event type enum. Before submitting your pull request, please ensure you have completed the following: ## Code Change - [ ] The [Common checklist](https://msdata.visualstudio.com/SQLToolsAndLibraries/_git/Common?path=/Templates/PR%20Checklist%20for%20SQLToolsAndLibraries.md&version=GBmain&_a=preview) has been reviewed and followed - [ ] Code changes are accompanied by appropriate unit tests - [ ] Identified and included SMEs needed to review code changes - [ ] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=make-the-changes-in) here to make changes in the code ## Testing - [ ] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=to-extend-the-tests-do-the-following%3A) here to add new tests for your feature ## Documentation - [ ] Update relevant documentation in the [wiki](https://dev.azure.com/msdata/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki) and the README.md file ## Additional Information Please provide any additional information that might be helpful for the reviewers Adding missing event CREATE_JSON_INDEX ---- #### AI description (iteration 1) #### PR Classification This PR introduces a new feature by adding a missing event type to the codebase. #### PR Summary The pull request adds the `CreateJsonIndex` event to the `EventNotificationEventType.cs` file with an enum value of 343, ensuring support for the CREATE_JSON_INDEX event. - `SqlScriptDom/Parser/TSql/EventNotificationEventType.cs`: Added the `CreateJsonIndex` enum member along with its documentation. --- SqlScriptDom/Parser/TSql/EventNotificationEventType.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SqlScriptDom/Parser/TSql/EventNotificationEventType.cs b/SqlScriptDom/Parser/TSql/EventNotificationEventType.cs index 6edc4f8..221ef2e 100644 --- a/SqlScriptDom/Parser/TSql/EventNotificationEventType.cs +++ b/SqlScriptDom/Parser/TSql/EventNotificationEventType.cs @@ -1091,6 +1091,11 @@ public enum EventNotificationEventType /// DropExternalLanguage = 331, + /// + /// CREATE_JSON_INDEX + /// + CreateJsonIndex = 343, + /// /// CREATE_VECTOR_INDEX /// From 3c901d69ffe3a0ee7d4a29cedc6f257790a65024 Mon Sep 17 00:00:00 2001 From: C Shanmukha Reddy Date: Wed, 27 Aug 2025 21:36:48 +0000 Subject: [PATCH 3/8] Merged PR 1781082: Adding regexp_like syntax Please provide a detailed description, include the link to the design specification or SQL feature document for the new TSQL syntaxes. Make sure to add links to the Github or DevDiv issue Regexp_like function works as a boolean expression similar to LIKE, MATCH starting from compat level 170. Before submitting your pull request, please ensure you have completed the following: - [ ] The [Common checklist](https://msdata.visualstudio.com/SQLToolsAndLibraries/_git/Common?path=/Templates/PR%20Checklist%20for%20SQLToolsAndLibraries.md&version=GBmain&_a=preview) has been reviewed and followed - [x] Code changes are accompanied by appropriate unit tests - [ ] Identified and included SMEs needed to review code changes - [ ] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=make-the-changes-in) here to make changes in the code - [x] Follow the [steps](https://msdata.visualstudio.com/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki/33838/Adding-or-Extending-TSql-support-in-Sql-Dom?anchor=to-extend-the-tests-do-the-following%3A) here to add new tests for your feature - [ ] Update relevant documentation in the [wiki](https://dev.azure.com/msdata/SQLToolsAndLibraries/_wiki/wikis/SQLToolsAndLibraries.wiki) and the README.md file Please provide any additional information that might be helpful for the reviewers Adding regexp_like syntax ---- This pull request implements a new feature by adding support for the REGEXP_LIKE predicate syntax in SQL. The pull request introduces complete support for the REGEXP_LIKE predicate by updating the script generator, grammar, AST, and tests. - `SqlScriptGeneratorVisitor.RegexpLikePredicate.cs`: Added a new visitor method for generating the REGEXP_LIKE SQL syntax. - `TSql170.g`: Extended the T-SQL grammar to include a new rule for REGEXP_LIKE with an optional flags parameter. - `Ast.xml`: Defined a new `RegexpLikePredicate` AST node with members for text, pattern, and optional flags. - `CodeGenerationSupporter.cs`: Added a new constant for REGEXP_LIKE token generation. - Test files in `/Test/SqlDom/Baselines170/RegexpLikeTests170.sql`, `/Test/SqlDom/TestScripts/RegexpLikeTests170.sql`, and updated entry in `Only170SyntaxTests.cs`: Provided extensive test cases validating various REGEXP_LIKE scenarios. Related work items: #4005966 --- SqlScriptDom/Parser/TSql/Ast.xml | 5 +++ .../Parser/TSql/CodeGenerationSupporter.cs | 1 + SqlScriptDom/Parser/TSql/TSql170.g | 26 ++++++++++++++ ...iptGeneratorVisitor.RegexpLikePredicate.cs | 35 +++++++++++++++++++ .../Baselines170/RegexpLikeTests170.sql | 33 +++++++++++++++++ Test/SqlDom/Only170SyntaxTests.cs | 1 + .../SqlDom/TestScripts/RegexpLikeTests170.sql | 33 +++++++++++++++++ 7 files changed, 134 insertions(+) create mode 100644 SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.RegexpLikePredicate.cs create mode 100644 Test/SqlDom/Baselines170/RegexpLikeTests170.sql create mode 100644 Test/SqlDom/TestScripts/RegexpLikeTests170.sql diff --git a/SqlScriptDom/Parser/TSql/Ast.xml b/SqlScriptDom/Parser/TSql/Ast.xml index 842a787..905f414 100644 --- a/SqlScriptDom/Parser/TSql/Ast.xml +++ b/SqlScriptDom/Parser/TSql/Ast.xml @@ -349,6 +349,11 @@ + + + + + diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs index 3fde5de..acb3acb 100644 --- a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs +++ b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs @@ -820,6 +820,7 @@ internal static class CodeGenerationSupporter internal const string RecursiveTriggers = "RECURSIVE_TRIGGERS"; internal const string Recovery = "RECOVERY"; internal const string Regenerate = "REGENERATE"; + internal const string RegexpLike = "REGEXP_LIKE"; internal const string RegexpMatches = "REGEXP_MATCHES"; internal const string RegexpSplitToTable = "REGEXP_SPLIT_TO_TABLE"; internal const string RejectType = "REJECT_TYPE"; diff --git a/SqlScriptDom/Parser/TSql/TSql170.g b/SqlScriptDom/Parser/TSql/TSql170.g index 86d46ee..c3ed8b7 100644 --- a/SqlScriptDom/Parser/TSql/TSql170.g +++ b/SqlScriptDom/Parser/TSql/TSql170.g @@ -31094,6 +31094,9 @@ booleanExpressionPrimary [ExpressionFlags expressionFlags] returns [BooleanExpre vResult = vMatchPredicate; UpdateTokenInfo(vResult,tRParen); } + | + {NextTokenMatches(CodeGenerationSupporter.RegexpLike)}? + vResult=regexpLikePredicate | vExpressionFirst=expressionWithFlags[expressionFlags] ( @@ -31475,6 +31478,29 @@ tsEqualCall returns [TSEqualCall vResult = this.FragmentFactory.CreateFragment()] +{ + ScalarExpression vText; + ScalarExpression vPattern; + ScalarExpression vFlags = null; +} + : tRegexp:Identifier LeftParenthesis vText=expression Comma vPattern=expression + { + UpdateTokenInfo(vResult,tRegexp); + vResult.Text = vText; + vResult.Pattern = vPattern; + } + (Comma vFlags=expression + )? + { + vResult.Flags = vFlags; + } + tRParen:RightParenthesis + { + UpdateTokenInfo(vResult,tRParen); + } + ; + updateCall returns [UpdateCall vResult = this.FragmentFactory.CreateFragment()] { Identifier vIdentifier; diff --git a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.RegexpLikePredicate.cs b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.RegexpLikePredicate.cs new file mode 100644 index 0000000..5ecb0e9 --- /dev/null +++ b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.RegexpLikePredicate.cs @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +//------------------------------------------------------------------------------ +using System; +using Microsoft.SqlServer.TransactSql.ScriptDom; + +namespace Microsoft.SqlServer.TransactSql.ScriptDom.ScriptGenerator +{ + internal partial class SqlScriptGeneratorVisitor + { + public override void ExplicitVisit(RegexpLikePredicate node) + { + GenerateIdentifier(CodeGenerationSupporter.RegexpLike); + + GenerateSpace(); + GenerateSymbol(TSqlTokenType.LeftParenthesis); + + GenerateFragmentIfNotNull(node.Text); + GenerateSymbol(TSqlTokenType.Comma); + GenerateSpace(); + GenerateFragmentIfNotNull(node.Pattern); + + if (node.Flags != null) + { + GenerateSymbol(TSqlTokenType.Comma); + GenerateSpace(); + GenerateFragmentIfNotNull(node.Flags); + } + + GenerateSymbol(TSqlTokenType.RightParenthesis); + } + } +} diff --git a/Test/SqlDom/Baselines170/RegexpLikeTests170.sql b/Test/SqlDom/Baselines170/RegexpLikeTests170.sql new file mode 100644 index 0000000..2faab93 --- /dev/null +++ b/Test/SqlDom/Baselines170/RegexpLikeTests170.sql @@ -0,0 +1,33 @@ +SELECT 1 +WHERE REGEXP_LIKE ('abc', '^a'); + +SELECT 1 +WHERE NOT REGEXP_LIKE ('abc', '^b'); + +SELECT IIF (REGEXP_LIKE ('abc', '^a'), 1, 0) AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', '^a'), 1, 0) AS is_match; + +SELECT CASE WHEN REGEXP_LIKE ('abc', '^a') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a') THEN 1 ELSE 0 END AS is_match; + +SELECT 1 +WHERE REGEXP_LIKE ('abc', '^a', 'i'); + +SELECT 1 +WHERE NOT REGEXP_LIKE ('abc', '^b', 'i'); + +SELECT IIF (REGEXP_LIKE ('abc', '^a', 'i'), 1, 0) AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', '^a', 'i'), 1, 0) AS is_match; + +SELECT CASE WHEN REGEXP_LIKE ('abc', '^a', 'i') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a', 'i') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a', NULL) THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN REGEXP_LIKE (NULL, '^a', 'c') THEN 1 ELSE 0 END AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', NULL), 1, 0) AS is_match; \ No newline at end of file diff --git a/Test/SqlDom/Only170SyntaxTests.cs b/Test/SqlDom/Only170SyntaxTests.cs index 40dae01..f477acc 100644 --- a/Test/SqlDom/Only170SyntaxTests.cs +++ b/Test/SqlDom/Only170SyntaxTests.cs @@ -23,6 +23,7 @@ public partial class SqlDomTests new ParserTest170("DropExternalModelStatementTests170.sql", nErrors80: 1, nErrors90: 1, nErrors100: 1, nErrors110: 1, nErrors120: 1, nErrors130: 1, nErrors140: 1, nErrors150: 1, nErrors160: 1), new ParserTest170("VectorFunctionTests170.sql", nErrors80: 1, nErrors90: 1, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 2, nErrors140: 2, nErrors150: 2, nErrors160: 2), new ParserTest170("SecurityStatementExternalModelTests170.sql", nErrors80: 2, nErrors90: 17, nErrors100: 17, nErrors110: 17, nErrors120: 17, nErrors130: 17, nErrors140: 17, nErrors150: 17, nErrors160: 17), + new ParserTest170("RegexpLikeTests170.sql", nErrors80: 13, nErrors90: 13, nErrors100: 13, nErrors110: 15, nErrors120: 15, nErrors130: 15, nErrors140: 15, nErrors150: 15, nErrors160: 15) }; private static readonly ParserTest[] SqlAzure170_TestInfos = diff --git a/Test/SqlDom/TestScripts/RegexpLikeTests170.sql b/Test/SqlDom/TestScripts/RegexpLikeTests170.sql new file mode 100644 index 0000000..2faab93 --- /dev/null +++ b/Test/SqlDom/TestScripts/RegexpLikeTests170.sql @@ -0,0 +1,33 @@ +SELECT 1 +WHERE REGEXP_LIKE ('abc', '^a'); + +SELECT 1 +WHERE NOT REGEXP_LIKE ('abc', '^b'); + +SELECT IIF (REGEXP_LIKE ('abc', '^a'), 1, 0) AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', '^a'), 1, 0) AS is_match; + +SELECT CASE WHEN REGEXP_LIKE ('abc', '^a') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a') THEN 1 ELSE 0 END AS is_match; + +SELECT 1 +WHERE REGEXP_LIKE ('abc', '^a', 'i'); + +SELECT 1 +WHERE NOT REGEXP_LIKE ('abc', '^b', 'i'); + +SELECT IIF (REGEXP_LIKE ('abc', '^a', 'i'), 1, 0) AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', '^a', 'i'), 1, 0) AS is_match; + +SELECT CASE WHEN REGEXP_LIKE ('abc', '^a', 'i') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a', 'i') THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN NOT REGEXP_LIKE ('abc', '^a', NULL) THEN 1 ELSE 0 END AS is_match; + +SELECT CASE WHEN REGEXP_LIKE (NULL, '^a', 'c') THEN 1 ELSE 0 END AS is_match; + +SELECT IIF (NOT REGEXP_LIKE ('abc', NULL), 1, 0) AS is_match; \ No newline at end of file From 04968bd1232ced0d7246a78747c5d147b0ac91c3 Mon Sep 17 00:00:00 2001 From: Dhruv Relwani Date: Thu, 28 Aug 2025 18:12:15 +0000 Subject: [PATCH 4/8] Merged PR 1762947: Nested CTE Implementation - Fabric DW In this PR we modify the Fabric DW Grammar to support Nested Common Table Expressions with the following syntax: ``` WITH [ (column_name , ...) ] AS (WITH [ (column_name , ...) ] AS ( ... WITH [ ( column_name , ...) ] AS ( WITH [ ( column_name , ...) ] AS ( Standard_CTE_query_definition ) -- Data source must include NESTED_CTE_NAME_LEVELn-1 ... )