@@ -1689,6 +1689,17 @@ public class CCJSqlParser extends AbstractJSqlParser<CCJSqlParser> {
16891689 return ":".equals(token.image) || "]".equals(token.image) || ",".equals(token.image);
16901690 }
16911691
1692+ /** Whether a window specification starts with the name of the window it extends. */
1693+ private boolean isBaseWindowNameAhead() {
1694+ Token token = getToken(1);
1695+ switch (token.kind) {
1696+ case K_PARTITION: case K_ORDER: case K_ROWS: case K_RANGE: case K_GROUPS:
1697+ return false;
1698+ default:
1699+ return isIdentifierishNameToken(token);
1700+ }
1701+ }
1702+
16921703 private boolean isAliasAhead() {
16931704 if (isAsOfJoinAhead() || isSemiAntiJoinAhead() || isApproxNearestAhead()) {
16941705 return false;
@@ -8193,6 +8204,9 @@ PlainSelect PlainSelect() #PlainSelect:
81938204 ( LOOKAHEAD(2) "," windowName = RelObjectName() <K_AS> winDef = windowDefinition() { winDefs.add(winDef.withWindowName(windowName)); } )*
81948205 { plainSelect.setWindowDefinitions(winDefs); }
81958206 ]
8207+ // DuckDB: QUALIFY after WINDOW
8208+ [ LOOKAHEAD(2, { plainSelect.getQualify() == null }) qualify=Qualify()
8209+ { plainSelect.setQualify(qualify); plainSelect.setQualifyAfterWindow(true); } ]
81968210 [ LOOKAHEAD(<K_ORDER> <K_BY>) orderByElements = OrderByElements() { plainSelect.setOrderByElements(orderByElements); } ]
81978211 [ LOOKAHEAD(2) interpolateElements = InterpolateClause() { plainSelect.setInterpolate(interpolateElements); } ]
81988212 [ LOOKAHEAD(2) forClause = ForClause() {plainSelect.setForClause(forClause);} ]
@@ -13217,8 +13231,12 @@ WindowDefinition windowDefinition() : {
1321713231 WindowElement windowElement = null;
1321813232 boolean partitionByBrackets = false;
1321913233 WindowDefinition winDef = new WindowDefinition();
13234+ String baseWindowName;
1322013235} {
1322113236 "("
13237+ // DuckDB: (w ORDER BY b) extends the named window w
13238+ [ LOOKAHEAD({ isBaseWindowNameAhead() }) baseWindowName=RelObjectName()
13239+ { winDef.setBaseWindowName(baseWindowName); } ]
1322213240 [<K_PARTITION> <K_BY>
1322313241 (LOOKAHEAD(3) expressionList=ComplexExpressionList()
1322413242 | "(" {partitionByBrackets = true;} expressionList=ComplexExpressionList() ")" )
@@ -13242,7 +13260,7 @@ AnalyticExpression AnalyticExpression(Function function) :
1324213260{
1324313261 (
1324413262 (
13245- filter=AggregateFilter() { retval.setType(AnalyticType.FILTER_ONLY); }
13263+ filter=AggregateFilter(retval ) { retval.setType(AnalyticType.FILTER_ONLY); }
1324613264 [ LOOKAHEAD(2) windowFun(retval) ]
1324713265 {
1324813266 if (Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect))
@@ -13254,19 +13272,29 @@ AnalyticExpression AnalyticExpression(Function function) :
1325413272 )
1325513273 | windowFun(retval)
1325613274 [ LOOKAHEAD({ retval.getType() == AnalyticType.WITHIN_GROUP
13257- && getToken(1).kind == K_FILTER }) filter=AggregateFilter() ]
13275+ && getToken(1).kind == K_FILTER }) filter=AggregateFilter(retval ) ]
1325813276 )
1325913277 {
1326013278 retval.setFilterExpression(filter);
1326113279 if (true) { return retval; }
1326213280 }
1326313281}
1326413282
13265- /** Shared FILTER predicate for ordinary, window, and ordered-set aggregates. */
13266- Expression AggregateFilter():
13283+ /**
13284+ * Shared FILTER predicate for ordinary, window, and ordered-set aggregates. DuckDB also accepts
13285+ * it without WHERE, FILTER (x > 1), but PostgreSQL does not.
13286+ */
13287+ Expression AggregateFilter(AnalyticExpression analyticExpression):
1326713288{ Expression filter; }
1326813289{
13269- <K_FILTER> "(" <K_WHERE> filter=Expression() ")"
13290+ <K_FILTER> "("
13291+ (
13292+ <K_WHERE>
13293+ |
13294+ LOOKAHEAD({ !Dialect.POSTGRESQL.name().equals(getAsString(Feature.dialect)) })
13295+ { analyticExpression.setFilterWhereKeyword(false); }
13296+ )
13297+ filter=Expression() ")"
1327013298 { return filter; }
1327113299}
1327213300
0 commit comments