@@ -1650,6 +1650,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
16501650 || next.kind >= MIN_NON_RESERVED_WORD && next.kind <= MAX_NON_RESERVED_WORD;
16511651 }
16521652
1653+ /** Whether a window specification starts with the name of the window it extends. */
1654+ private boolean isBaseWindowNameAhead() {
1655+ Token token = getToken(1);
1656+ switch (token.kind) {
1657+ case K_PARTITION: case K_ORDER: case K_ROWS: case K_RANGE: case K_GROUPS:
1658+ return false;
1659+ default:
1660+ return isIdentifierishNameToken(token);
1661+ }
1662+ }
1663+
16531664 private boolean isAliasAhead() {
16541665 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
16551666 return false;
@@ -8146,6 +8157,9 @@ PlainSelect PlainSelect() #PlainSelect:
81468157 ( LOOKAHEAD(2) "," windowName = RelObjectName() <K_AS> winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )*
81478158 { plainSelect.setWindowDefinitions(winDefs); }
81488159 ]
8160+ // DuckDB: QUALIFY after WINDOW
8161+ [ LOOKAHEAD(2, { plainSelect.getQualify() == null }) qualify=Qualify()
8162+ { plainSelect.setQualify(qualify); plainSelect.setQualifyAfterWindow(true); } ]
81498163 [ LOOKAHEAD(<K_ORDER> <K_BY>) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ]
81508164 [ LOOKAHEAD(2) interpolateElements = InterpolateClause() { plainSelect.setInterpolate(interpolateElements); } ]
81518165 [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ]
@@ -13098,8 +13112,12 @@ WindowDefinition windowDefinition() : {
1309813112 WindowElement windowElement = null;
1309913113 boolean partitionByBrackets = false;
1310013114 WindowDefinition winDef = new WindowDefinition();
13115+ String baseWindowName;
1310113116} {
1310213117 "("
13118+ // DuckDB: (w ORDER BY b) extends the named window w
13119+ [ LOOKAHEAD({ isBaseWindowNameAhead() }) baseWindowName=RelObjectName()
13120+ { winDef.setBaseWindowName(baseWindowName); } ]
1310313121 [<K_PARTITION> <K_BY>
1310413122 (LOOKAHEAD(3) expressionList=ComplexExpressionList()
1310513123 | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" )
@@ -13123,7 +13141,7 @@ AnalyticExpression AnalyticExpression(Function function) :
1312313141{
1312413142 (
1312513143 (
13126- filter=AggregateFilter() { retval.setType(AnalyticType.FILTER_ONLY); }
13144+ filter=AggregateFilter(retval ) { retval.setType(AnalyticType.FILTER_ONLY); }
1312713145 [ LOOKAHEAD(2) windowFun(retval) ]
1312813146 {
1312913147 if (Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
@@ -13135,19 +13153,29 @@ AnalyticExpression AnalyticExpression(Function function) :
1313513153 )
1313613154 | windowFun(retval)
1313713155 [ LOOKAHEAD({ retval.getType() == AnalyticType.WITHIN_GROUP
13138- && getToken(1).kind == K_FILTER }) filter=AggregateFilter() ]
13156+ && getToken(1).kind == K_FILTER }) filter=AggregateFilter(retval ) ]
1313913157 )
1314013158 {
1314113159 retval.setFilterExpression(filter);
1314213160 if (true) { return retval; }
1314313161 }
1314413162}
1314513163
13146- /** Shared FILTER predicate for ordinary, window, and ordered-set aggregates. */
13147- Expression AggregateFilter():
13164+ /**
13165+ * Shared FILTER predicate for ordinary, window, and ordered-set aggregates. DuckDB also accepts
13166+ * it without WHERE, FILTER (x > 1), but PostgreSQL does not.
13167+ */
13168+ Expression AggregateFilter(AnalyticExpression analyticExpression):
1314813169{ Expression filter; }
1314913170{
13150- <K_FILTER> "(" <K_WHERE> filter=Expression() ")"
13171+ <K_FILTER> "("
13172+ (
13173+ <K_WHERE>
13174+ |
13175+ LOOKAHEAD({ !Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
13176+ { analyticExpression.setFilterWhereKeyword(false); }
13177+ )
13178+ filter=Expression() ")"
1315113179 { return filter; }
1315213180}
1315313181
0 commit comments