Skip to content

Commit aaac0c3

Browse files
hayssamsclaude
andcommitted
Support ORDER BY after IGNORE NULLS in aggregate functions
BigQuery orders aggregate arguments as ARRAY_AGG(expr [IGNORE NULLS] [ORDER BY key] [LIMIT n]), so the ORDER BY may follow the null handling. Only the pre-null-handling position was accepted before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EqinwHBKuAtPEmtXr3b5P2
1 parent 9dd197a commit aaac0c3

2 files changed

Lines changed: 27 additions & 1 deletion

File tree

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11519,6 +11519,7 @@ Function InternalFunction(boolean escaped):
1151911519
Column attributeColumn = null;
1152011520
Token attributeToken = null;
1152111521
Limit limit;
11522+
List<OrderByElement> orderByList = null;
1152211523
List<Function.KeywordArgument> keywordArgs = null;
1152311524
}
1152411525
{
@@ -11568,6 +11569,12 @@ Function InternalFunction(boolean escaped):
1156811569
)
1156911570
]
1157011571

11572+
// BigQuery orders aggregate arguments after the null handling:
11573+
// ARRAY_AGG(expr [IGNORE NULLS] [ORDER BY key] [LIMIT n])
11574+
[
11575+
LOOKAHEAD(2) orderByList = OrderByElements() { retval.setOrderByElements(orderByList); }
11576+
]
11577+
1157111578
[
1157211579
limit = PlainLimit() { retval.setLimit(limit); }
1157311580
]
@@ -11651,7 +11658,8 @@ ExpressionList FunctionArgumentList(Function retval):
1165111658
{ if ("XMLFOREST".equalsIgnoreCase(retval.getName())) { return XmlForestArguments(); } }
1165211659
[ LOOKAHEAD(2) extraKeywordToken = <K_TABLE> { retval.setExtraKeyword(extraKeywordToken.image); } ]
1165311660
expressionList=ExpressionList()
11654-
[ orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]
11661+
// explicit lookahead: InternalFunction accepts ORDER BY after IGNORE NULLS too
11662+
[ LOOKAHEAD(2) orderByList = OrderByElements() { retval.setOrderByElements(orderByList); } ]
1165511663

1165611664
// https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LISTAGG.html
1165711665
[

src/test/java/net/sf/jsqlparser/statement/select/BigQueryTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,22 @@ void testUnnestWithOrdinalityAliasStillBindsToTableFunction() throws JSQLParserE
160160
Assertions.assertFalse(unnest.isWithOffset());
161161
Assertions.assertEquals("t", unnest.getAlias().getName());
162162
}
163+
164+
@Test
165+
void testAggregateFunctionIgnoreNullsBeforeOrderBy() throws JSQLParserException {
166+
String sqlStr = "SELECT ARRAY_AGG(x IGNORE NULLS ORDER BY x) FROM t";
167+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
168+
}
169+
170+
@Test
171+
void testAggregateFunctionIgnoreNullsOrderByLimit() throws JSQLParserException {
172+
String sqlStr = "SELECT ARRAY_AGG(DISTINCT x IGNORE NULLS ORDER BY x DESC LIMIT 5) FROM t";
173+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
174+
}
175+
176+
@Test
177+
void testAggregateFunctionOrderByWithoutNullHandling() throws JSQLParserException {
178+
String sqlStr = "SELECT ARRAY_AGG(x ORDER BY x) FROM t";
179+
TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true);
180+
}
163181
}

0 commit comments

Comments
 (0)