diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 63fae82..6f6ccdc 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -695,6 +695,9 @@ _outAgg(StringInfo str, const Agg *node) for (i = 0; i < node->numCols; i++) appendStringInfo(str, " %d", node->grpColIdx[i]); + WRITE_BOOL_FIELD(combineStates); + WRITE_BOOL_FIELD(finalizeAggs); + appendStringInfoString(str, " :grpOperators"); for (i = 0; i < node->numCols; i++) appendStringInfo(str, " %u", node->grpOperators[i]); diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index d2232c2..0a2baec 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -140,6 +140,14 @@ static bool fix_opfuncids_walker(Node *node, void *context); static bool extract_query_dependencies_walker(Node *node, PlannerInfo *context); +static void set_agg_references(PlannerInfo *root, Plan *plan, int rtoffset); +static Node *fix_combine_agg_expr(PlannerInfo *root, + Node *node, + indexed_tlist *subplan_itlist, + Index newvarno, + int rtoffset); +static Node * fix_combine_agg_expr_mutator(Node *node, fix_upper_expr_context *context); + /***************************************************************************** * * SUBPLAN REFERENCES @@ -668,7 +676,7 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } break; case T_Agg: - set_upper_references(root, plan, rtoffset); + set_agg_references(root, plan, rtoffset); break; case T_Group: set_upper_references(root, plan, rtoffset); @@ -2431,3 +2439,212 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context) return expression_tree_walker(node, extract_query_dependencies_walker, (void *) context); } + + +/* + * set_agg_references + * Update the targetlist and quals of an upper-level plan node + * to refer to the tuples returned by its lefttree subplan. + * Also perform opcode lookup for these expressions, and + * add regclass OIDs to root->glob->relationOids. + * + * This is used for single-input plan types like Agg, Group, Result. + * + * In most cases, we have to match up individual Vars in the tlist and + * qual expressions with elements of the subplan's tlist (which was + * generated by flatten_tlist() from these selfsame expressions, so it + * should have all the required variables). There is an important exception, + * however: GROUP BY and ORDER BY expressions will have been pushed into the + * subplan tlist unflattened. If these values are also needed in the output + * then we want to reference the subplan tlist element rather than recomputing + * the expression. + */ +static void +set_agg_references(PlannerInfo *root, Plan *plan, int rtoffset) +{ + Agg *agg = (Agg*)plan; + Plan *subplan = plan->lefttree; + indexed_tlist *subplan_itlist; + List *output_targetlist; + ListCell *l; + + subplan_itlist = build_tlist_index(subplan->targetlist); + + output_targetlist = NIL; + + if(agg->combineStates) + { + foreach(l, plan->targetlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(l); + Node *newexpr; + + /* If it's a non-Var sort/group item, first try to match by sortref */ + if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var)) + { + newexpr = (Node *) + search_indexed_tlist_for_sortgroupref((Node *) tle->expr, + tle->ressortgroupref, + subplan_itlist, + OUTER_VAR); + if (!newexpr) + newexpr = fix_combine_agg_expr(root, + (Node *) tle->expr, + subplan_itlist, + OUTER_VAR, + rtoffset); + } + else + newexpr = fix_combine_agg_expr(root, + (Node *) tle->expr, + subplan_itlist, + OUTER_VAR, + rtoffset); + tle = flatCopyTargetEntry(tle); + tle->expr = (Expr *) newexpr; + output_targetlist = lappend(output_targetlist, tle); + } + } + else + { + foreach(l, plan->targetlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(l); + Node *newexpr; + + /* If it's a non-Var sort/group item, first try to match by sortref */ + if (tle->ressortgroupref != 0 && !IsA(tle->expr, Var)) + { + newexpr = (Node *) + search_indexed_tlist_for_sortgroupref((Node *) tle->expr, + tle->ressortgroupref, + subplan_itlist, + OUTER_VAR); + if (!newexpr) + newexpr = fix_upper_expr(root, + (Node *) tle->expr, + subplan_itlist, + OUTER_VAR, + rtoffset); + } + else + newexpr = fix_upper_expr(root, + (Node *) tle->expr, + subplan_itlist, + OUTER_VAR, + rtoffset); + tle = flatCopyTargetEntry(tle); + tle->expr = (Expr *) newexpr; + output_targetlist = lappend(output_targetlist, tle); + } + } + + plan->targetlist = output_targetlist; + + plan->qual = (List *) + fix_upper_expr(root, + (Node *) plan->qual, + subplan_itlist, + OUTER_VAR, + rtoffset); + + pfree(subplan_itlist); +} + + +/* + * This function is only used by combineAgg to set the Var nodes as args of + * Aggref reference output of a Gather plan. + */ +static Node * +fix_combine_agg_expr(PlannerInfo *root, + Node *node, + indexed_tlist *subplan_itlist, + Index newvarno, + int rtoffset) +{ + fix_upper_expr_context context; + + context.root = root; + context.subplan_itlist = subplan_itlist; + context.newvarno = newvarno; + context.rtoffset = rtoffset; + return fix_combine_agg_expr_mutator(node, &context); +} + +static Node * +fix_combine_agg_expr_mutator(Node *node, fix_upper_expr_context *context) +{ + Var *newvar; + + if (node == NULL) + return NULL; + if (IsA(node, Var)) + { + Var *var = (Var *) node; + + newvar = search_indexed_tlist_for_var(var, + context->subplan_itlist, + context->newvarno, + context->rtoffset); + if (!newvar) + elog(ERROR, "variable not found in subplan target list"); + return (Node *) newvar; + } + if (IsA(node, Aggref)) + { + TargetEntry *tle; + Aggref *aggref = (Aggref*)node; + List *args = NIL; + + tle = tlist_member(node, context->subplan_itlist->tlist); + if (tle) + { + /* Found a matching subplan output expression */ + Var *newvar; + TargetEntry *newtle; + + newvar = makeVarFromTargetEntry(context->newvarno, tle); + newvar->varnoold = 0; /* wasn't ever a plain Var */ + newvar->varoattno = 0; + + /* update the args in the aggref */ + + /* makeTargetEntry ,always set resno to one for finialize agg */ + newtle = makeTargetEntry((Expr*)newvar,1,NULL,false); + args = lappend(args,newtle); + + /* + * Updated the args, let the newvar refer to the right position of + * the agg function in the subplan + */ + aggref->args = args; + + return (Node *) aggref; + } + } + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + + /* See if the PlaceHolderVar has bubbled up from a lower plan node */ + if (context->subplan_itlist->has_ph_vars) + { + newvar = search_indexed_tlist_for_non_var((Node *) phv, + context->subplan_itlist, + context->newvarno); + if (newvar) + return (Node *) newvar; + } + /* If not supplied by input plan, evaluate the contained expr */ + return fix_upper_expr_mutator((Node *) phv->phexpr, context); + } + if (IsA(node, Param)) + return fix_param_node(context->root, (Param *) node); + + fix_expr_common(context->root, node); + return expression_tree_mutator(node, + fix_combine_agg_expr_mutator, + (void *) context); +} +