mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Correctly assess parallel-safety of tlists when SRFs are used.
Since commit 69f4b9c85f168ae006929eec44fc44d569e846b9, the existing code was no longer assessing the parallel-safety of the real tlist for each upper rel, but rather the first of possibly several tlists created by split_pathtarget_at_srfs(). Repair. Even though this is clearly wrong, it's not clear that it has any user-visible consequences at the moment, so no back-patch for now. If we discover later that it does have user-visible consequences, we might need to back-patch this to v10. Patch by me, per a report from Rajkumar Raghuwanshi. Discussion: http://postgr.es/m/CA+Tgmoaob_Strkg4Dcx=VyxnyXtrmkV=ofj=pX7gH9hSre-g0Q@mail.gmail.com
This commit is contained in:
parent
44468f49bb
commit
960df2a971
@ -137,6 +137,7 @@ static Size estimate_hashagg_tablesize(Path *path,
|
|||||||
static RelOptInfo *create_grouping_paths(PlannerInfo *root,
|
static RelOptInfo *create_grouping_paths(PlannerInfo *root,
|
||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
|
bool target_parallel_safe,
|
||||||
const AggClauseCosts *agg_costs,
|
const AggClauseCosts *agg_costs,
|
||||||
grouping_sets_data *gd);
|
grouping_sets_data *gd);
|
||||||
static void consider_groupingsets_paths(PlannerInfo *root,
|
static void consider_groupingsets_paths(PlannerInfo *root,
|
||||||
@ -152,6 +153,7 @@ static RelOptInfo *create_window_paths(PlannerInfo *root,
|
|||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *input_target,
|
PathTarget *input_target,
|
||||||
PathTarget *output_target,
|
PathTarget *output_target,
|
||||||
|
bool output_target_parallel_safe,
|
||||||
List *tlist,
|
List *tlist,
|
||||||
WindowFuncLists *wflists,
|
WindowFuncLists *wflists,
|
||||||
List *activeWindows);
|
List *activeWindows);
|
||||||
@ -168,6 +170,7 @@ static RelOptInfo *create_distinct_paths(PlannerInfo *root,
|
|||||||
static RelOptInfo *create_ordered_paths(PlannerInfo *root,
|
static RelOptInfo *create_ordered_paths(PlannerInfo *root,
|
||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
|
bool target_parallel_safe,
|
||||||
double limit_tuples);
|
double limit_tuples);
|
||||||
static PathTarget *make_group_input_target(PlannerInfo *root,
|
static PathTarget *make_group_input_target(PlannerInfo *root,
|
||||||
PathTarget *final_target);
|
PathTarget *final_target);
|
||||||
@ -1583,6 +1586,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
PathTarget *final_target;
|
PathTarget *final_target;
|
||||||
List *final_targets;
|
List *final_targets;
|
||||||
List *final_targets_contain_srfs;
|
List *final_targets_contain_srfs;
|
||||||
|
bool final_target_parallel_safe;
|
||||||
RelOptInfo *current_rel;
|
RelOptInfo *current_rel;
|
||||||
RelOptInfo *final_rel;
|
RelOptInfo *final_rel;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
@ -1645,6 +1649,10 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
/* Also extract the PathTarget form of the setop result tlist */
|
/* Also extract the PathTarget form of the setop result tlist */
|
||||||
final_target = current_rel->cheapest_total_path->pathtarget;
|
final_target = current_rel->cheapest_total_path->pathtarget;
|
||||||
|
|
||||||
|
/* And check whether it's parallel safe */
|
||||||
|
final_target_parallel_safe =
|
||||||
|
is_parallel_safe(root, (Node *) final_target->exprs);
|
||||||
|
|
||||||
/* The setop result tlist couldn't contain any SRFs */
|
/* The setop result tlist couldn't contain any SRFs */
|
||||||
Assert(!parse->hasTargetSRFs);
|
Assert(!parse->hasTargetSRFs);
|
||||||
final_targets = final_targets_contain_srfs = NIL;
|
final_targets = final_targets_contain_srfs = NIL;
|
||||||
@ -1676,12 +1684,15 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
PathTarget *sort_input_target;
|
PathTarget *sort_input_target;
|
||||||
List *sort_input_targets;
|
List *sort_input_targets;
|
||||||
List *sort_input_targets_contain_srfs;
|
List *sort_input_targets_contain_srfs;
|
||||||
|
bool sort_input_target_parallel_safe;
|
||||||
PathTarget *grouping_target;
|
PathTarget *grouping_target;
|
||||||
List *grouping_targets;
|
List *grouping_targets;
|
||||||
List *grouping_targets_contain_srfs;
|
List *grouping_targets_contain_srfs;
|
||||||
|
bool grouping_target_parallel_safe;
|
||||||
PathTarget *scanjoin_target;
|
PathTarget *scanjoin_target;
|
||||||
List *scanjoin_targets;
|
List *scanjoin_targets;
|
||||||
List *scanjoin_targets_contain_srfs;
|
List *scanjoin_targets_contain_srfs;
|
||||||
|
bool scanjoin_target_parallel_safe;
|
||||||
bool have_grouping;
|
bool have_grouping;
|
||||||
AggClauseCosts agg_costs;
|
AggClauseCosts agg_costs;
|
||||||
WindowFuncLists *wflists = NULL;
|
WindowFuncLists *wflists = NULL;
|
||||||
@ -1805,6 +1816,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
* that were obtained within query_planner().
|
* that were obtained within query_planner().
|
||||||
*/
|
*/
|
||||||
final_target = create_pathtarget(root, tlist);
|
final_target = create_pathtarget(root, tlist);
|
||||||
|
final_target_parallel_safe =
|
||||||
|
is_parallel_safe(root, (Node *) final_target->exprs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If ORDER BY was given, consider whether we should use a post-sort
|
* If ORDER BY was given, consider whether we should use a post-sort
|
||||||
@ -1812,11 +1825,18 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
* so.
|
* so.
|
||||||
*/
|
*/
|
||||||
if (parse->sortClause)
|
if (parse->sortClause)
|
||||||
|
{
|
||||||
sort_input_target = make_sort_input_target(root,
|
sort_input_target = make_sort_input_target(root,
|
||||||
final_target,
|
final_target,
|
||||||
&have_postponed_srfs);
|
&have_postponed_srfs);
|
||||||
|
sort_input_target_parallel_safe =
|
||||||
|
is_parallel_safe(root, (Node *) sort_input_target->exprs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
sort_input_target = final_target;
|
sort_input_target = final_target;
|
||||||
|
sort_input_target_parallel_safe = final_target_parallel_safe;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have window functions to deal with, the output from any
|
* If we have window functions to deal with, the output from any
|
||||||
@ -1824,11 +1844,18 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
* otherwise, it should be sort_input_target.
|
* otherwise, it should be sort_input_target.
|
||||||
*/
|
*/
|
||||||
if (activeWindows)
|
if (activeWindows)
|
||||||
|
{
|
||||||
grouping_target = make_window_input_target(root,
|
grouping_target = make_window_input_target(root,
|
||||||
final_target,
|
final_target,
|
||||||
activeWindows);
|
activeWindows);
|
||||||
|
grouping_target_parallel_safe =
|
||||||
|
is_parallel_safe(root, (Node *) grouping_target->exprs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
grouping_target = sort_input_target;
|
grouping_target = sort_input_target;
|
||||||
|
grouping_target_parallel_safe = sort_input_target_parallel_safe;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have grouping or aggregation to do, the topmost scan/join
|
* If we have grouping or aggregation to do, the topmost scan/join
|
||||||
@ -1838,9 +1865,16 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
have_grouping = (parse->groupClause || parse->groupingSets ||
|
have_grouping = (parse->groupClause || parse->groupingSets ||
|
||||||
parse->hasAggs || root->hasHavingQual);
|
parse->hasAggs || root->hasHavingQual);
|
||||||
if (have_grouping)
|
if (have_grouping)
|
||||||
|
{
|
||||||
scanjoin_target = make_group_input_target(root, final_target);
|
scanjoin_target = make_group_input_target(root, final_target);
|
||||||
|
scanjoin_target_parallel_safe =
|
||||||
|
is_parallel_safe(root, (Node *) grouping_target->exprs);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
scanjoin_target = grouping_target;
|
scanjoin_target = grouping_target;
|
||||||
|
scanjoin_target_parallel_safe = grouping_target_parallel_safe;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are any SRFs in the targetlist, we must separate each of
|
* If there are any SRFs in the targetlist, we must separate each of
|
||||||
@ -1922,8 +1956,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
* for partial paths. But only parallel-safe expressions can be
|
* for partial paths. But only parallel-safe expressions can be
|
||||||
* computed by partial paths.
|
* computed by partial paths.
|
||||||
*/
|
*/
|
||||||
if (current_rel->partial_pathlist &&
|
if (current_rel->partial_pathlist && scanjoin_target_parallel_safe)
|
||||||
is_parallel_safe(root, (Node *) scanjoin_target->exprs))
|
|
||||||
{
|
{
|
||||||
/* Apply the scan/join target to each partial path */
|
/* Apply the scan/join target to each partial path */
|
||||||
foreach(lc, current_rel->partial_pathlist)
|
foreach(lc, current_rel->partial_pathlist)
|
||||||
@ -1984,6 +2017,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
current_rel = create_grouping_paths(root,
|
current_rel = create_grouping_paths(root,
|
||||||
current_rel,
|
current_rel,
|
||||||
grouping_target,
|
grouping_target,
|
||||||
|
grouping_target_parallel_safe,
|
||||||
&agg_costs,
|
&agg_costs,
|
||||||
gset_data);
|
gset_data);
|
||||||
/* Fix things up if grouping_target contains SRFs */
|
/* Fix things up if grouping_target contains SRFs */
|
||||||
@ -2003,6 +2037,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
current_rel,
|
current_rel,
|
||||||
grouping_target,
|
grouping_target,
|
||||||
sort_input_target,
|
sort_input_target,
|
||||||
|
sort_input_target_parallel_safe,
|
||||||
tlist,
|
tlist,
|
||||||
wflists,
|
wflists,
|
||||||
activeWindows);
|
activeWindows);
|
||||||
@ -2036,6 +2071,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
|
|||||||
current_rel = create_ordered_paths(root,
|
current_rel = create_ordered_paths(root,
|
||||||
current_rel,
|
current_rel,
|
||||||
final_target,
|
final_target,
|
||||||
|
final_target_parallel_safe,
|
||||||
have_postponed_srfs ? -1.0 :
|
have_postponed_srfs ? -1.0 :
|
||||||
limit_tuples);
|
limit_tuples);
|
||||||
/* Fix things up if final_target contains SRFs */
|
/* Fix things up if final_target contains SRFs */
|
||||||
@ -3623,6 +3659,7 @@ static RelOptInfo *
|
|||||||
create_grouping_paths(PlannerInfo *root,
|
create_grouping_paths(PlannerInfo *root,
|
||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
|
bool target_parallel_safe,
|
||||||
const AggClauseCosts *agg_costs,
|
const AggClauseCosts *agg_costs,
|
||||||
grouping_sets_data *gd)
|
grouping_sets_data *gd)
|
||||||
{
|
{
|
||||||
@ -3652,8 +3689,7 @@ create_grouping_paths(PlannerInfo *root,
|
|||||||
* target list and HAVING quals are parallel-safe. The partially grouped
|
* target list and HAVING quals are parallel-safe. The partially grouped
|
||||||
* relation obeys the same rules.
|
* relation obeys the same rules.
|
||||||
*/
|
*/
|
||||||
if (input_rel->consider_parallel &&
|
if (input_rel->consider_parallel && target_parallel_safe &&
|
||||||
is_parallel_safe(root, (Node *) target->exprs) &&
|
|
||||||
is_parallel_safe(root, (Node *) parse->havingQual))
|
is_parallel_safe(root, (Node *) parse->havingQual))
|
||||||
{
|
{
|
||||||
grouped_rel->consider_parallel = true;
|
grouped_rel->consider_parallel = true;
|
||||||
@ -4230,6 +4266,7 @@ create_window_paths(PlannerInfo *root,
|
|||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *input_target,
|
PathTarget *input_target,
|
||||||
PathTarget *output_target,
|
PathTarget *output_target,
|
||||||
|
bool output_target_parallel_safe,
|
||||||
List *tlist,
|
List *tlist,
|
||||||
WindowFuncLists *wflists,
|
WindowFuncLists *wflists,
|
||||||
List *activeWindows)
|
List *activeWindows)
|
||||||
@ -4245,8 +4282,7 @@ create_window_paths(PlannerInfo *root,
|
|||||||
* can't be parallel-safe, either. Otherwise, we need to examine the
|
* can't be parallel-safe, either. Otherwise, we need to examine the
|
||||||
* target list and active windows for non-parallel-safe constructs.
|
* target list and active windows for non-parallel-safe constructs.
|
||||||
*/
|
*/
|
||||||
if (input_rel->consider_parallel &&
|
if (input_rel->consider_parallel && output_target_parallel_safe &&
|
||||||
is_parallel_safe(root, (Node *) output_target->exprs) &&
|
|
||||||
is_parallel_safe(root, (Node *) activeWindows))
|
is_parallel_safe(root, (Node *) activeWindows))
|
||||||
window_rel->consider_parallel = true;
|
window_rel->consider_parallel = true;
|
||||||
|
|
||||||
@ -4621,6 +4657,7 @@ static RelOptInfo *
|
|||||||
create_ordered_paths(PlannerInfo *root,
|
create_ordered_paths(PlannerInfo *root,
|
||||||
RelOptInfo *input_rel,
|
RelOptInfo *input_rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
|
bool target_parallel_safe,
|
||||||
double limit_tuples)
|
double limit_tuples)
|
||||||
{
|
{
|
||||||
Path *cheapest_input_path = input_rel->cheapest_total_path;
|
Path *cheapest_input_path = input_rel->cheapest_total_path;
|
||||||
@ -4635,8 +4672,7 @@ create_ordered_paths(PlannerInfo *root,
|
|||||||
* can't be parallel-safe, either. Otherwise, it's parallel-safe if the
|
* can't be parallel-safe, either. Otherwise, it's parallel-safe if the
|
||||||
* target list is parallel-safe.
|
* target list is parallel-safe.
|
||||||
*/
|
*/
|
||||||
if (input_rel->consider_parallel &&
|
if (input_rel->consider_parallel && target_parallel_safe)
|
||||||
is_parallel_safe(root, (Node *) target->exprs))
|
|
||||||
ordered_rel->consider_parallel = true;
|
ordered_rel->consider_parallel = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user