mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Fix improper repetition of previous results from a hashed aggregate.
ExecReScanAgg's check for whether it could re-use a previously calculated hashtable neglected the possibility that the Agg node might reference PARAM_EXEC Params that are not referenced by its input plan node. That's okay if the Params are in upper tlist or qual expressions; but if one appears in aggregate input expressions, then the hashtable contents need to be recomputed when the Param's value changes. To avoid unnecessary performance degradation in the case of a Param that isn't within an aggregate input, add logic to the planner to determine which Params are within aggregate inputs. This requires a new field in struct Agg, but fortunately we never write plans to disk, so this isn't an initdb-forcing change. Per report from Jeevan Chalke. This has been broken since forever, so back-patch to all supported branches. Andrew Gierth, with minor adjustments by me Report: <CAM2+6=VY8ykfLT5Q8vb9B6EbeBk-NGuLbT6seaQ+Fq4zXvrDcA@mail.gmail.com>
This commit is contained in:
@ -5664,6 +5664,7 @@ make_agg(List *tlist, List *qual,
|
||||
node->grpColIdx = grpColIdx;
|
||||
node->grpOperators = grpOperators;
|
||||
node->numGroups = numGroups;
|
||||
node->aggParams = NULL; /* SS_finalize_plan() will fill this */
|
||||
node->groupingSets = groupingSets;
|
||||
node->chain = chain;
|
||||
|
||||
|
@ -82,6 +82,7 @@ static Bitmapset *finalize_plan(PlannerInfo *root,
|
||||
Bitmapset *valid_params,
|
||||
Bitmapset *scan_params);
|
||||
static bool finalize_primnode(Node *node, finalize_primnode_context *context);
|
||||
static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context);
|
||||
|
||||
|
||||
/*
|
||||
@ -2652,6 +2653,29 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
|
||||
locally_added_param);
|
||||
break;
|
||||
|
||||
case T_Agg:
|
||||
{
|
||||
Agg *agg = (Agg *) plan;
|
||||
|
||||
/*
|
||||
* AGG_HASHED plans need to know which Params are referenced
|
||||
* in aggregate calls. Do a separate scan to identify them.
|
||||
*/
|
||||
if (agg->aggstrategy == AGG_HASHED)
|
||||
{
|
||||
finalize_primnode_context aggcontext;
|
||||
|
||||
aggcontext.root = root;
|
||||
aggcontext.paramids = NULL;
|
||||
finalize_agg_primnode((Node *) agg->plan.targetlist,
|
||||
&aggcontext);
|
||||
finalize_agg_primnode((Node *) agg->plan.qual,
|
||||
&aggcontext);
|
||||
agg->aggParams = aggcontext.paramids;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_WindowAgg:
|
||||
finalize_primnode(((WindowAgg *) plan)->startOffset,
|
||||
&context);
|
||||
@ -2660,7 +2684,6 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params,
|
||||
break;
|
||||
|
||||
case T_Hash:
|
||||
case T_Agg:
|
||||
case T_Material:
|
||||
case T_Sort:
|
||||
case T_Unique:
|
||||
@ -2811,6 +2834,29 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
/*
|
||||
* finalize_agg_primnode: find all Aggref nodes in the given expression tree,
|
||||
* and add IDs of all PARAM_EXEC params appearing within their aggregated
|
||||
* arguments to the result set.
|
||||
*/
|
||||
static bool
|
||||
finalize_agg_primnode(Node *node, finalize_primnode_context *context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, Aggref))
|
||||
{
|
||||
Aggref *agg = (Aggref *) node;
|
||||
|
||||
/* we should not consider the direct arguments, if any */
|
||||
finalize_primnode((Node *) agg->args, context);
|
||||
finalize_primnode((Node *) agg->aggfilter, context);
|
||||
return false; /* there can't be any Aggrefs below here */
|
||||
}
|
||||
return expression_tree_walker(node, finalize_agg_primnode,
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
/*
|
||||
* SS_make_initplan_output_param - make a Param for an initPlan's output
|
||||
*
|
||||
|
Reference in New Issue
Block a user