@@ -1833,6 +1833,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
18331833 }
18341834 }
18351835
1836+ /** Whether a window specification starts with the name of the window it extends. */
1837+ private boolean isBaseWindowNameAhead() {
1838+ Token token = getToken(1);
1839+ switch (token.kind) {
1840+ case K_PARTITION: case K_ORDER: case K_ROWS: case K_RANGE: case K_GROUPS:
1841+ return false;
1842+ default:
1843+ return isIdentifierishNameToken(token);
1844+ }
1845+ }
1846+
18361847 private boolean isAliasAhead() {
18371848 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
18381849 return false;
@@ -8409,6 +8420,9 @@ PlainSelect PlainSelect() #PlainSelect:
84098420 ( LOOKAHEAD(2) "," windowName = RelObjectName() <K_AS> winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )*
84108421 { plainSelect.setWindowDefinitions(winDefs); }
84118422 ]
8423+ // DuckDB: QUALIFY after WINDOW
8424+ [ LOOKAHEAD(2, { plainSelect.getQualify() == null }) qualify=Qualify()
8425+ { plainSelect.setQualify(qualify); plainSelect.setQualifyAfterWindow(true); } ]
84128426 [ LOOKAHEAD(<K_ORDER> <K_BY>) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ]
84138427 [ LOOKAHEAD(2) interpolateElements = InterpolateClause() { plainSelect.setInterpolate(interpolateElements); } ]
84148428 [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ]
@@ -13498,8 +13512,12 @@ WindowDefinition windowDefinition() : {
1349813512 WindowElement windowElement = null;
1349913513 boolean partitionByBrackets = false;
1350013514 WindowDefinition winDef = new WindowDefinition();
13515+ String baseWindowName;
1350113516} {
1350213517 "("
13518+ // DuckDB: (w ORDER BY b) extends the named window w
13519+ [ LOOKAHEAD({ isBaseWindowNameAhead() }) baseWindowName=RelObjectName()
13520+ { winDef.setBaseWindowName(baseWindowName); } ]
1350313521 [<K_PARTITION> <K_BY>
1350413522 (LOOKAHEAD(3) expressionList=ComplexExpressionList()
1350513523 | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" )
@@ -13523,7 +13541,7 @@ AnalyticExpression AnalyticExpression(Function function) :
1352313541{
1352413542 (
1352513543 (
13526- filter=AggregateFilter() { retval.setType(AnalyticType.FILTER_ONLY); }
13544+ filter=AggregateFilter(retval ) { retval.setType(AnalyticType.FILTER_ONLY); }
1352713545 [ LOOKAHEAD(2) windowFun(retval) ]
1352813546 {
1352913547 if (Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
@@ -13535,19 +13553,29 @@ AnalyticExpression AnalyticExpression(Function function) :
1353513553 )
1353613554 | windowFun(retval)
1353713555 [ LOOKAHEAD({ retval.getType() == AnalyticType.WITHIN_GROUP
13538- && getToken(1).kind == K_FILTER }) filter=AggregateFilter() ]
13556+ && getToken(1).kind == K_FILTER }) filter=AggregateFilter(retval ) ]
1353913557 )
1354013558 {
1354113559 retval.setFilterExpression(filter);
1354213560 if (true) { return retval; }
1354313561 }
1354413562}
1354513563
13546- /** Shared FILTER predicate for ordinary, window, and ordered-set aggregates. */
13547- Expression AggregateFilter():
13564+ /**
13565+ * Shared FILTER predicate for ordinary, window, and ordered-set aggregates. DuckDB also accepts
13566+ * it without WHERE, FILTER (x > 1), but PostgreSQL does not.
13567+ */
13568+ Expression AggregateFilter(AnalyticExpression analyticExpression):
1354813569{ Expression filter; }
1354913570{
13550- <K_FILTER> "(" <K_WHERE> filter=Expression() ")"
13571+ <K_FILTER> "("
13572+ (
13573+ <K_WHERE>
13574+ |
13575+ LOOKAHEAD({ !Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
13576+ { analyticExpression.setFilterWhereKeyword(false); }
13577+ )
13578+ filter=Expression() ")"
1355113579 { return filter; }
1355213580}
1355313581
0 commit comments