diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index e1c0ac996d5..49fc43bf167 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -911,6 +911,7 @@ generate_base_implied_equalities_no_const(PlannerInfo *root, EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc); List *vars = pull_var_clause((Node *) cur_em->em_expr, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); add_vars_to_targetlist(root, vars, ec->ec_relids, false); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 243e41d0cde..d138728e679 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -5307,7 +5307,8 @@ prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys, * that we treat Aggrefs as if they were variables; this is * necessary when attempting to sort the output from an Agg node * for use in a WindowFunc (since grouping_planner will have - * treated the Aggrefs as variables, too). + * treated the Aggrefs as variables, too). Likewise, if we find a + * WindowFunc in a sort expression, treat it as a variable. */ Expr *sortexpr = NULL; @@ -5336,6 +5337,7 @@ prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys, sortexpr = em->em_expr; exprvars = pull_var_clause((Node *) sortexpr, PVC_INCLUDE_AGGREGATES | + PVC_INCLUDE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); foreach(k, exprvars) { diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 4cbaa5a8816..64bc8a8e597 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -147,6 +147,7 @@ build_base_rel_tlists(PlannerInfo *root, List *final_tlist) { List *tlist_vars = pull_var_clause((Node *) final_tlist, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); if (tlist_vars != NIL) @@ -156,7 +157,8 @@ build_base_rel_tlists(PlannerInfo *root, List *final_tlist) } /* - * If there's a HAVING clause, we'll need the Vars it uses, too. + * If there's a HAVING clause, we'll need the Vars it uses, too. Note + * that HAVING can contain Aggrefs but not WindowFuncs. */ if (root->parse->havingQual) { @@ -1788,6 +1790,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, { List *vars = pull_var_clause(clause, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); add_vars_to_targetlist(root, vars, relids, false); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0161acf5223..a2cd6deb612 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -3837,11 +3837,12 @@ make_group_input_target(PlannerInfo *root, List *tlist) * add them to the result tlist if not already present. (A Var used * directly as a GROUP BY item will be present already.) Note this * includes Vars used in resjunk items, so we are covering the needs of - * ORDER BY and window specifications. Vars used within Aggrefs will be - * pulled out here, too. + * ORDER BY and window specifications. Vars used within Aggrefs and + * WindowFuncs will be pulled out here, too. */ non_group_vars = pull_var_clause((Node *) non_group_cols, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); sub_tlist = add_to_flat_tlist(sub_tlist, non_group_vars); @@ -4086,10 +4087,12 @@ make_window_input_target(PlannerInfo *root, * * Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that the * Aggrefs are placed in the Agg node's tlist and not left to be computed - * at higher levels. + * at higher levels. On the other hand, we should recurse into + * WindowFuncs to make sure their input expressions are available. */ flattenable_vars = pull_var_clause((Node *) flattenable_cols, PVC_INCLUDE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); new_tlist = add_to_flat_tlist(new_tlist, flattenable_vars); diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 777b273ac17..1c8d1052c58 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -169,6 +169,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) vars = pull_var_clause((Node *) parse->returningList, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); foreach(l, vars) { diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index 5e11286ac7a..9e1c0e53333 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -221,6 +221,7 @@ find_placeholders_in_expr(PlannerInfo *root, Node *expr) */ vars = pull_var_clause(expr, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); foreach(vl, vars) { @@ -355,6 +356,7 @@ fix_placeholder_input_needed_levels(PlannerInfo *root) PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(lc); List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_INCLUDE_PLACEHOLDERS); add_vars_to_targetlist(root, vars, phinfo->ph_eval_at, false); diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index a389f42a224..292e1f4aac3 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -503,6 +503,13 @@ locate_var_of_level_walker(Node *node, * Vars within an Aggref's expression are included in the result only * when PVC_RECURSE_AGGREGATES is specified. * + * WindowFuncs are handled according to these bits in 'flags': + * PVC_INCLUDE_WINDOWFUNCS include WindowFuncs in output list + * PVC_RECURSE_WINDOWFUNCS recurse into WindowFunc arguments + * neither flag throw error if WindowFunc found + * Vars within a WindowFunc's expression are included in the result only + * when PVC_RECURSE_WINDOWFUNCS is specified. + * * PlaceHolderVars are handled according to these bits in 'flags': * PVC_INCLUDE_PLACEHOLDERS include PlaceHolderVars in output list * PVC_RECURSE_PLACEHOLDERS recurse into PlaceHolderVar arguments @@ -532,6 +539,8 @@ pull_var_clause(Node *node, int flags) /* Assert that caller has not specified inconsistent flags */ Assert((flags & (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES)) != (PVC_INCLUDE_AGGREGATES | PVC_RECURSE_AGGREGATES)); + Assert((flags & (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS)) + != (PVC_INCLUDE_WINDOWFUNCS | PVC_RECURSE_WINDOWFUNCS)); Assert((flags & (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS)) != (PVC_INCLUDE_PLACEHOLDERS | PVC_RECURSE_PLACEHOLDERS)); @@ -594,6 +603,22 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) else elog(ERROR, "GROUPING found where not expected"); } + else if (IsA(node, WindowFunc)) + { + /* WindowFuncs have no levelsup field to check ... */ + if (context->flags & PVC_INCLUDE_WINDOWFUNCS) + { + context->varlist = lappend(context->varlist, node); + /* we do NOT descend into the contained expressions */ + return false; + } + else if (context->flags & PVC_RECURSE_WINDOWFUNCS) + { + /* fall through to recurse into the windowfunc's arguments */ + } + else + elog(ERROR, "WindowFunc found where not expected"); + } else if (IsA(node, PlaceHolderVar)) { if (((PlaceHolderVar *) node)->phlevelsup != 0) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 6e75a39bf3f..d396ef142f9 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -3329,6 +3329,7 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, */ varshere = pull_var_clause(groupexpr, PVC_RECURSE_AGGREGATES | + PVC_RECURSE_WINDOWFUNCS | PVC_RECURSE_PLACEHOLDERS); /* diff --git a/src/include/optimizer/var.h b/src/include/optimizer/var.h index d1b0978b97e..463e75b8282 100644 --- a/src/include/optimizer/var.h +++ b/src/include/optimizer/var.h @@ -19,9 +19,11 @@ /* Bits that can be OR'd into the flags argument of pull_var_clause() */ #define PVC_INCLUDE_AGGREGATES 0x0001 /* include Aggrefs in output list */ #define PVC_RECURSE_AGGREGATES 0x0002 /* recurse into Aggref arguments */ -#define PVC_INCLUDE_PLACEHOLDERS 0x0004 /* include PlaceHolderVars in +#define PVC_INCLUDE_WINDOWFUNCS 0x0004 /* include WindowFuncs in output list */ +#define PVC_RECURSE_WINDOWFUNCS 0x0008 /* recurse into WindowFunc arguments */ +#define PVC_INCLUDE_PLACEHOLDERS 0x0010 /* include PlaceHolderVars in * output list */ -#define PVC_RECURSE_PLACEHOLDERS 0x0008 /* recurse into PlaceHolderVar +#define PVC_RECURSE_PLACEHOLDERS 0x0020 /* recurse into PlaceHolderVar * arguments */