diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 5777cb2..3334b91 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -94,6 +94,8 @@ static void compare_tlist_datatypes(List *tlist, List *colTypes, bool *unsafeColumns); static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, bool *unsafeColumns); +static bool var_exists_in_all_query_partition_by_clauses(Query *subquery, + Var *var); static void subquery_push_qual(Query *subquery, RangeTblEntry *rte, Index rti, Node *qual); static void recurse_push_qual(Node *setOp, Query *topquery, @@ -1664,10 +1666,7 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels) * 1. If the subquery has a LIMIT clause, we must not push down any quals, * since that could change the set of rows returned. * - * 2. If the subquery contains any window functions, we can't push quals - * into it, because that could change the results. - * - * 3. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push + * 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push * quals into it, because that could change the results. * * In addition, we make several checks on the subquery's output columns @@ -1690,10 +1689,6 @@ subquery_is_pushdown_safe(Query *subquery, Query *topquery, if (subquery->limitOffset != NULL || subquery->limitCount != NULL) return false; - /* Check point 2 */ - if (subquery->hasWindowFuncs) - return false; - /* * If we're at a leaf query, check for unsafe expressions in its target * list, and mark any unsafe ones in unsafeColumns[]. (Non-leaf nodes in @@ -1888,6 +1883,10 @@ compare_tlist_datatypes(List *tlist, List *colTypes, * * 3. The qual must not refer to any subquery output columns that were * found to be unsafe to reference by subquery_is_pushdown_safe(). + * + * 4. If the subquery contains window functions then the qual may be + * pushed down if it is part of the PARTITION BY in every window frame + * that is defined in the subquery. */ static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, @@ -1948,6 +1947,13 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, safe = false; break; } + + if (subquery->hasWindowFuncs && + !var_exists_in_all_query_partition_by_clauses(subquery, var)) + { + safe = false; + break; + } } list_free(vars); @@ -1956,6 +1962,24 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, } /* + * var_exists_in_all_query_partition_by_clauses + * returns true if the given Var exists in the PARTITION BY clause in every + * WINDOW defined in the subquery + */ +static bool var_exists_in_all_query_partition_by_clauses(Query *subquery, Var *var) +{ + ListCell *lc; + TargetEntry *tle = get_tle_by_resno(subquery->targetList, var->varattno); + + foreach(lc, subquery->windowClause) + { + WindowClause *wc = (WindowClause *) lfirst(lc); + if (!targetIsInSortList(tle, InvalidOid, wc->partitionClause)) + return false; + } + return true; +} +/* * subquery_push_qual - push down a qual that we have determined is safe */ static void