Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit59a3795

Browse files
committed
Simplify planner's final setup of Aggrefs for partial aggregation.
Commite06a389's original coding for constructing the execution-timeexpression tree for a combining aggregate was rather messy, involvingduplicating quite a lot of code in setrefs.c so that it could injecta nonstandard matching rule for Aggrefs. Get rid of that in favor ofexplicitly constructing a combining Aggref with a partial Aggref as input,then allowing setref's normal matching logic to match the partial Aggrefto the output of the lower plan node and hence replace it with a Var.In passing, rename and redocument make_partialgroup_input_target to havesome connection to what it actually does.
1 parente3ad3ff commit59a3795

File tree

5 files changed

+171
-334
lines changed

5 files changed

+171
-334
lines changed

‎src/backend/optimizer/plan/planner.c

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include"access/sysattr.h"
2424
#include"access/xact.h"
2525
#include"catalog/pg_constraint_fn.h"
26+
#include"catalog/pg_type.h"
2627
#include"executor/executor.h"
2728
#include"executor/nodeAgg.h"
2829
#include"foreign/fdwapi.h"
@@ -140,8 +141,8 @@ static RelOptInfo *create_ordered_paths(PlannerInfo *root,
140141
doublelimit_tuples);
141142
staticPathTarget*make_group_input_target(PlannerInfo*root,
142143
PathTarget*final_target);
143-
staticPathTarget*make_partialgroup_input_target(PlannerInfo*root,
144-
PathTarget*final_target);
144+
staticPathTarget*make_partial_grouping_target(PlannerInfo*root,
145+
PathTarget*grouping_target);
145146
staticList*postprocess_setop_tlist(List*new_tlist,List*orig_tlist);
146147
staticList*select_active_windows(PlannerInfo*root,WindowFuncLists*wflists);
147148
staticPathTarget*make_window_input_target(PlannerInfo*root,
@@ -3456,12 +3457,13 @@ create_grouping_paths(PlannerInfo *root,
34563457
Path*cheapest_partial_path=linitial(input_rel->partial_pathlist);
34573458

34583459
/*
3459-
* Build target list for partial aggregate paths. We cannot reuse the
3460-
* final target as Aggrefs must be set in partial mode, and we must
3461-
* also include Aggrefs from the HAVING clause in the target as these
3462-
* may not be present in the final target.
3460+
* Build target list for partial aggregate paths. These paths cannot
3461+
* just emit the same tlist as regular aggregate paths, because (1) we
3462+
* must include Vars and Aggrefs needed in HAVING, which might not
3463+
* appear in the result tlist, and (2) the Aggrefs must be set in
3464+
* partial mode.
34633465
*/
3464-
partial_grouping_target=make_partialgroup_input_target(root,target);
3466+
partial_grouping_target=make_partial_grouping_target(root,target);
34653467

34663468
/* Estimate number of partial groups. */
34673469
dNumPartialGroups=get_number_of_groups(root,
@@ -4317,46 +4319,48 @@ make_group_input_target(PlannerInfo *root, PathTarget *final_target)
43174319
}
43184320

43194321
/*
4320-
* make_partialgroup_input_target
4321-
* Generate appropriate PathTarget for input for Partial Aggregate nodes.
4322+
* make_partial_grouping_target
4323+
* Generate appropriate PathTarget for output of partial aggregate
4324+
* (or partial grouping, if there are no aggregates) nodes.
43224325
*
4323-
* Similar to make_group_input_target(), only we don't recurse into Aggrefs, as
4324-
* we need these to remain intact so that they can be found later in Combine
4325-
* Aggregate nodes during set_combineagg_references(). Vars will be still
4326-
* pulled out of non-Aggref nodes as these will still be required by the
4327-
* combine aggregate phase.
4326+
* A partial aggregation node needs to emit all the same aggregates that
4327+
* a regular aggregation node would, plus any aggregates used in HAVING;
4328+
* except that the Aggref nodes should be marked as partial aggregates.
43284329
*
4329-
* We also convert any Aggrefs which we do find and put them into partial mode,
4330-
* this adjusts the Aggref's return type so that the partially calculated
4331-
* aggregate value can make its way up the execution tree up to the Finalize
4332-
* Aggregate node.
4330+
* In addition, we'd better emit any Vars and PlaceholderVars that are
4331+
* used outside of Aggrefs in the aggregation tlist and HAVING. (Presumably,
4332+
* these would be Vars that are grouped by or used in grouping expressions.)
4333+
*
4334+
* grouping_target is the tlist to be emitted by the topmost aggregation step.
4335+
* We get the HAVING clause out of *root.
43334336
*/
43344337
staticPathTarget*
4335-
make_partialgroup_input_target(PlannerInfo*root,PathTarget*final_target)
4338+
make_partial_grouping_target(PlannerInfo*root,PathTarget*grouping_target)
43364339
{
43374340
Query*parse=root->parse;
4338-
PathTarget*input_target;
4341+
PathTarget*partial_target;
43394342
List*non_group_cols;
43404343
List*non_group_exprs;
43414344
inti;
43424345
ListCell*lc;
43434346

4344-
input_target=create_empty_pathtarget();
4347+
partial_target=create_empty_pathtarget();
43454348
non_group_cols=NIL;
43464349

43474350
i=0;
4348-
foreach(lc,final_target->exprs)
4351+
foreach(lc,grouping_target->exprs)
43494352
{
43504353
Expr*expr= (Expr*)lfirst(lc);
4351-
Indexsgref=get_pathtarget_sortgroupref(final_target,i);
4354+
Indexsgref=get_pathtarget_sortgroupref(grouping_target,i);
43524355

43534356
if (sgref&&parse->groupClause&&
43544357
get_sortgroupref_clause_noerr(sgref,parse->groupClause)!=NULL)
43554358
{
43564359
/*
4357-
* It's a grouping column, so add it to the input target as-is.
4360+
* It's a grouping column, so add it to the partial_target as-is.
4361+
* (This allows the upper agg step to repeat the grouping calcs.)
43584362
*/
4359-
add_column_to_pathtarget(input_target,expr,sgref);
4363+
add_column_to_pathtarget(partial_target,expr,sgref);
43604364
}
43614365
else
43624366
{
@@ -4371,35 +4375,83 @@ make_partialgroup_input_target(PlannerInfo *root, PathTarget *final_target)
43714375
}
43724376

43734377
/*
4374-
* If there's a HAVING clause, we'll need the Aggrefs it uses, too.
4378+
* If there's a HAVING clause, we'll need theVars/Aggrefs it uses, too.
43754379
*/
43764380
if (parse->havingQual)
43774381
non_group_cols=lappend(non_group_cols,parse->havingQual);
43784382

43794383
/*
4380-
* Pull out all the Vars mentioned in non-group cols (plus HAVING), and
4381-
* add them to the input target if not already present. (A Var used
4382-
* directly as a GROUP BY item will be present already.) Note this
4383-
* includes Vars used in resjunk items, so we are covering the needs of
4384-
* ORDER BY and window specifications. Vars used within Aggrefs will be
4385-
* ignored and the Aggrefs themselves will be added to the PathTarget.
4384+
* Pull out all the Vars, PlaceHolderVars, and Aggrefs mentioned in
4385+
* non-group cols (plus HAVING), and add them to the partial_target if not
4386+
* already present. (An expression used directly as a GROUP BY item will
4387+
* be present already.) Note this includes Vars used in resjunk items, so
4388+
* we are covering the needs of ORDER BY and window specifications.
43864389
*/
43874390
non_group_exprs=pull_var_clause((Node*)non_group_cols,
43884391
PVC_INCLUDE_AGGREGATES |
43894392
PVC_RECURSE_WINDOWFUNCS |
43904393
PVC_INCLUDE_PLACEHOLDERS);
43914394

4392-
add_new_columns_to_pathtarget(input_target,non_group_exprs);
4395+
add_new_columns_to_pathtarget(partial_target,non_group_exprs);
4396+
4397+
/*
4398+
* Adjust Aggrefs to put them in partial mode. At this point all Aggrefs
4399+
* are at the top level of the target list, so we can just scan the list
4400+
* rather than recursing through the expression trees.
4401+
*/
4402+
foreach(lc,partial_target->exprs)
4403+
{
4404+
Aggref*aggref= (Aggref*)lfirst(lc);
4405+
4406+
if (IsA(aggref,Aggref))
4407+
{
4408+
Aggref*newaggref;
4409+
4410+
/*
4411+
* We shouldn't need to copy the substructure of the Aggref node,
4412+
* but flat-copy the node itself to avoid damaging other trees.
4413+
*/
4414+
newaggref=makeNode(Aggref);
4415+
memcpy(newaggref,aggref,sizeof(Aggref));
4416+
4417+
/* XXX assume serialization required */
4418+
mark_partial_aggref(newaggref, true);
4419+
4420+
lfirst(lc)=newaggref;
4421+
}
4422+
}
43934423

43944424
/* clean up cruft */
43954425
list_free(non_group_exprs);
43964426
list_free(non_group_cols);
43974427

4398-
/* Adjust Aggrefs to put them in partial mode. */
4399-
apply_partialaggref_adjustment(input_target);
4400-
44014428
/* XXX this causes some redundant cost calculation ... */
4402-
returnset_pathtarget_cost_width(root,input_target);
4429+
returnset_pathtarget_cost_width(root,partial_target);
4430+
}
4431+
4432+
/*
4433+
* mark_partial_aggref
4434+
* Adjust an Aggref to make it represent the output of partial aggregation.
4435+
*
4436+
* The Aggref node is modified in-place; caller must do any copying required.
4437+
*/
4438+
void
4439+
mark_partial_aggref(Aggref*agg,boolserialize)
4440+
{
4441+
/* aggtranstype should be computed by this point */
4442+
Assert(OidIsValid(agg->aggtranstype));
4443+
4444+
/*
4445+
* Normally, a partial aggregate returns the aggregate's transition type;
4446+
* but if that's INTERNAL and we're serializing, it returns BYTEA instead.
4447+
*/
4448+
if (agg->aggtranstype==INTERNALOID&&serialize)
4449+
agg->aggoutputtype=BYTEAOID;
4450+
else
4451+
agg->aggoutputtype=agg->aggtranstype;
4452+
4453+
/* flag it as partial */
4454+
agg->aggpartial= true;
44034455
}
44044456

44054457
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp