Skip to content

Commit 49635d7

Browse files
committed
Minor additional refactoring of planner.c's PathTarget handling.
Teach make_group_input_target() and make_window_input_target() to work entirely with the PathTarget representation of tlists, rather than constructing a tlist and immediately deconstructing it into PathTarget format. In itself this only saves a few palloc's; the bigger picture is that it opens the door for sharing cost_qual_eval work across all of planner.c's constructions of PathTargets. I'll come back to that later. In support of this, flesh out tlist.c's infrastructure for PathTargets a bit more.
1 parent 92f03fe commit 49635d7

File tree

3 files changed

+111
-64
lines changed

3 files changed

+111
-64
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,13 @@ static RelOptInfo *create_distinct_paths(PlannerInfo *root,
128128
static RelOptInfo *create_ordered_paths(PlannerInfo *root,
129129
RelOptInfo *input_rel,
130130
double limit_tuples);
131-
static PathTarget *make_group_input_target(PlannerInfo *root, List *tlist);
131+
static PathTarget *make_group_input_target(PlannerInfo *root,
132+
PathTarget *final_target);
132133
static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
133134
static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists);
134135
static PathTarget *make_window_input_target(PlannerInfo *root,
135-
List *tlist, List *activeWindows);
136+
PathTarget *final_target,
137+
List *activeWindows);
136138
static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc,
137139
List *tlist);
138140

@@ -1664,7 +1666,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
16641666
*/
16651667
if (activeWindows)
16661668
grouping_target = make_window_input_target(root,
1667-
tlist,
1669+
final_target,
16681670
activeWindows);
16691671
else
16701672
grouping_target = final_target;
@@ -1678,7 +1680,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
16781680
have_grouping = (parse->groupClause || parse->groupingSets ||
16791681
parse->hasAggs || root->hasHavingQual);
16801682
if (have_grouping)
1681-
scanjoin_target = make_group_input_target(root, tlist);
1683+
scanjoin_target = make_group_input_target(root, final_target);
16821684
else
16831685
scanjoin_target = grouping_target;
16841686

