Skip to content

Commit 96924d1

Browse files
committed
JSON_OBJECTAGG support for OVER clause
## Description JSON_OBJECTAGG supports windowed aggregate usage via the OVER (PARTITION BY ...) clause in SQL Server, but ScriptDOM was missing support for parsing and generating it. This PR adds OVER clause support for JSON_OBJECTAGG in the TSql170 parser and script generator. SQL syntax now supported: `sql SELECT JSON_OBJECTAGG(CustomerName:OrderDate) OVER (PARTITION BY OrderDate) FROM Customers; SELECT JSON_OBJECTAGG(CustomerName:OrderDate ABSENT ON NULL) OVER (PARTITION BY OrderDate) FROM Customers; SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL) OVER (PARTITION BY OrderDate) FROM Customers; SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL RETURNING JSON) OVER (PARTITION BY OrderDate) FROM Customers; ` ## Changes - Updated JSON_OBJECTAGG production in TSql170.g to optionally parse an OVER clause - Enhanced SqlScriptGeneratorVisitor.FunctionCall.cs to generate the OVER clause in the output - Added new baseline and test scripts (JsonObjectAggOverClause170.sql in both Baselines170 and TestScripts) ## Additional Information No AST changes were needed -- FunctionCall.OverClause already exists in Ast.xml. The grammar uses overClauseNoOrderBy (not overClause) since, like regular aggregates (e.g., SUM() OVER (...)), the ORDER BY within the OVER clause is not applicable for JSON_OBJECTAGG as a windowed aggregate. All older parsers (80-160) produce 4 errors each (one per test statement) since the JSON_OBJECTAGG key:value syntax is not recognized pre-TSql170.
1 parent c6e10b2 commit 96924d1

File tree

5 files changed

+32
-0
lines changed

5 files changed

+32
-0
lines changed

SqlScriptDom/Parser/TSql/TSql170.g

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33167,6 +33167,7 @@ jsonObjectBuiltInFunctionCall [FunctionCall vParent]
3316733167

3316833168
jsonObjectAggBuiltInFunctionCall [FunctionCall vParent]
3316933169
{
33170+
OverClause vOverClause;
3317033171
}
3317133172
: (
3317233173
jsonObjectAggExpressionList[vParent]
@@ -33177,6 +33178,12 @@ jsonObjectAggBuiltInFunctionCall [FunctionCall vParent]
3317733178
{
3317833179
UpdateTokenInfo(vParent, tRParen);
3317933180
}
33181+
(
33182+
vOverClause=overClauseNoOrderBy
33183+
{
33184+
vParent.OverClause = vOverClause;
33185+
}
33186+
)?
3318033187
;
3318133188

3318233189
jsonQueryBuiltInFunctionCall [FunctionCall vParent]

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public override void ExplicitVisit(FunctionCall node)
7070
GenerateSpace();
7171
GenerateReturnType(node?.ReturnType);
7272
GenerateSymbol(TSqlTokenType.RightParenthesis);
73+
// Generate OVER clause for windowed json_objectagg
74+
GenerateSpaceAndFragmentIfNotNull(node.OverClause);
7375
}
7476
else if (node.FunctionName.Value.ToUpper(CultureInfo.InvariantCulture) == CodeGenerationSupporter.JsonArray)
7577
{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate) OVER (PARTITION BY OrderDate)
2+
FROM Customers;
3+
4+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate ABSENT ON NULL) OVER (PARTITION BY OrderDate)
5+
FROM Customers;
6+
7+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL) OVER (PARTITION BY OrderDate)
8+
FROM Customers;
9+
10+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL RETURNING JSON) OVER (PARTITION BY OrderDate)
11+
FROM Customers;

Test/SqlDom/Only170SyntaxTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public partial class SqlDomTests
2121
new ParserTest170("AiGenerateChunksTests170.sql", nErrors80: 19, nErrors90: 16, nErrors100: 15, nErrors110: 15, nErrors120: 15, nErrors130: 15, nErrors140: 15, nErrors150: 15, nErrors160: 15),
2222
new ParserTest170("JsonFunctionTests170.sql", nErrors80: 29, nErrors90: 8, nErrors100: 54, nErrors110: 54, nErrors120: 54, nErrors130: 54, nErrors140: 54, nErrors150: 54, nErrors160: 54),
2323
new ParserTest170("JsonArrayAggOrderBy170.sql", nErrors80: 10, nErrors90: 9, nErrors100: 9, nErrors110: 9, nErrors120: 9, nErrors130: 9, nErrors140: 9, nErrors150: 9, nErrors160: 9),
24+
new ParserTest170("JsonObjectAggOverClause170.sql", nErrors80: 4, nErrors90: 4, nErrors100: 4, nErrors110: 4, nErrors120: 4, nErrors130: 4, nErrors140: 4, nErrors150: 4, nErrors160: 4),
2425
new ParserTest170("ComplexJsonObjectFunctionTests170.sql"),
2526
new ParserTest170("AiGenerateEmbeddingsTests170.sql", nErrors80: 14, nErrors90: 11, nErrors100: 11, nErrors110: 11, nErrors120: 11, nErrors130: 11, nErrors140: 11, nErrors150: 11, nErrors160: 11),
2627
new ParserTest170("CreateExternalModelStatementTests170.sql", nErrors80: 2, nErrors90: 2, nErrors100: 2, nErrors110: 2, nErrors120: 2, nErrors130: 4, nErrors140: 4, nErrors150: 4, nErrors160: 4),
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-- JSON_OBJECTAGG with OVER clause (PARTITION BY)
2+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate) OVER (PARTITION BY OrderDate) FROM Customers;
3+
4+
-- JSON_OBJECTAGG with ABSENT ON NULL and OVER clause
5+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate ABSENT ON NULL) OVER (PARTITION BY OrderDate) FROM Customers;
6+
7+
-- JSON_OBJECTAGG with NULL ON NULL and OVER clause
8+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL) OVER (PARTITION BY OrderDate) FROM Customers;
9+
10+
-- JSON_OBJECTAGG with NULL ON NULL, RETURNING JSON, and OVER clause
11+
SELECT JSON_OBJECTAGG(CustomerName:OrderDate NULL ON NULL RETURNING JSON) OVER (PARTITION BY OrderDate) FROM Customers;

0 commit comments

Comments
 (0)