@@ -1603,6 +1603,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
16031603 || next.kind >= MIN_NON_RESERVED_WORD && next.kind <= MAX_NON_RESERVED_WORD;
16041604 }
16051605
1606+ /** Whether a window specification starts with the name of the window it extends. */
1607+ private boolean isBaseWindowNameAhead() {
1608+ Token token = getToken(1);
1609+ switch (token.kind) {
1610+ case K_PARTITION: case K_ORDER: case K_ROWS: case K_RANGE: case K_GROUPS:
1611+ return false;
1612+ default:
1613+ return isIdentifierishNameToken(token);
1614+ }
1615+ }
1616+
16061617 private boolean isAliasAhead() {
16071618 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
16081619 return false;
@@ -8094,6 +8105,9 @@ PlainSelect PlainSelect() #PlainSelect:
80948105 ( LOOKAHEAD(2) "," windowName = RelObjectName() <K_AS> winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )*
80958106 { plainSelect.setWindowDefinitions(winDefs); }
80968107 ]
8108+ // DuckDB: QUALIFY after WINDOW
8109+ [ LOOKAHEAD(2, { plainSelect.getQualify() == null }) qualify=Qualify()
8110+ { plainSelect.setQualify(qualify); plainSelect.setQualifyAfterWindow(true); } ]
80978111 [ LOOKAHEAD(<K_ORDER> <K_BY>) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ]
80988112 [ LOOKAHEAD(2) interpolateElements = InterpolateClause() { plainSelect.setInterpolate(interpolateElements); } ]
80998113 [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ]
@@ -13035,8 +13049,12 @@ WindowDefinition windowDefinition() : {
1303513049 WindowElement windowElement = null;
1303613050 boolean partitionByBrackets = false;
1303713051 WindowDefinition winDef = new WindowDefinition();
13052+ String baseWindowName;
1303813053} {
1303913054 "("
13055+ // DuckDB: (w ORDER BY b) extends the named window w
13056+ [ LOOKAHEAD({ isBaseWindowNameAhead() }) baseWindowName=RelObjectName()
13057+ { winDef.setBaseWindowName(baseWindowName); } ]
1304013058 [<K_PARTITION> <K_BY>
1304113059 (LOOKAHEAD(3) expressionList=ComplexExpressionList()
1304213060 | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" )
@@ -13060,7 +13078,7 @@ AnalyticExpression AnalyticExpression(Function function) :
1306013078{
1306113079 (
1306213080 (
13063- filter=AggregateFilter() { retval.setType(AnalyticType.FILTER_ONLY); }
13081+ filter=AggregateFilter(retval ) { retval.setType(AnalyticType.FILTER_ONLY); }
1306413082 [ LOOKAHEAD(2) windowFun(retval) ]
1306513083 {
1306613084 if (Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
@@ -13072,19 +13090,29 @@ AnalyticExpression AnalyticExpression(Function function) :
1307213090 )
1307313091 | windowFun(retval)
1307413092 [ LOOKAHEAD({ retval.getType() == AnalyticType.WITHIN_GROUP
13075- && getToken(1).kind == K_FILTER }) filter=AggregateFilter() ]
13093+ && getToken(1).kind == K_FILTER }) filter=AggregateFilter(retval ) ]
1307613094 )
1307713095 {
1307813096 retval.setFilterExpression(filter);
1307913097 if (true) { return retval; }
1308013098 }
1308113099}
1308213100
13083- /** Shared FILTER predicate for ordinary, window, and ordered-set aggregates. */
13084- Expression AggregateFilter():
13101+ /**
13102+ * Shared FILTER predicate for ordinary, window, and ordered-set aggregates. DuckDB also accepts
13103+ * it without WHERE, FILTER (x > 1), but PostgreSQL does not.
13104+ */
13105+ Expression AggregateFilter(AnalyticExpression analyticExpression):
1308513106{ Expression filter; }
1308613107{
13087- <K_FILTER> "(" <K_WHERE> filter=Expression() ")"
13108+ <K_FILTER> "("
13109+ (
13110+ <K_WHERE>
13111+ |
13112+ LOOKAHEAD({ !Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
13113+ { analyticExpression.setFilterWhereKeyword(false); }
13114+ )
13115+ filter=Expression() ")"
1308813116 { return filter; }
1308913117}
1309013118
0 commit comments