@@ -3758,10 +3760,10 @@ create_ordered_paths(PlannerInfo *root,
37583760
*
37593761
* If there is grouping or aggregation, the scan/join subplan cannot emit
37603762
* the query's final targetlist; for example, it certainly can't emit any
3761-
* aggregate function calls. This routine generates the correct target list
3763+
* aggregate function calls. This routine generates the correct target
37623764
* for the scan/join subplan.
37633765
*
3764-
* The initial target list passed from the parser already contains entries
3766+
* The query target list passed from the parser already contains entries
37653767
* for all ORDER BY and GROUP BY expressions, but it will not have entries
37663768
* for variables used only in HAVING clauses; so we need to add those
37673769
* variables to the subplan target list. Also, we flatten all expressions
@@ -3774,56 +3776,52 @@ create_ordered_paths(PlannerInfo *root,
37743776
* where the a+b target will be used by the Sort/Group steps, and the
37753777
* other targets will be used for computing the final results.
37763778
*
3777-
* 'tlist' is the query's final target list.
3779+
* 'final_target' is the query's final target list (in PathTarget form)
37783780
*
37793781
* The result is the PathTarget to be computed by the Paths returned from
37803782
* query_planner().
37813783
*/
37823784
static PathTarget *
3783-
make_group_input_target(PlannerInfo *root, List *tlist)
3785+
make_group_input_target(PlannerInfo *root, PathTarget *final_target)
37843786
{
37853787
Query *parse = root->parse;
3786-
List *sub_tlist;
3788+
PathTarget *input_target;
37873789
List *non_group_cols;
37883790
List *non_group_vars;
3789-
ListCell *tl;
3791+
int i;
3792+
ListCell *lc;
37903793

37913794
/*
3792-
* We must build a tlist containing all grouping columns, plus any other
3793-
* Vars mentioned in the targetlist and HAVING qual.
3795+
* We must build a target containing all grouping columns, plus any other
3796+
* Vars mentioned in the query's targetlist and HAVING qual.
37943797
*/
3795-
sub_tlist = NIL;
3798+
input_target = create_empty_pathtarget();
37963799
non_group_cols = NIL;
37973800

3798-
foreach(tl, tlist)
3801+
i = 0;
3802+
foreach(lc, final_target->exprs)
37993803
{
3800-
TargetEntry *tle = (TargetEntry *) lfirst(tl);
3804+
Expr *expr = (Expr *) lfirst(lc);
3805+
Index sgref = final_target->sortgrouprefs[i];
38013806

3802-
if (tle->ressortgroupref && parse->groupClause &&
3803-
get_sortgroupref_clause_noerr(tle->ressortgroupref,
3804-
parse->groupClause) != NULL)
3807+
if (sgref && parse->groupClause &&
3808+
get_sortgroupref_clause_noerr(sgref, parse->groupClause) != NULL)
38053809
{
38063810
/*
3807-
* It's a grouping column, so add it to the result tlist as-is.
3811+
* It's a grouping column, so add it to the input target as-is.
38083812
*/
3809-
TargetEntry *newtle;
3810-
3811-
newtle = makeTargetEntry(tle->expr,
3812-
list_length(sub_tlist) + 1,
3813-
NULL,
3814-
false);
3815-
newtle->ressortgroupref = tle->ressortgroupref;
3816-
sub_tlist = lappend(sub_tlist, newtle);
3813+
add_column_to_pathtarget(input_target, expr, sgref);
38173814
}
38183815
else
38193816
{
38203817
/*
38213818
* Non-grouping column, so just remember the expression for later
3822-
* call to pull_var_clause. There's no need for pull_var_clause
3823-
* to examine the TargetEntry node itself.
3819+
* call to pull_var_clause.
38243820
*/
3825-
non_group_cols = lappend(non_group_cols, tle->expr);
3821+
non_group_cols = lappend(non_group_cols, expr);
38263822
}
3823+
3824+
i++;
38273825
}
38283826

38293827
/*
@@ -3834,7 +3832,7 @@ make_group_input_target(PlannerInfo *root, List *tlist)
38343832

38353833
/*
38363834
* Pull out all the Vars mentioned in non-group cols (plus HAVING), and
3837-
* add them to the result tlist if not already present. (A Var used
3835+
* add them to the input target if not already present. (A Var used
38383836
* directly as a GROUP BY item will be present already.) Note this
38393837
* includes Vars used in resjunk items, so we are covering the needs of
38403838
* ORDER BY and window specifications. Vars used within Aggrefs and
@@ -3844,13 +3842,14 @@ make_group_input_target(PlannerInfo *root, List *tlist)
38443842
PVC_RECURSE_AGGREGATES |
38453843
PVC_RECURSE_WINDOWFUNCS |
38463844
PVC_INCLUDE_PLACEHOLDERS);
3847-
sub_tlist = add_to_flat_tlist(sub_tlist, non_group_vars);
3845+
add_new_columns_to_pathtarget(input_target, non_group_vars);
38483846

38493847
/* clean up cruft */
38503848
list_free(non_group_vars);
38513849
list_free(non_group_cols);
38523850

3853-
return create_pathtarget(root, sub_tlist);
3851+
/* XXX this causes some redundant cost calculation ... */
3852+
return set_pathtarget_cost_width(root, input_target);
38543853
}
38553854

38563855
/*
@@ -3964,13 +3963,13 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
39643963
* make_window_input_target
39653964
* Generate appropriate PathTarget for initial input to WindowAgg nodes.
39663965
*
3967-
* When the query has window functions, this function computes the initial
3968-
* target list to be computed by the node just below the first WindowAgg.
3966+
* When the query has window functions, this function computes the desired
3967+
* target to be computed by the node just below the first WindowAgg.
39693968
* This tlist must contain all values needed to evaluate the window functions,
39703969
* compute the final target list, and perform any required final sort step.
39713970
* If multiple WindowAggs are needed, each intermediate one adds its window
3972-
* function results onto this tlist; only the topmost WindowAgg computes the
3973-
* actual desired target list.
3971+
* function results onto this base tlist; only the topmost WindowAgg computes
3972+
* the actual desired target list.
39743973
*
39753974
* This function is much like make_group_input_target, though not quite enough
39763975
* like it to share code. As in that function, we flatten most expressions
@@ -3986,7 +3985,7 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
39863985
* flatten Aggref expressions, since those are to be computed below the
39873986
* window functions and just referenced like Vars above that.
39883987
*
3989-
* 'tlist' is the query's final target list.
3988+
* 'final_target' is the query's final target list (in PathTarget form)
39903989
* 'activeWindows' is the list of active windows previously identified by
39913990
* select_active_windows.
39923991
*
@@ -3995,14 +3994,15 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
39953994
*/
39963995
static PathTarget *
39973996
make_window_input_target(PlannerInfo *root,
3998-
List *tlist,
3997+
PathTarget *final_target,
39993998
List *activeWindows)
40003999
{
40014000
Query *parse = root->parse;
4001+
PathTarget *input_target;
40024002
Bitmapset *sgrefs;
4003-
List *new_tlist;
40044003
List *flattenable_cols;
40054004
List *flattenable_vars;
4005+
int i;
40064006
ListCell *lc;
40074007

40084008
Assert(parse->hasWindowFuncs);
@@ -4040,52 +4040,49 @@ make_window_input_target(PlannerInfo *root,
40404040
}
40414041

40424042
/*
4043-
* Construct a tlist containing all the non-flattenable tlist items, and
4044-
* save aside the others for a moment.
4043+
* Construct a target containing all the non-flattenable targetlist items,
4044+
* and save aside the others for a moment.
40454045
*/
4046-
new_tlist = NIL;
4046+
input_target = create_empty_pathtarget();
40474047
flattenable_cols = NIL;
40484048

4049-
foreach(lc, tlist)
4049+
i = 0;
4050+
foreach(lc, final_target->exprs)
40504051
{
4051-
TargetEntry *tle = (TargetEntry *) lfirst(lc);
4052+
Expr *expr = (Expr *) lfirst(lc);
4053+
Index sgref = final_target->sortgrouprefs[i];
40524054

40534055
/*
40544056
* Don't want to deconstruct window clauses or GROUP BY items. (Note
40554057
* that such items can't contain window functions, so it's okay to
40564058
* compute them below the WindowAgg nodes.)
40574059
*/
4058-
if (tle->ressortgroupref != 0 &&
4059-
bms_is_member(tle->ressortgroupref, sgrefs))
4060+
if (sgref != 0 && bms_is_member(sgref, sgrefs))
40604061
{
4061-
/* Don't want to deconstruct this value, so add to new_tlist */
4062-
TargetEntry *newtle;
4063-
4064-
newtle = makeTargetEntry(tle->expr,
4065-
list_length(new_tlist) + 1,
4066-
NULL,
4067-
false);
4068-
/* Preserve its sortgroupref marking, in case it's volatile */
4069-
newtle->ressortgroupref = tle->ressortgroupref;
4070-
new_tlist = lappend(new_tlist, newtle);
4062+
/*
4063+
* Don't want to deconstruct this value, so add it to the input
4064+
* target as-is.
4065+
*/
4066+
add_column_to_pathtarget(input_target, expr, sgref);
40714067
}
40724068
else
40734069
{
40744070
/*
40754071
* Column is to be flattened, so just remember the expression for
4076-
* later call to pull_var_clause. There's no need for
4077-
* pull_var_clause to examine the TargetEntry node itself.
4072+
* later call to pull_var_clause.
40784073
*/
4079-
flattenable_cols = lappend(flattenable_cols, tle->expr);
4074+
flattenable_cols = lappend(flattenable_cols, expr);
40804075
}
4076+
4077+
i++;
40814078
}
40824079

40834080
/*
40844081
* Pull out all the Vars and Aggrefs mentioned in flattenable columns, and
4085-
* add them to the result tlist if not already present. (Some might be
4082+
* add them to the input target if not already present. (Some might be
40864083
* there already because they're used directly as window/group clauses.)
40874084
*
4088-
* Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that the
4085+
* Note: it's essential to use PVC_INCLUDE_AGGREGATES here, so that any
40894086
* Aggrefs are placed in the Agg node's tlist and not left to be computed
40904087
* at higher levels. On the other hand, we should recurse into
40914088
* WindowFuncs to make sure their input expressions are available.
@@ -4094,13 +4091,14 @@ make_window_input_target(PlannerInfo *root,
40944091
PVC_INCLUDE_AGGREGATES |
40954092
PVC_RECURSE_WINDOWFUNCS |
40964093
PVC_INCLUDE_PLACEHOLDERS);
4097-
new_tlist = add_to_flat_tlist(new_tlist, flattenable_vars);
4094+
add_new_columns_to_pathtarget(input_target, flattenable_vars);
40984095

40994096
/* clean up cruft */
41004097
list_free(flattenable_vars);
41014098
list_free(flattenable_cols);
41024099

4103-
return create_pathtarget(root, new_tlist);
4100+
/* XXX this causes some redundant cost calculation ... */
4101+
return set_pathtarget_cost_width(root, input_target);
41044102
}
41054103

41064104
/*

src/backend/optimizer/util/tlist.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,17 @@ copy_pathtarget(PathTarget *src)
623623
return dst;
624624
}
625625

626+
/*
627+
* create_empty_pathtarget
628+
* Create an empty (zero columns, zero cost) PathTarget.
629+
*/
630+
PathTarget *
631+
create_empty_pathtarget(void)
632+
{
633+
/* This is easy, but we don't want callers to hard-wire this ... */
634+
return (PathTarget *) palloc0(sizeof(PathTarget));
635+
}
636+
626637
/*
627638
* add_column_to_pathtarget
628639
* Append a target column to the PathTarget.
@@ -655,6 +666,41 @@ add_column_to_pathtarget(PathTarget *target, Expr *expr, Index sortgroupref)
655666
}
656667
}
657668

669+
/*
670+
* add_new_column_to_pathtarget
671+
* Append a target column to the PathTarget, but only if it's not
672+
* equal() to any pre-existing target expression.
673+
*
674+
* The caller cannot specify a sortgroupref, since it would be unclear how
675+
* to merge that with a pre-existing column.
676+
*
677+
* As with make_pathtarget_from_tlist, we leave it to the caller to update
678+
* the cost and width fields.
679+
*/
680+
void
681+
add_new_column_to_pathtarget(PathTarget *target, Expr *expr)
682+
{
683+
if (!list_member(target->exprs, expr))
684+
add_column_to_pathtarget(target, expr, 0);
685+
}
686+
687+
/*
688+
* add_new_columns_to_pathtarget
689+
* Apply add_new_column_to_pathtarget() for each element of the list.
690+
*/
691+
void
692+
add_new_columns_to_pathtarget(PathTarget *target, List *exprs)
693+
{
694+
ListCell *lc;
695+
696+
foreach(lc, exprs)
697+
{
698+
Expr *expr = (Expr *) lfirst(lc);
699+
700+
add_new_column_to_pathtarget(target, expr);
701+
}
702+
}
703+
658704
/*
659705
* apply_pathtarget_labeling_to_tlist
660706
* Apply any sortgrouprefs in the PathTarget to matching tlist entries

src/include/optimizer/tlist.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ extern bool grouping_is_hashable(List *groupClause);
5555
extern PathTarget *make_pathtarget_from_tlist(List *tlist);
5656
extern List *make_tlist_from_pathtarget(PathTarget *target);
5757
extern PathTarget *copy_pathtarget(PathTarget *src);
58+
extern PathTarget *create_empty_pathtarget(void);
5859
extern void add_column_to_pathtarget(PathTarget *target,
5960
Expr *expr, Index sortgroupref);
61+
extern void add_new_column_to_pathtarget(PathTarget *target, Expr *expr);
62+
extern void add_new_columns_to_pathtarget(PathTarget *target, List *exprs);
6063
extern void apply_pathtarget_labeling_to_tlist(List *tlist, PathTarget *target);
6164

6265
/* Convenience macro to get a PathTarget with valid cost/width fields */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy