@@ -1659,6 +1659,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
16591659 || next.kind >= MIN_NON_RESERVED_WORD && next.kind <= MAX_NON_RESERVED_WORD;
16601660 }
16611661
1662+ /** Whether a window specification starts with the name of the window it extends. */
1663+ private boolean isBaseWindowNameAhead() {
1664+ Token token = getToken(1);
1665+ switch (token.kind) {
1666+ case K_PARTITION: case K_ORDER: case K_ROWS: case K_RANGE: case K_GROUPS:
1667+ return false;
1668+ default:
1669+ return isIdentifierishNameToken(token);
1670+ }
1671+ }
1672+
16621673 private boolean isAliasAhead() {
16631674 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
16641675 return false;
@@ -8157,6 +8168,9 @@ PlainSelect PlainSelect() #PlainSelect:
81578168 ( LOOKAHEAD(2) "," windowName = RelObjectName() <K_AS> winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )*
81588169 { plainSelect.setWindowDefinitions(winDefs); }
81598170 ]
8171+ // DuckDB: QUALIFY after WINDOW
8172+ [ LOOKAHEAD(2, { plainSelect.getQualify() == null }) qualify=Qualify()
8173+ { plainSelect.setQualify(qualify); plainSelect.setQualifyAfterWindow(true); } ]
81608174 [ LOOKAHEAD(<K_ORDER> <K_BY>) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ]
81618175 [ LOOKAHEAD(2) interpolateElements = InterpolateClause() { plainSelect.setInterpolate(interpolateElements); } ]
81628176 [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ]
@@ -13125,8 +13139,12 @@ WindowDefinition windowDefinition() : {
1312513139 WindowElement windowElement = null;
1312613140 boolean partitionByBrackets = false;
1312713141 WindowDefinition winDef = new WindowDefinition();
13142+ String baseWindowName;
1312813143} {
1312913144 "("
13145+ // DuckDB: (w ORDER BY b) extends the named window w
13146+ [ LOOKAHEAD({ isBaseWindowNameAhead() }) baseWindowName=RelObjectName()
13147+ { winDef.setBaseWindowName(baseWindowName); } ]
1313013148 [<K_PARTITION> <K_BY>
1313113149 (LOOKAHEAD(3) expressionList=ComplexExpressionList()
1313213150 | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" )
@@ -13150,7 +13168,7 @@ AnalyticExpression AnalyticExpression(Function function) :
1315013168{
1315113169 (
1315213170 (
13153- filter=AggregateFilter() { retval.setType(AnalyticType.FILTER_ONLY); }
13171+ filter=AggregateFilter(retval ) { retval.setType(AnalyticType.FILTER_ONLY); }
1315413172 [ LOOKAHEAD(2) windowFun(retval) ]
1315513173 {
1315613174 if (Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
@@ -13162,19 +13180,29 @@ AnalyticExpression AnalyticExpression(Function function) :
1316213180 )
1316313181 | windowFun(retval)
1316413182 [ LOOKAHEAD({ retval.getType() == AnalyticType.WITHIN_GROUP
13165- && getToken(1).kind == K_FILTER }) filter=AggregateFilter() ]
13183+ && getToken(1).kind == K_FILTER }) filter=AggregateFilter(retval ) ]
1316613184 )
1316713185 {
1316813186 retval.setFilterExpression(filter);
1316913187 if (true) { return retval; }
1317013188 }
1317113189}
1317213190
13173- /** Shared FILTER predicate for ordinary, window, and ordered-set aggregates. */
13174- Expression AggregateFilter():
13191+ /**
13192+ * Shared FILTER predicate for ordinary, window, and ordered-set aggregates. DuckDB also accepts
13193+ * it without WHERE, FILTER (x > 1), but PostgreSQL does not.
13194+ */
13195+ Expression AggregateFilter(AnalyticExpression analyticExpression):
1317513196{ Expression filter; }
1317613197{
13177- <K_FILTER> "(" <K_WHERE> filter=Expression() ")"
13198+ <K_FILTER> "("
13199+ (
13200+ <K_WHERE>
13201+ |
13202+ LOOKAHEAD({ !Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
13203+ { analyticExpression.setFilterWhereKeyword(false); }
13204+ )
13205+ filter=Expression() ")"
1317813206 { return filter; }
1317913207}
1318013208
0 commit comments