diff options
Diffstat (limited to 'src/backend/optimizer/util')
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/util/pathnode.c | 37 | ||||
| -rw-r--r-- | src/backend/optimizer/util/placeholder.c | 40 | ||||
| -rw-r--r-- | src/backend/optimizer/util/relnode.c | 24 |
4 files changed, 78 insertions, 25 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index dff115e8dc..6ac25dc663 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3489,7 +3489,7 @@ eval_const_expressions_mutator(Node *node, * can optimize field selection from a RowExpr construct. * * However, replacing a whole-row Var in this way has a - * pitfall: if we've already built the reltargetlist for the + * pitfall: if we've already built the rel targetlist for the * source relation, then the whole-row Var is scheduled to be * produced by the relation scan, but the simple Var probably * isn't, which will lead to a failure in setrefs.c. This is diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 1097a1804a..9417587abf 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -929,6 +929,7 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_SeqScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = parallel_degree > 0 ? true : false; @@ -952,6 +953,7 @@ create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer pathnode->pathtype = T_SampleScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1008,6 +1010,7 @@ create_index_path(PlannerInfo *root, pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1056,6 +1059,7 @@ create_bitmap_heap_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapHeapScan; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1085,6 +1089,7 @@ create_bitmap_and_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapAnd; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = NULL; /* not used in bitmap trees */ /* @@ -1120,6 +1125,7 @@ create_bitmap_or_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapOr; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = NULL; /* not used in bitmap trees */ /* @@ -1154,6 +1160,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals, pathnode->path.pathtype = T_TidScan; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1185,6 +1192,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer, pathnode->path.pathtype = T_Append; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_appendrel_parampathinfo(rel, required_outer); pathnode->path.parallel_aware = false; @@ -1243,6 +1251,7 @@ create_merge_append_path(PlannerInfo *root, pathnode->path.pathtype = T_MergeAppend; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_appendrel_parampathinfo(rel, required_outer); pathnode->path.parallel_aware = false; @@ -1290,7 +1299,7 @@ create_merge_append_path(PlannerInfo *root, pathkeys, subpath->total_cost, subpath->parent->tuples, - subpath->parent->width, + subpath->pathtarget->width, 0.0, work_mem, pathnode->limit_tuples); @@ -1322,7 +1331,8 @@ create_result_path(RelOptInfo *rel, List *quals) ResultPath *pathnode = makeNode(ResultPath); pathnode->path.pathtype = T_Result; - pathnode->path.parent = NULL; + pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = NULL; /* there are no other rels... */ pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = rel->consider_parallel; @@ -1339,7 +1349,10 @@ create_result_path(RelOptInfo *rel, List *quals) * In theory we should include the qual eval cost as well, but at present * that doesn't accomplish much except duplicate work that will be done * again in make_result; since this is only used for degenerate cases, - * nothing interesting will be done with the path cost values... + * nothing interesting will be done with the path cost values. + * + * (Likewise, we don't worry about pathtarget->cost since that tlist will + * be empty at this point.) */ return pathnode; @@ -1359,6 +1372,7 @@ create_material_path(RelOptInfo *rel, Path *subpath) pathnode->path.pathtype = T_Material; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = subpath->param_info; pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = subpath->parallel_safe; @@ -1371,7 +1385,7 @@ create_material_path(RelOptInfo *rel, Path *subpath) subpath->startup_cost, subpath->total_cost, subpath->rows, - rel->width); + subpath->pathtarget->width); return pathnode; } @@ -1422,6 +1436,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, pathnode->path.pathtype = T_Unique; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = subpath->param_info; pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = subpath->parallel_safe; @@ -1516,7 +1531,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, cost_sort(&sort_path, root, NIL, subpath->total_cost, rel->rows, - rel->width, + subpath->pathtarget->width, 0.0, work_mem, -1.0); @@ -1536,7 +1551,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, * Estimate the overhead per hashtable entry at 64 bytes (same as in * planner.c). */ - int hashentrysize = rel->width + 64; + int hashentrysize = subpath->pathtarget->width + 64; if (hashentrysize * pathnode->path.rows > work_mem * 1024L) { @@ -1607,6 +1622,7 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, pathnode->path.pathtype = T_Gather; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1672,6 +1688,7 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_SubqueryScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1697,6 +1714,7 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_FunctionScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1722,6 +1740,7 @@ create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_ValuesScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1746,6 +1765,7 @@ create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer) pathnode->pathtype = T_CteScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1771,6 +1791,7 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_WorkTableScan; pathnode->parent = rel; + pathnode->pathtarget = &(rel->reltarget); pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1806,6 +1827,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->path.pathtype = T_ForeignScan; pathnode->path.parent = rel; + pathnode->path.pathtarget = &(rel->reltarget); pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1938,6 +1960,7 @@ create_nestloop_path(PlannerInfo *root, pathnode->path.pathtype = T_NestLoop; pathnode->path.parent = joinrel; + pathnode->path.pathtarget = &(joinrel->reltarget); pathnode->path.param_info = get_joinrel_parampathinfo(root, joinrel, @@ -2000,6 +2023,7 @@ create_mergejoin_path(PlannerInfo *root, pathnode->jpath.path.pathtype = T_MergeJoin; pathnode->jpath.path.parent = joinrel; + pathnode->jpath.path.pathtarget = &(joinrel->reltarget); pathnode->jpath.path.param_info = get_joinrel_parampathinfo(root, joinrel, @@ -2060,6 +2084,7 @@ create_hashjoin_path(PlannerInfo *root, pathnode->jpath.path.pathtype = T_HashJoin; pathnode->jpath.path.parent = joinrel; + pathnode->jpath.path.pathtarget = &(joinrel->reltarget); pathnode->jpath.path.param_info = get_joinrel_parampathinfo(root, joinrel, diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index d95426555b..4af06ab73e 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -16,6 +16,7 @@ #include "postgres.h" #include "nodes/nodeFuncs.h" +#include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/placeholder.h" #include "optimizer/planmain.h" @@ -388,8 +389,9 @@ add_placeholders_to_base_rels(PlannerInfo *root) { RelOptInfo *rel = find_base_rel(root, varno); - rel->reltargetlist = lappend(rel->reltargetlist, - copyObject(phinfo->ph_var)); + rel->reltarget.exprs = lappend(rel->reltarget.exprs, + copyObject(phinfo->ph_var)); + /* reltarget's cost and width fields will be updated later */ } } } @@ -402,11 +404,10 @@ add_placeholders_to_base_rels(PlannerInfo *root) * * A join rel should emit a PlaceHolderVar if (a) the PHV is needed above * this join level and (b) the PHV can be computed at or below this level. - * At this time we do not need to distinguish whether the PHV will be - * computed here or copied up from below. */ void -add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel) +add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, + RelOptInfo *outer_rel, RelOptInfo *inner_rel) { Relids relids = joinrel->relids; ListCell *lc; @@ -422,9 +423,32 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel) if (bms_is_subset(phinfo->ph_eval_at, relids)) { /* Yup, add it to the output */ - joinrel->reltargetlist = lappend(joinrel->reltargetlist, - phinfo->ph_var); - joinrel->width += phinfo->ph_width; + joinrel->reltarget.exprs = lappend(joinrel->reltarget.exprs, + phinfo->ph_var); + joinrel->reltarget.width += phinfo->ph_width; + + /* + * Charge the cost of evaluating the contained expression if + * the PHV can be computed here but not in either input. This + * is a bit bogus because we make the decision based on the + * first pair of possible input relations considered for the + * joinrel. With other pairs, it might be possible to compute + * the PHV in one input or the other, and then we'd be double + * charging the PHV's cost for some join paths. For now, live + * with that; but we might want to improve it later by + * refiguring the reltarget costs for each pair of inputs. + */ + if (!bms_is_subset(phinfo->ph_eval_at, outer_rel->relids) && + !bms_is_subset(phinfo->ph_eval_at, inner_rel->relids)) + { + QualCost cost; + + cost_qual_eval_node(&cost, (Node *) phinfo->ph_var->phexpr, + root); + joinrel->reltarget.cost.startup += cost.startup; + joinrel->reltarget.cost.per_tuple += cost.per_tuple; + } + /* Adjust joinrel's direct_lateral_relids as needed */ joinrel->direct_lateral_relids = bms_add_members(joinrel->direct_lateral_relids, diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 420692f7a4..e658f27180 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -102,12 +102,14 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->reloptkind = reloptkind; rel->relids = bms_make_singleton(relid); rel->rows = 0; - rel->width = 0; /* cheap startup cost is interesting iff not all tuples to be retrieved */ rel->consider_startup = (root->tuple_fraction > 0); rel->consider_param_startup = false; /* might get changed later */ rel->consider_parallel = false; /* might get changed later */ - rel->reltargetlist = NIL; + rel->reltarget.exprs = NIL; + rel->reltarget.cost.startup = 0; + rel->reltarget.cost.per_tuple = 0; + rel->reltarget.width = 0; rel->pathlist = NIL; rel->ppilist = NIL; rel->partial_pathlist = NIL; @@ -387,12 +389,14 @@ build_join_rel(PlannerInfo *root, joinrel->reloptkind = RELOPT_JOINREL; joinrel->relids = bms_copy(joinrelids); joinrel->rows = 0; - joinrel->width = 0; /* cheap startup cost is interesting iff not all tuples to be retrieved */ joinrel->consider_startup = (root->tuple_fraction > 0); joinrel->consider_param_startup = false; joinrel->consider_parallel = false; - joinrel->reltargetlist = NIL; + joinrel->reltarget.exprs = NIL; + joinrel->reltarget.cost.startup = 0; + joinrel->reltarget.cost.per_tuple = 0; + joinrel->reltarget.width = 0; joinrel->pathlist = NIL; joinrel->ppilist = NIL; joinrel->partial_pathlist = NIL; @@ -459,7 +463,7 @@ build_join_rel(PlannerInfo *root, */ build_joinrel_tlist(root, joinrel, outer_rel); build_joinrel_tlist(root, joinrel, inner_rel); - add_placeholders_to_joinrel(root, joinrel); + add_placeholders_to_joinrel(root, joinrel, outer_rel, inner_rel); /* * add_placeholders_to_joinrel also took care of adding the ph_lateral @@ -609,7 +613,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, Relids relids = joinrel->relids; ListCell *vars; - foreach(vars, input_rel->reltargetlist) + foreach(vars, input_rel->reltarget.exprs) { Var *var = (Var *) lfirst(vars); RelOptInfo *baserel; @@ -628,7 +632,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, * rels, which will never be seen here.) */ if (!IsA(var, Var)) - elog(ERROR, "unexpected node type in reltargetlist: %d", + elog(ERROR, "unexpected node type in rel targetlist: %d", (int) nodeTag(var)); /* Get the Var's original base rel */ @@ -639,8 +643,9 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, if (bms_nonempty_difference(baserel->attr_needed[ndx], relids)) { /* Yup, add it to the output */ - joinrel->reltargetlist = lappend(joinrel->reltargetlist, var); - joinrel->width += baserel->attr_widths[ndx]; + joinrel->reltarget.exprs = lappend(joinrel->reltarget.exprs, var); + /* Vars have cost zero, so no need to adjust reltarget.cost */ + joinrel->reltarget.width += baserel->attr_widths[ndx]; } } } @@ -826,7 +831,6 @@ build_empty_join_rel(PlannerInfo *root) joinrel->reloptkind = RELOPT_JOINREL; joinrel->relids = NULL; /* empty set */ joinrel->rows = 1; /* we produce one row for such cases */ - joinrel->width = 0; /* it contains no Vars */ joinrel->rtekind = RTE_JOIN; root->join_rel_list = lappend(root->join_rel_list, joinrel); |
