if (IsA(node, Aggref))
{
Aggref *aggref = (Aggref *) node;
+ Param *aggparam;
/* See if the Aggref should be replaced by a Param */
- if (context->root->minmax_aggs != NIL &&
- list_length(aggref->args) == 1)
+ aggparam = find_minmax_agg_replacement_param(context->root, aggref);
+ if (aggparam != NULL)
{
- TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
- ListCell *lc;
-
- foreach(lc, context->root->minmax_aggs)
- {
- MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
-
- if (mminfo->aggfnoid == aggref->aggfnoid &&
- equal(mminfo->target, curTarget->expr))
- return (Node *) copyObject(mminfo->param);
- }
+ /* Make a copy of the Param for paranoia's sake */
+ return (Node *) copyObject(aggparam);
}
/* If no match, just fall through to process it normally */
}
if (IsA(node, Aggref))
{
Aggref *aggref = (Aggref *) node;
+ Param *aggparam;
/* See if the Aggref should be replaced by a Param */
- if (context->root->minmax_aggs != NIL &&
- list_length(aggref->args) == 1)
+ aggparam = find_minmax_agg_replacement_param(context->root, aggref);
+ if (aggparam != NULL)
{
- TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
- ListCell *lc;
-
- foreach(lc, context->root->minmax_aggs)
- {
- MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
-
- if (mminfo->aggfnoid == aggref->aggfnoid &&
- equal(mminfo->target, curTarget->expr))
- return (Node *) copyObject(mminfo->param);
- }
+ /* Make a copy of the Param for paranoia's sake */
+ return (Node *) copyObject(aggparam);
}
/* If no match, just fall through to process it normally */
}
return newlist;
}
+/*
+ * find_minmax_agg_replacement_param
+ * If the given Aggref is one that we are optimizing into a subquery
+ * (cf. planagg.c), then return the Param that should replace it.
+ * Else return NULL.
+ *
+ * This is exported so that SS_finalize_plan can use it before setrefs.c runs.
+ * Note that it will not find anything until we have built a Plan from a
+ * MinMaxAggPath, as root->minmax_aggs will never be filled otherwise.
+ */
+Param *
+find_minmax_agg_replacement_param(PlannerInfo *root, Aggref *aggref)
+{
+ if (root->minmax_aggs != NIL &&
+ list_length(aggref->args) == 1)
+ {
+ TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args);
+ ListCell *lc;
+
+ foreach(lc, root->minmax_aggs)
+ {
+ MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
+
+ if (mminfo->aggfnoid == aggref->aggfnoid &&
+ equal(mminfo->target, curTarget->expr))
+ return mminfo->param;
+ }
+ }
+ return NULL;
+}
+
+
/*****************************************************************************
* QUERY DEPENDENCY MANAGEMENT
*****************************************************************************/
}
/*
- * finalize_primnode: add IDs of all PARAM_EXEC params appearing in the given
- * expression tree to the result set.
+ * finalize_primnode: add IDs of all PARAM_EXEC params that appear (or will
+ * appear) in the given expression tree to the result set.
*/
static bool
finalize_primnode(Node *node, finalize_primnode_context *context)
}
return false; /* no more to do here */
}
- if (IsA(node, SubPlan))
+ else if (IsA(node, Aggref))
+ {
+ /*
+ * Check to see if the aggregate will be replaced by a Param
+ * referencing a subquery output during setrefs.c. If so, we must
+ * account for that Param here. (For various reasons, it's not
+ * convenient to perform that substitution earlier than setrefs.c, nor
+ * to perform this processing after setrefs.c. Thus we need a wart
+ * here.)
+ */
+ Aggref *aggref = (Aggref *) node;
+ Param *aggparam;
+
+ aggparam = find_minmax_agg_replacement_param(context->root, aggref);
+ if (aggparam != NULL)
+ context->paramids = bms_add_member(context->paramids,
+ aggparam->paramid);
+ /* Fall through to examine the agg's arguments */
+ }
+ else if (IsA(node, SubPlan))
{
SubPlan *subplan = (SubPlan *) node;
Plan *plan = planner_subplan_get_plan(context->root, subplan);