|
|
|
@ -2368,9 +2368,9 @@ create_projection_path(PlannerInfo *root, |
|
|
|
|
* knows that the given path isn't referenced elsewhere and so can be modified |
|
|
|
|
* in-place. |
|
|
|
|
* |
|
|
|
|
* If the input path is a GatherPath, we try to push the new target down to |
|
|
|
|
* its input as well; this is a yet more invasive modification of the input |
|
|
|
|
* path, which create_projection_path() can't do. |
|
|
|
|
* If the input path is a GatherPath or GatherMergePath, we try to push the |
|
|
|
|
* new target down to its input as well; this is a yet more invasive |
|
|
|
|
* modification of the input path, which create_projection_path() can't do. |
|
|
|
|
* |
|
|
|
|
* Note that we mustn't change the source path's parent link; so when it is |
|
|
|
|
* add_path'd to "rel" things will be a bit inconsistent. So far that has |
|
|
|
@ -2407,31 +2407,44 @@ apply_projection_to_path(PlannerInfo *root, |
|
|
|
|
(target->cost.per_tuple - oldcost.per_tuple) * path->rows; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the path happens to be a Gather path, we'd like to arrange for the |
|
|
|
|
* subpath to return the required target list so that workers can help |
|
|
|
|
* project. But if there is something that is not parallel-safe in the |
|
|
|
|
* target expressions, then we can't. |
|
|
|
|
* If the path happens to be a Gather or GatherMerge path, we'd like to |
|
|
|
|
* arrange for the subpath to return the required target list so that |
|
|
|
|
* workers can help project. But if there is something that is not |
|
|
|
|
* parallel-safe in the target expressions, then we can't. |
|
|
|
|
*/ |
|
|
|
|
if (IsA(path, GatherPath) && |
|
|
|
|
if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) && |
|
|
|
|
is_parallel_safe(root, (Node *) target->exprs)) |
|
|
|
|
{ |
|
|
|
|
GatherPath *gpath = (GatherPath *) path; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We always use create_projection_path here, even if the subpath is |
|
|
|
|
* projection-capable, so as to avoid modifying the subpath in place. |
|
|
|
|
* It seems unlikely at present that there could be any other |
|
|
|
|
* references to the subpath, but better safe than sorry. |
|
|
|
|
* |
|
|
|
|
* Note that we don't change the GatherPath's cost estimates; it might |
|
|
|
|
* Note that we don't change the parallel path's cost estimates; it might |
|
|
|
|
* be appropriate to do so, to reflect the fact that the bulk of the |
|
|
|
|
* target evaluation will happen in workers. |
|
|
|
|
*/ |
|
|
|
|
gpath->subpath = (Path *) |
|
|
|
|
create_projection_path(root, |
|
|
|
|
gpath->subpath->parent, |
|
|
|
|
gpath->subpath, |
|
|
|
|
target); |
|
|
|
|
if (IsA(path, GatherPath)) |
|
|
|
|
{ |
|
|
|
|
GatherPath *gpath = (GatherPath *) path; |
|
|
|
|
|
|
|
|
|
gpath->subpath = (Path *) |
|
|
|
|
create_projection_path(root, |
|
|
|
|
gpath->subpath->parent, |
|
|
|
|
gpath->subpath, |
|
|
|
|
target); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
GatherMergePath *gmpath = (GatherMergePath *) path; |
|
|
|
|
|
|
|
|
|
gmpath->subpath = (Path *) |
|
|
|
|
create_projection_path(root, |
|
|
|
|
gmpath->subpath->parent, |
|
|
|
|
gmpath->subpath, |
|
|
|
|
target); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (path->parallel_safe && |
|
|
|
|
!is_parallel_safe(root, (Node *) target->exprs)) |
|
|
|
|