Skip to content

Commit 4ba3382

Browse files
authored
Sync Repos: Release 170.82.0 (#154)
* 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. * 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. Adding missing event CREATE_JSON_INDEX * Merged PR 1781082: Adding regexp_like syntax Regexp_like function works as a boolean expression similar to LIKE, MATCH starting from compat level 170. Adding regexp_like syntax Related work items: #4005966 * 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 <NESTED_CTE_NAME_LEVEL1> [ (column_name , ...) ] AS (WITH <NESTED_CTE_NAME_LEVEL2> [ (column_name , ...) ] AS ( ... WITH <NESTED_CTE_NAME_LEVELn-1> [ ( column_name , ...) ] AS ( WITH <NESTED_CTE_NAME_LEVELn> [ ( column_name , ...) ] AS ( Standard_CTE_query_definition ) <SELECT statement> -- Data source must include NESTED_CTE_NAME_LEVELn ) <SELECT statement> -- Data source must include NESTED_CTE_NAME_LEVELn-1 ... ) <SELECT statement> -- Data source must include NESTED_CTE_NAME_LEVEL2 ) ``` This is derived from public [Nested CTE Documentation](https://learn.microsoft.com/en-us/sql/t-sql/queries/nested-common-table-expression?view=sql-server-ver16). Work Item: https://dev.azure.com/powerbi/AI/_workitems/edit/1672555/ * Merged PR 1785976: [AI_GENERATE_CHUNKS] ENABLE_CHUNK_SET_ID to Integer # Pull Request Template for ScriptDom ## Description This PR changes the optional parameter ENABLE_CHUNK_SET_ID of AI_GENERATE_CHUNKS from expression to integer/null only. * Merged PR 1780003: Fixed a bug when parsing json keyvalue parameter Some of json functions accept json key value and the key value can be with or without single quote. The problem comes when the parser assumes any name and ':' should be parsed as a label. and label are not supported as function parameters. since it's not easy to differentiate between a label and json value, had to change the parser to accept label as function parameter and then parse it as column reference. Fixed a bug when parsing json keyvalue parameter * Merged PR 1787157: Adding release notes for 170.100 Adding release notes for 170.0.96
1 parent 63236ba commit 4ba3382

22 files changed

+541
-29
lines changed

SqlScriptDom/Parser/TSql/Ast.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
<Member Name="ExpressionName" Type="Identifier" Summary="The expression name."/>
237237
<Member Name="Columns" Type="Identifier" Collection="true" Summary="The columns. Optional may have zero elements."/>
238238
<Member Name="QueryExpression" Type="QueryExpression" Summary="The query definition."/>
239+
<Member Name="WithCtesAndXmlNamespaces" Type="WithCtesAndXmlNamespaces" Nullable="true" Summary="Nested CTE." />
239240
</Class>
240241
<Class Name="WithCtesAndXmlNamespaces" Summary="This class represents a common construct that can have common table expressions and xml namespaces in it.">
241242
<Member Name="XmlNamespaces" Type="XmlNamespaces" Summary="The xml namespaces. May be null."/>
@@ -349,6 +350,11 @@
349350
<Member Name="OdbcEscape" Type="bool" Summary="True if escape is defined using odbc delimiters."/>
350351
<Member Name="EscapeExpression" Type="ScalarExpression" Summary="The escape expression. Optional may be null."/>
351352
</Class>
353+
<Class Name="RegexpLikePredicate" Base="BooleanExpression" Summary="Represents the REGEXP_LIKE boolean predicate.">
354+
<Member Name="Text" Type="ScalarExpression" Summary="The text to match against the pattern."/>
355+
<Member Name="Pattern" Type="ScalarExpression" Summary="The regular expression pattern."/>
356+
<Member Name="Flags" Type="ScalarExpression" Optional="true" Summary="Optional flags for the regular expression match."/>
357+
</Class>
352358
<Class Name="DistinctPredicate" Base="BooleanExpression" Summary="Represents the distinct predicate.">
353359
<Member Name="FirstExpression" Type="ScalarExpression" Summary="The first expression."/>
354360
<Member Name="SecondExpression" Type="ScalarExpression" Summary="The second expression."/>

SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ internal static class CodeGenerationSupporter
523523
internal const string JsonArray = "JSON_ARRAY";
524524
internal const string JsonObject = "JSON_OBJECT";
525525
internal const string JsonObjectAgg = "JSON_OBJECTAGG";
526+
internal const string JsonArrayAgg = "JSON_ARRAYAGG";
526527
internal const string Keep = "KEEP";
527528
internal const string KeepDefaults = "KEEPDEFAULTS";
528529
internal const string KeepFixed = "KEEPFIXED";
@@ -819,6 +820,7 @@ internal static class CodeGenerationSupporter
819820
internal const string RecursiveTriggers = "RECURSIVE_TRIGGERS";
820821
internal const string Recovery = "RECOVERY";
821822
internal const string Regenerate = "REGENERATE";
823+
internal const string RegexpLike = "REGEXP_LIKE";
822824
internal const string RegexpMatches = "REGEXP_MATCHES";
823825
internal const string RegexpSplitToTable = "REGEXP_SPLIT_TO_TABLE";
824826
internal const string RejectType = "REJECT_TYPE";

SqlScriptDom/Parser/TSql/EventNotificationEventType.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,11 @@ public enum EventNotificationEventType
10911091
/// </summary>
10921092
DropExternalLanguage = 331,
10931093

1094+
/// <summary>
1095+
/// CREATE_JSON_INDEX
1096+
/// </summary>
1097+
CreateJsonIndex = 343,
1098+
10941099
/// <summary>
10951100
/// CREATE_VECTOR_INDEX
10961101
/// </summary>

SqlScriptDom/Parser/TSql/TSql160.g

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31846,15 +31846,31 @@ jsonKeyValueExpression returns [JsonKeyValue vResult = FragmentFactory.CreateFra
3184631846
:
3184731847
(
3184831848
vKey=expression
31849-
{
31850-
vResult.JsonKeyName=vKey;
31851-
}
31849+
{
31850+
vResult.JsonKeyName=vKey;
31851+
}
3185231852
Colon vValue=expression
31853-
{
31854-
vResult.JsonValue=vValue;
31853+
{
31854+
vResult.JsonValue=vValue;
3185531855
}
31856-
)
31857-
;
31856+
31857+
|
31858+
31859+
label:Label
31860+
{
31861+
var identifier = this.FragmentFactory.CreateFragment<Identifier>();
31862+
var multiPartIdentifier = this.FragmentFactory.CreateFragment<MultiPartIdentifier>();
31863+
var columnRef = this.FragmentFactory.CreateFragment<ColumnReferenceExpression>();
31864+
CreateIdentifierFromLabel(label, identifier, multiPartIdentifier);
31865+
columnRef.MultiPartIdentifier = multiPartIdentifier;
31866+
vResult.JsonKeyName=columnRef;
31867+
}
31868+
vValue=expression
31869+
{
31870+
vResult.JsonValue=vValue;
31871+
}
31872+
)
31873+
;
3185831874

3185931875
windowClause returns [WindowClause vResult = FragmentFactory.CreateFragment<WindowClause>()]
3186031876
{

SqlScriptDom/Parser/TSql/TSql170.g

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19238,7 +19238,10 @@ aiGenerateFixedChunksTableReference [ScalarExpression vSource, Identifier vChunk
1923819238
Match(vEnableChunkSetIdParam, CodeGenerationSupporter.EnableChunkSetId);
1923919239
}
1924019240
EqualsSign
19241-
vEnableChunkSetId = expression
19241+
(
19242+
vEnableChunkSetId = integer // constant integer
19243+
| vEnableChunkSetId = nullLiteral // NULL literal
19244+
)
1924219245
{
1924319246
vResult.EnableChunkSetId = vEnableChunkSetId;
1924419247
}
@@ -31094,6 +31097,9 @@ booleanExpressionPrimary [ExpressionFlags expressionFlags] returns [BooleanExpre
3109431097
vResult = vMatchPredicate;
3109531098
UpdateTokenInfo(vResult,tRParen);
3109631099
}
31100+
|
31101+
{NextTokenMatches(CodeGenerationSupporter.RegexpLike)}?
31102+
vResult=regexpLikePredicate
3109731103
|
3109831104
vExpressionFirst=expressionWithFlags[expressionFlags]
3109931105
(
@@ -31475,6 +31481,29 @@ tsEqualCall returns [TSEqualCall vResult = this.FragmentFactory.CreateFragment<T
3147531481
}
3147631482
;
3147731483

31484+
regexpLikePredicate returns [RegexpLikePredicate vResult = this.FragmentFactory.CreateFragment<RegexpLikePredicate>()]
31485+
{
31486+
ScalarExpression vText;
31487+
ScalarExpression vPattern;
31488+
ScalarExpression vFlags = null;
31489+
}
31490+
: tRegexp:Identifier LeftParenthesis vText=expression Comma vPattern=expression
31491+
{
31492+
UpdateTokenInfo(vResult,tRegexp);
31493+
vResult.Text = vText;
31494+
vResult.Pattern = vPattern;
31495+
}
31496+
(Comma vFlags=expression
31497+
)?
31498+
{
31499+
vResult.Flags = vFlags;
31500+
}
31501+
tRParen:RightParenthesis
31502+
{
31503+
UpdateTokenInfo(vResult,tRParen);
31504+
}
31505+
;
31506+
3147831507
updateCall returns [UpdateCall vResult = this.FragmentFactory.CreateFragment<UpdateCall>()]
3147931508
{
3148031509
Identifier vIdentifier;
@@ -32502,6 +32531,22 @@ jsonKeyValueExpression returns [JsonKeyValue vResult = FragmentFactory.CreateFra
3250232531
{
3250332532
vResult.JsonValue=vValue;
3250432533
}
32534+
32535+
|
32536+
32537+
label:Label
32538+
{
32539+
var identifier = this.FragmentFactory.CreateFragment<Identifier>();
32540+
var multiPartIdentifier = this.FragmentFactory.CreateFragment<MultiPartIdentifier>();
32541+
var columnRef = this.FragmentFactory.CreateFragment<ColumnReferenceExpression>();
32542+
CreateIdentifierFromLabel(label, identifier, multiPartIdentifier);
32543+
columnRef.MultiPartIdentifier = multiPartIdentifier;
32544+
vResult.JsonKeyName=columnRef;
32545+
}
32546+
vValue=expression
32547+
{
32548+
vResult.JsonValue=vValue;
32549+
}
3250532550
)
3250632551
;
3250732552

@@ -32785,6 +32830,9 @@ builtInFunctionCall returns [FunctionCall vResult = FragmentFactory.CreateFragme
3278532830
|
3278632831
{(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonObjectAgg)}?
3278732832
jsonObjectAggBuiltInFunctionCall[vResult]
32833+
|
32834+
{(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArrayAgg)}?
32835+
jsonArrayAggBuiltInFunctionCall[vResult]
3278832836
|
3278932837
{(vResult.FunctionName != null && vResult.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.Trim) &&
3279032838
(NextTokenMatches(CodeGenerationSupporter.Leading) | NextTokenMatches(CodeGenerationSupporter.Trailing) | NextTokenMatches(CodeGenerationSupporter.Both))}?
@@ -32829,6 +32877,32 @@ jsonArrayBuiltInFunctionCall [FunctionCall vParent]
3282932877
}
3283032878
;
3283132879

32880+
jsonArrayAggBuiltInFunctionCall [FunctionCall vParent]
32881+
{
32882+
ScalarExpression vExpression;
32883+
}
32884+
: (
32885+
vExpression=expression
32886+
{
32887+
AddAndUpdateTokenInfo(vParent, vParent.Parameters, vExpression);
32888+
}
32889+
)
32890+
(
32891+
jsonNullClauseFunction[vParent]
32892+
|
32893+
/* empty */
32894+
)
32895+
(
32896+
jsonReturningClause[vParent]
32897+
|
32898+
/* empty */
32899+
)
32900+
tRParen:RightParenthesis
32901+
{
32902+
UpdateTokenInfo(vParent, tRParen);
32903+
}
32904+
;
32905+
3283232906
jsonObjectBuiltInFunctionCall [FunctionCall vParent]
3283332907
{
3283432908
}

SqlScriptDom/Parser/TSql/TSql80ParserBaseInternal.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,25 @@ internal static void UpdateTokenInfo(TSqlFragment fragment, antlr.IToken token)
263263
fragment.UpdateTokenInfo(tokenIndex, tokenIndex);
264264
}
265265

266+
/// <summary>
267+
/// Creates an identifier from a label token and adds it to the multipart identifier.
268+
/// </summary>
269+
/// <param name="token"></param>
270+
/// <param name="identifier"></param>
271+
/// <param name="multiPartIdentifier"></param>
272+
internal static void CreateIdentifierFromLabel(antlr.IToken token, Identifier identifier, MultiPartIdentifier multiPartIdentifier)
273+
{
274+
var tokenText = token?.getText();
275+
if (string.IsNullOrEmpty(tokenText))
276+
{
277+
throw GetUnexpectedTokenErrorException(token);
278+
}
279+
var identifierName = tokenText?.EndsWith(":") == true ? tokenText.Substring(0, tokenText.Length - 1) : tokenText;
280+
identifier.SetIdentifier(identifierName);
281+
UpdateTokenInfo(identifier, token);
282+
AddAndUpdateTokenInfo(multiPartIdentifier, multiPartIdentifier.Identifiers, identifier);
283+
}
284+
266285
protected static void AddAndUpdateTokenInfo<TFragmentType>(TSqlFragment node, IList<TFragmentType> collection, TFragmentType item)
267286
where TFragmentType : TSqlFragment
268287
{

SqlScriptDom/Parser/TSql/TSqlFabricDW.g

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17746,15 +17746,29 @@ commonTableExpression returns [CommonTableExpression vResult = this.FragmentFact
1774617746
{
1774717747
Identifier vIdentifier;
1774817748
QueryExpression vQueryExpression;
17749+
WithCtesAndXmlNamespaces vWithCommonTableExpressionsAndXmlNamespaces;
1774917750
}
1775017751
: vIdentifier=identifier
1775117752
{
1775217753
vResult.ExpressionName = vIdentifier;
1775317754
}
1775417755
(columnNameList[vResult, vResult.Columns])?
17755-
As tLParen:LeftParenthesis vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert] tRParen:RightParenthesis
17756+
As tLParen:LeftParenthesis
17757+
(
17758+
vWithCommonTableExpressionsAndXmlNamespaces=withCommonTableExpressionsAndXmlNamespaces
17759+
vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert]
17760+
{
17761+
vResult.QueryExpression = vQueryExpression;
17762+
vResult.WithCtesAndXmlNamespaces = vWithCommonTableExpressionsAndXmlNamespaces;
17763+
}
17764+
|
17765+
vQueryExpression=subqueryExpression[SubDmlFlags.SelectNotForInsert]
17766+
{
17767+
vResult.QueryExpression = vQueryExpression;
17768+
}
17769+
)
17770+
tRParen:RightParenthesis
1775617771
{
17757-
vResult.QueryExpression = vQueryExpression;
1775817772
UpdateTokenInfo(vResult,tLParen);
1775917773
UpdateTokenInfo(vResult,tRParen);
1776017774
}

SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.CommonTableExpression.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,28 @@ public override void ExplicitVisit(CommonTableExpression node)
3131
AlignmentPoint subquery = new AlignmentPoint();
3232
MarkAndPushAlignmentPoint(subquery);
3333

34-
GenerateQueryExpressionInParentheses(node.QueryExpression);
34+
GenerateSymbol(TSqlTokenType.LeftParenthesis);
35+
36+
AlignmentPoint queryBody = new AlignmentPoint();
37+
MarkAndPushAlignmentPoint(queryBody);
38+
39+
// Generate nested WITH clause if present
40+
if (node.WithCtesAndXmlNamespaces != null)
41+
{
42+
AlignmentPoint clauseBodyNested = new AlignmentPoint(ClauseBody);
43+
GenerateFragmentWithAlignmentPointIfNotNull(node.WithCtesAndXmlNamespaces, clauseBodyNested);
44+
NewLine();
45+
}
46+
47+
if (node.QueryExpression != null)
48+
{
49+
AlignmentPoint clauseBodyQuery = new AlignmentPoint(ClauseBody);
50+
GenerateFragmentWithAlignmentPointIfNotNull(node.QueryExpression, clauseBodyQuery);
51+
}
52+
53+
PopAlignmentPoint();
54+
55+
GenerateSymbol(TSqlTokenType.RightParenthesis);
3556

3657
PopAlignmentPoint();
3758
}

SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.FunctionCall.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ public override void ExplicitVisit(FunctionCall node)
7272
GenerateSymbol(TSqlTokenType.RightParenthesis);
7373
}
7474
else if (node.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArray)
75+
{
76+
GenerateCommaSeparatedList(node.Parameters);
77+
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
78+
GenerateSpace();
79+
GenerateNullOnNullOrAbsentOnNull(node?.AbsentOrNullOnNull);
80+
if (node.ReturnType?.Count > 0) //If there are values and null on null or absent on null present then generate space in between them
81+
GenerateSpace();
82+
GenerateReturnType(node?.ReturnType);
83+
GenerateSymbol(TSqlTokenType.RightParenthesis);
84+
}
85+
else if (node.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArrayAgg)
7586
{
7687
GenerateCommaSeparatedList(node.Parameters);
7788
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
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//------------------------------------------------------------------------------
2+
// <copyright file="SqlScriptGeneratorVisitor.RegexpLikePredicate.cs" company="Microsoft">
3+
// Copyright (c) Microsoft Corporation. All rights reserved.
4+
// </copyright>
5+
//------------------------------------------------------------------------------
6+
using System;
7+
using Microsoft.SqlServer.TransactSql.ScriptDom;
8+
9+
namespace Microsoft.SqlServer.TransactSql.ScriptDom.ScriptGenerator
10+
{
11+
internal partial class SqlScriptGeneratorVisitor
12+
{
13+
public override void ExplicitVisit(RegexpLikePredicate node)
14+
{
15+
GenerateIdentifier(CodeGenerationSupporter.RegexpLike);
16+
17+
GenerateSpace();
18+
GenerateSymbol(TSqlTokenType.LeftParenthesis);
19+
20+
GenerateFragmentIfNotNull(node.Text);
21+
GenerateSymbol(TSqlTokenType.Comma);
22+
GenerateSpace();
23+
GenerateFragmentIfNotNull(node.Pattern);
24+
25+
if (node.Flags != null)
26+
{
27+
GenerateSymbol(TSqlTokenType.Comma);
28+
GenerateSpace();
29+
GenerateFragmentIfNotNull(node.Flags);
30+
}
31+
32+
GenerateSymbol(TSqlTokenType.RightParenthesis);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)