diff --git a/SqlScriptDom/Parser/TSql/Ast.xml b/SqlScriptDom/Parser/TSql/Ast.xml
index 842a787..9a1d8b5 100644
--- a/SqlScriptDom/Parser/TSql/Ast.xml
+++ b/SqlScriptDom/Parser/TSql/Ast.xml
@@ -236,6 +236,7 @@
+
@@ -349,6 +350,11 @@
+
+
+
+
+
diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs
index 1106636..acb3acb 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";
@@ -819,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/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
///
diff --git a/SqlScriptDom/Parser/TSql/TSql160.g b/SqlScriptDom/Parser/TSql/TSql160.g
index 913e2a0..d870760 100644
--- a/SqlScriptDom/Parser/TSql/TSql160.g
+++ b/SqlScriptDom/Parser/TSql/TSql160.g
@@ -31846,15 +31846,31 @@ jsonKeyValueExpression returns [JsonKeyValue vResult = FragmentFactory.CreateFra
:
(
vKey=expression
- {
- vResult.JsonKeyName=vKey;
- }
+ {
+ vResult.JsonKeyName=vKey;
+ }
Colon vValue=expression
- {
- vResult.JsonValue=vValue;
+ {
+ vResult.JsonValue=vValue;
}
- )
- ;
+
+ |
+
+ label:Label
+ {
+ var identifier = this.FragmentFactory.CreateFragment();
+ var multiPartIdentifier = this.FragmentFactory.CreateFragment();
+ var columnRef = this.FragmentFactory.CreateFragment();
+ CreateIdentifierFromLabel(label, identifier, multiPartIdentifier);
+ columnRef.MultiPartIdentifier = multiPartIdentifier;
+ vResult.JsonKeyName=columnRef;
+ }
+ vValue=expression
+ {
+ vResult.JsonValue=vValue;
+ }
+ )
+ ;
windowClause returns [WindowClause vResult = FragmentFactory.CreateFragment()]
{
diff --git a/SqlScriptDom/Parser/TSql/TSql170.g b/SqlScriptDom/Parser/TSql/TSql170.g
index a8f9bf2..8ba896b 100644
--- a/SqlScriptDom/Parser/TSql/TSql170.g
+++ b/SqlScriptDom/Parser/TSql/TSql170.g
@@ -19238,7 +19238,10 @@ aiGenerateFixedChunksTableReference [ScalarExpression vSource, Identifier vChunk
Match(vEnableChunkSetIdParam, CodeGenerationSupporter.EnableChunkSetId);
}
EqualsSign
- vEnableChunkSetId = expression
+ (
+ vEnableChunkSetId = integer // constant integer
+ | vEnableChunkSetId = nullLiteral // NULL literal
+ )
{
vResult.EnableChunkSetId = vEnableChunkSetId;
}
@@ -31094,6 +31097,9 @@ booleanExpressionPrimary [ExpressionFlags expressionFlags] returns [BooleanExpre
vResult = vMatchPredicate;
UpdateTokenInfo(vResult,tRParen);
}
+ |
+ {NextTokenMatches(CodeGenerationSupporter.RegexpLike)}?
+ vResult=regexpLikePredicate
|
vExpressionFirst=expressionWithFlags[expressionFlags]
(
@@ -31475,6 +31481,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;
@@ -32502,6 +32531,22 @@ jsonKeyValueExpression returns [JsonKeyValue vResult = FragmentFactory.CreateFra
{
vResult.JsonValue=vValue;
}
+
+ |
+
+ label:Label
+ {
+ var identifier = this.FragmentFactory.CreateFragment();
+ var multiPartIdentifier = this.FragmentFactory.CreateFragment();
+ var columnRef = this.FragmentFactory.CreateFragment();
+ CreateIdentifierFromLabel(label, identifier, multiPartIdentifier);
+ columnRef.MultiPartIdentifier = multiPartIdentifier;
+ vResult.JsonKeyName=columnRef;
+ }
+ vValue=expression
+ {
+ vResult.JsonValue=vValue;
+ }
)
;
@@ -32785,6 +32830,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 +32877,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/Parser/TSql/TSql80ParserBaseInternal.cs b/SqlScriptDom/Parser/TSql/TSql80ParserBaseInternal.cs
index 120adcc..7415c4a 100644
--- a/SqlScriptDom/Parser/TSql/TSql80ParserBaseInternal.cs
+++ b/SqlScriptDom/Parser/TSql/TSql80ParserBaseInternal.cs
@@ -263,6 +263,25 @@ internal static void UpdateTokenInfo(TSqlFragment fragment, antlr.IToken token)
fragment.UpdateTokenInfo(tokenIndex, tokenIndex);
}
+ ///
+ /// Creates an identifier from a label token and adds it to the multipart identifier.
+ ///
+ ///
+ ///
+ ///
+ internal static void CreateIdentifierFromLabel(antlr.IToken token, Identifier identifier, MultiPartIdentifier multiPartIdentifier)
+ {
+ var tokenText = token?.getText();
+ if (string.IsNullOrEmpty(tokenText))
+ {
+ throw GetUnexpectedTokenErrorException(token);
+ }
+ var identifierName = tokenText?.EndsWith(":") == true ? tokenText.Substring(0, tokenText.Length - 1) : tokenText;
+ identifier.SetIdentifier(identifierName);
+ UpdateTokenInfo(identifier, token);
+ AddAndUpdateTokenInfo(multiPartIdentifier, multiPartIdentifier.Identifiers, identifier);
+ }
+
protected static void AddAndUpdateTokenInfo(TSqlFragment node, IList collection, TFragmentType item)
where TFragmentType : TSqlFragment
{
diff --git a/SqlScriptDom/Parser/TSql/TSqlFabricDW.g b/SqlScriptDom/Parser/TSql/TSqlFabricDW.g
index 137a318..fda6c13 100644
--- a/SqlScriptDom/Parser/TSql/TSqlFabricDW.g
+++ b/SqlScriptDom/Parser/TSql/TSqlFabricDW.g
@@ -17746,15 +17746,29 @@ commonTableExpression returns [CommonTableExpression vResult = this.FragmentFact
{
Identifier vIdentifier;
QueryExpression vQueryExpression;
+ WithCtesAndXmlNamespaces vWithCommonTableExpressionsAndXmlNamespaces;
}
: vIdentifier=identifier
{
vResult.ExpressionName = vIdentifier;
}
(columnNameList[vResult, vResult.Columns])?
- As tLParen:LeftParenthesis vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert] tRParen:RightParenthesis
+ As tLParen:LeftParenthesis
+ (
+ vWithCommonTableExpressionsAndXmlNamespaces=withCommonTableExpressionsAndXmlNamespaces
+ vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert]
+ {
+ vResult.QueryExpression = vQueryExpression;
+ vResult.WithCtesAndXmlNamespaces = vWithCommonTableExpressionsAndXmlNamespaces;
+ }
+ |
+ vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert]
+ {
+ vResult.QueryExpression = vQueryExpression;
+ }
+ )
+ tRParen:RightParenthesis
{
- vResult.QueryExpression = vQueryExpression;
UpdateTokenInfo(vResult,tLParen);
UpdateTokenInfo(vResult,tRParen);
}
diff --git a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.CommonTableExpression.cs b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.CommonTableExpression.cs
index dc6d8e0..7fec1eb 100644
--- a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.CommonTableExpression.cs
+++ b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.CommonTableExpression.cs
@@ -31,7 +31,28 @@ public override void ExplicitVisit(CommonTableExpression node)
AlignmentPoint subquery = new AlignmentPoint();
MarkAndPushAlignmentPoint(subquery);
- GenerateQueryExpressionInParentheses(node.QueryExpression);
+ GenerateSymbol(TSqlTokenType.LeftParenthesis);
+
+ AlignmentPoint queryBody = new AlignmentPoint();
+ MarkAndPushAlignmentPoint(queryBody);
+
+ // Generate nested WITH clause if present
+ if (node.WithCtesAndXmlNamespaces != null)
+ {
+ AlignmentPoint clauseBodyNested = new AlignmentPoint(ClauseBody);
+ GenerateFragmentWithAlignmentPointIfNotNull(node.WithCtesAndXmlNamespaces, clauseBodyNested);
+ NewLine();
+ }
+
+ if (node.QueryExpression != null)
+ {
+ AlignmentPoint clauseBodyQuery = new AlignmentPoint(ClauseBody);
+ GenerateFragmentWithAlignmentPointIfNotNull(node.QueryExpression, clauseBodyQuery);
+ }
+
+ PopAlignmentPoint();
+
+ GenerateSymbol(TSqlTokenType.RightParenthesis);
PopAlignmentPoint();
}
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/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/AiGenerateChunksTests170.sql b/Test/SqlDom/Baselines170/AiGenerateChunksTests170.sql
index 8374acc..a11724c 100644
--- a/Test/SqlDom/Baselines170/AiGenerateChunksTests170.sql
+++ b/Test/SqlDom/Baselines170/AiGenerateChunksTests170.sql
@@ -16,9 +16,6 @@ FROM AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE =
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = @SOURCE, CHUNK_TYPE = fixed, CHUNK_SIZE = @CHUNK_SIZE);
-SELECT *
-FROM AI_GENERATE_CHUNKS (SOURCE = @SOURCE, CHUNK_TYPE = fixed, CHUNK_SIZE = @CHUNK_SIZE, OVERLAP = @OVERLAP, ENABLE_CHUNK_SET_ID = @ENABLE_CHUNK_SET_ID);
-
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = NULL, CHUNK_TYPE = fixed, CHUNK_SIZE = 5);
@@ -31,9 +28,6 @@ FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed
SELECT *
FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = t1.c1);
-SELECT *
-FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = t1.c1);
-
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = N'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = NULL);
diff --git a/Test/SqlDom/Baselines170/JsonFunctionTests170.sql b/Test/SqlDom/Baselines170/JsonFunctionTests170.sql
index 29adc38..baa161f 100644
--- a/Test/SqlDom/Baselines170/JsonFunctionTests170.sql
+++ b/Test/SqlDom/Baselines170/JsonFunctionTests170.sql
@@ -37,7 +37,7 @@ DECLARE @id_key AS NVARCHAR (10) = N'id', @id_value AS NVARCHAR (64) = NEWID();
SELECT JSON_OBJECT('user_name':USER_NAME(), @id_key:@id_value, 'sid':(SELECT @@SPID));
SELECT s.session_id,
- JSON_OBJECT('security_id':s.security_id, 'login':s.login_name, 'status':s.status) AS info
+ JSON_OBJECT(security_id:s.security_id, 'login':s.login_name, 'status':s.status) AS info
FROM sys.dm_exec_sessions AS s
WHERE s.is_user_process = 1;
@@ -92,10 +92,44 @@ SELECT JSON_OBJECTAGG();
SELECT JSON_OBJECTAGG('name':1);
-SELECT JSON_OBJECTAGG('name':JSON_ARRAY(1, 2));
+SELECT JSON_OBJECTAGG('name':JSON_ARRAY(1, 2));
+
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_OBJECTAGG(c1:c2);
+
+SELECT JSON_OBJECTAGG(c1:'c2');
+
+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;
+
+
+GO
+CREATE VIEW dbo.jsonfunctest
+AS
+SELECT JSON_OBJECTAGG(c1:c2) AS jsoncontents
+FROM (VALUES ('key1', 'c'), ('key2', 'b'), ('key3', 'a')) AS t(c1, c2);
\ No newline at end of file
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/BaselinesFabricDW/NestedCTETestsFabricDW.sql b/Test/SqlDom/BaselinesFabricDW/NestedCTETestsFabricDW.sql
new file mode 100644
index 0000000..86e585d
--- /dev/null
+++ b/Test/SqlDom/BaselinesFabricDW/NestedCTETestsFabricDW.sql
@@ -0,0 +1,54 @@
+WITH Orders_Summary
+AS (SELECT CustomerID,
+ COUNT(*) AS OrderCount,
+ SUM(Amount) AS TotalAmount
+ FROM Orders
+ GROUP BY CustomerID)
+SELECT CustomerID,
+ OrderCount,
+ TotalAmount
+FROM Orders_Summary
+WHERE OrderCount > 5;
+
+WITH Regional_Analysis
+AS (WITH Sales_Data
+ AS (SELECT RegionID,
+ ProductID,
+ SUM(Amount) AS Sales
+ FROM Sales
+ GROUP BY RegionID, ProductID)
+ SELECT RegionID,
+ COUNT(ProductID) AS ProductCount,
+ SUM(Sales) AS TotalSales
+ FROM Sales_Data
+ GROUP BY RegionID)
+SELECT RegionID,
+ ProductCount,
+ TotalSales
+FROM Regional_Analysis
+WHERE TotalSales > 10000;
+
+WITH Final_Report
+AS (WITH Department_Summary
+ AS (WITH Employee_Data
+ AS (SELECT DepartmentID,
+ EmployeeID,
+ Salary
+ FROM Employees
+ WHERE IsActive = 1)
+ SELECT DepartmentID,
+ COUNT(EmployeeID) AS EmpCount,
+ AVG(Salary) AS AvgSalary
+ FROM Employee_Data
+ GROUP BY DepartmentID)
+ SELECT DepartmentID,
+ EmpCount,
+ AvgSalary,
+ CASE WHEN AvgSalary > 50000 THEN 'High' ELSE 'Low' END AS SalaryLevel
+ FROM Department_Summary)
+SELECT DepartmentID,
+ EmpCount,
+ AvgSalary,
+ SalaryLevel
+FROM Final_Report
+ORDER BY AvgSalary DESC;
\ No newline at end of file
diff --git a/Test/SqlDom/Only170SyntaxTests.cs b/Test/SqlDom/Only170SyntaxTests.cs
index a339cf7..736c839 100644
--- a/Test/SqlDom/Only170SyntaxTests.cs
+++ b/Test/SqlDom/Only170SyntaxTests.cs
@@ -1,6 +1,7 @@
using Microsoft.SqlServer.TransactSql.ScriptDom;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SqlStudio.Tests.AssemblyTools.TestCategory;
+using System.Collections.Generic;
namespace SqlStudio.Tests.UTSqlScriptDom
{
@@ -15,15 +16,15 @@ public partial class SqlDomTests
new ParserTest170("AlterDatabaseManualCutoverTests170.sql", nErrors80: 4, nErrors90: 4, nErrors100: 4, nErrors110: 4, nErrors120: 4, nErrors130: 4, nErrors140: 4, nErrors150: 4, nErrors160: 4),
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("AiGenerateChunksTests170.sql", nErrors80: 19, nErrors90: 16, nErrors100: 15, nErrors110: 15, nErrors120: 15, nErrors130: 15, nErrors140: 15, nErrors150: 15, nErrors160: 15),
+ new ParserTest170("JsonFunctionTests170.sql", nErrors80: 10, nErrors90: 8, nErrors100: 35, nErrors110: 35, nErrors120: 35, nErrors130: 35, nErrors140: 35, nErrors150: 35, nErrors160: 35),
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),
-
+ 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/OnlyFabricDWSyntaxTests.cs b/Test/SqlDom/OnlyFabricDWSyntaxTests.cs
index 043340e..86cc0b1 100644
--- a/Test/SqlDom/OnlyFabricDWSyntaxTests.cs
+++ b/Test/SqlDom/OnlyFabricDWSyntaxTests.cs
@@ -14,6 +14,7 @@ public partial class SqlDomTests
new ParserTestFabricDW("CreateExternalTableStatementTestsFabricDW.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 2, nErrors140: 2, nErrors150: 2, nErrors160: 0, nErrors170: 0),
new ParserTestFabricDW("CreateProcedureCloneTableTestsFabricDW.sql", nErrors80: 4, nErrors90: 4, nErrors100: 4, nErrors110: 4, nErrors120: 4, nErrors130: 4, nErrors140: 4, nErrors150: 4, nErrors160: 4, nErrors170: 4),
new ParserTestFabricDW("IdentityColumnTestsFabricDW.sql", nErrors80: 0, nErrors90: 0, nErrors100: 0, nErrors110: 0, nErrors120: 0, nErrors130: 0, nErrors140: 0, nErrors150: 0, nErrors160: 0, nErrors170: 0),
+ new ParserTestFabricDW("NestedCTETestsFabricDW.sql", nErrors80: 1, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 2, nErrors140: 2, nErrors150: 2, nErrors160: 2, nErrors170: 2),
new ParserTestFabricDW("ScalarFunctionTestsFabricDW.sql", nErrors80: 3, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 0, nErrors140: 0, nErrors150: 0, nErrors160: 0, nErrors170: 0)
};
diff --git a/Test/SqlDom/ParserErrorsTests.cs b/Test/SqlDom/ParserErrorsTests.cs
index 6a46317..26b5e09 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.
///
@@ -7189,6 +7218,31 @@ public void GenerateChunksNegativeTest170()
ParserTestUtils.ErrorTest170(
"SELECT * FROM AI_GENERATE_CHUNKS (source = 'some text', chunk_type = other, chunk_size = 5)",
new ParserErrorInfo(69, "SQL46010", "other"));
+
+ // Invalid ENABLE_CHUNK_SET_ID (parameter reference not allowed)
+ ParserTestUtils.ErrorTest170(
+ "SELECT * FROM AI_GENERATE_CHUNKS (SOURCE = @SOURCE, CHUNK_TYPE = fixed, CHUNK_SIZE = @CHUNK_SIZE, OVERLAP = @OVERLAP, ENABLE_CHUNK_SET_ID = @ENABLE_CHUNK_SET_ID)",
+ new ParserErrorInfo(140, "SQL46010", "@ENABLE_CHUNK_SET_ID"));
+
+ // Invalid ENABLE_CHUNK_SET_ID (column reference not allowed)
+ ParserTestUtils.ErrorTest170(
+ "SELECT * FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = t1.c1)",
+ new ParserErrorInfo(143, "SQL46010", "t1"));
+
+ // Invalid ENABLE_CHUNK_SET_ID (decimal literal not allowed)
+ ParserTestUtils.ErrorTest170(
+ "SELECT * FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = 0.1)",
+ new ParserErrorInfo(143, "SQL46010", "0.1"));
+
+ // Invalid ENABLE_CHUNK_SET_ID (string literal not allowed)
+ ParserTestUtils.ErrorTest170(
+ "SELECT * FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = '1')",
+ new ParserErrorInfo(143, "SQL46010", "'1'"));
+
+ // Invalid ENABLE_CHUNK_SET_ID (function call not allowed)
+ ParserTestUtils.ErrorTest170(
+ "SELECT * FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = rand())",
+ new ParserErrorInfo(143, "SQL46010", "rand"));
}
///
diff --git a/Test/SqlDom/TestScripts/AiGenerateChunksTests170.sql b/Test/SqlDom/TestScripts/AiGenerateChunksTests170.sql
index 8374acc..a11724c 100644
--- a/Test/SqlDom/TestScripts/AiGenerateChunksTests170.sql
+++ b/Test/SqlDom/TestScripts/AiGenerateChunksTests170.sql
@@ -16,9 +16,6 @@ FROM AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE =
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = @SOURCE, CHUNK_TYPE = fixed, CHUNK_SIZE = @CHUNK_SIZE);
-SELECT *
-FROM AI_GENERATE_CHUNKS (SOURCE = @SOURCE, CHUNK_TYPE = fixed, CHUNK_SIZE = @CHUNK_SIZE, OVERLAP = @OVERLAP, ENABLE_CHUNK_SET_ID = @ENABLE_CHUNK_SET_ID);
-
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = NULL, CHUNK_TYPE = fixed, CHUNK_SIZE = 5);
@@ -31,9 +28,6 @@ FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed
SELECT *
FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = t1.c1);
-SELECT *
-FROM t1 CROSS APPLY AI_GENERATE_CHUNKS (SOURCE = 'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = 10, OVERLAP = 5, ENABLE_CHUNK_SET_ID = t1.c1);
-
SELECT *
FROM AI_GENERATE_CHUNKS (SOURCE = N'some text', CHUNK_TYPE = fixed, CHUNK_SIZE = NULL);
diff --git a/Test/SqlDom/TestScripts/JsonFunctionTests170.sql b/Test/SqlDom/TestScripts/JsonFunctionTests170.sql
index d15a477..d275126 100644
--- a/Test/SqlDom/TestScripts/JsonFunctionTests170.sql
+++ b/Test/SqlDom/TestScripts/JsonFunctionTests170.sql
@@ -35,7 +35,7 @@ DECLARE @id_key AS NVARCHAR (10) = N'id', @id_value AS NVARCHAR (64) = NEWID();
SELECT JSON_OBJECT('user_name':USER_NAME(), @id_key:@id_value, 'sid':(SELECT @@SPID));
SELECT s.session_id,
- JSON_OBJECT('security_id':s.security_id, 'login':s.login_name, 'status':s.status) AS info
+ JSON_OBJECT(security_id:s.security_id, 'login':s.login_name, 'status':s.status) AS info
FROM sys.dm_exec_sessions AS s
WHERE s.is_user_process = 1;
@@ -96,3 +96,35 @@ 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_OBJECTAGG( c1:c2 )
+SELECT JSON_OBJECTAGG( c1:'c2' )
+
+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;
+
+GO
+CREATE VIEW dbo.jsonfunctest AS
+ SELECT JSON_OBJECTAGG( c1:c2 ) as jsoncontents
+ FROM (
+ VALUES('key1', 'c'), ('key2', 'b'), ('key3','a')
+ ) AS t(c1, c2);
\ No newline at end of file
diff --git a/Test/SqlDom/TestScripts/NestedCTETestsFabricDW.sql b/Test/SqlDom/TestScripts/NestedCTETestsFabricDW.sql
new file mode 100644
index 0000000..86e585d
--- /dev/null
+++ b/Test/SqlDom/TestScripts/NestedCTETestsFabricDW.sql
@@ -0,0 +1,54 @@
+WITH Orders_Summary
+AS (SELECT CustomerID,
+ COUNT(*) AS OrderCount,
+ SUM(Amount) AS TotalAmount
+ FROM Orders
+ GROUP BY CustomerID)
+SELECT CustomerID,
+ OrderCount,
+ TotalAmount
+FROM Orders_Summary
+WHERE OrderCount > 5;
+
+WITH Regional_Analysis
+AS (WITH Sales_Data
+ AS (SELECT RegionID,
+ ProductID,
+ SUM(Amount) AS Sales
+ FROM Sales
+ GROUP BY RegionID, ProductID)
+ SELECT RegionID,
+ COUNT(ProductID) AS ProductCount,
+ SUM(Sales) AS TotalSales
+ FROM Sales_Data
+ GROUP BY RegionID)
+SELECT RegionID,
+ ProductCount,
+ TotalSales
+FROM Regional_Analysis
+WHERE TotalSales > 10000;
+
+WITH Final_Report
+AS (WITH Department_Summary
+ AS (WITH Employee_Data
+ AS (SELECT DepartmentID,
+ EmployeeID,
+ Salary
+ FROM Employees
+ WHERE IsActive = 1)
+ SELECT DepartmentID,
+ COUNT(EmployeeID) AS EmpCount,
+ AVG(Salary) AS AvgSalary
+ FROM Employee_Data
+ GROUP BY DepartmentID)
+ SELECT DepartmentID,
+ EmpCount,
+ AvgSalary,
+ CASE WHEN AvgSalary > 50000 THEN 'High' ELSE 'Low' END AS SalaryLevel
+ FROM Department_Summary)
+SELECT DepartmentID,
+ EmpCount,
+ AvgSalary,
+ SalaryLevel
+FROM Final_Report
+ORDER BY AvgSalary DESC;
\ No newline at end of file
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
diff --git a/release-notes/170/170.100.0.md b/release-notes/170/170.100.0.md
new file mode 100644
index 0000000..8f6bf9f
--- /dev/null
+++ b/release-notes/170/170.100.0.md
@@ -0,0 +1,25 @@
+# Release Notes
+
+## Microsoft.SqlServer.TransactSql.ScriptDom 170.100.0
+This update brings the below 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.413
+
+#### .NET Framework
+#### .NET Core
+
+### New Features
+* Adds support for `JSON_ARRAYAGG` abd `REGEXP_LIKE` Functions.
+
+### Fixed
+
+### Changes
+
+### Known Issues