diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c index dc035d72a21f45184edb1606a0351dbbf57ecfcc..0ac4658e84dc2a5da3f29e88a38225364547c687 100644 --- a/contrib/file_fdw/file_fdw.c +++ b/contrib/file_fdw/file_fdw.c @@ -821,7 +821,7 @@ check_selective_binary_conversion(RelOptInfo *baserel, } /* Collect all the attributes needed for joins or final output. */ - pull_varattnos((Node *) baserel->reltarget.exprs, baserel->relid, + pull_varattnos((Node *) baserel->reltarget->exprs, baserel->relid, &attrs_used); /* Add all the attributes used by restriction clauses. */ @@ -953,7 +953,7 @@ estimate_size(PlannerInfo *root, RelOptInfo *baserel, */ int tuple_width; - tuple_width = MAXALIGN(baserel->reltarget.width) + + tuple_width = MAXALIGN(baserel->reltarget->width) + MAXALIGN(SizeofHeapTupleHeader); ntuples = clamp_row_est((double) stat_buf.st_size / (double) tuple_width); diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index e6d4cdbe5babe61b1d5f16932a214e6427977eb0..17081e48bd1c9cd92632ac196c4c489fe6c37f9d 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -728,10 +728,10 @@ build_tlist_to_deparse(RelOptInfo *foreignrel) PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private; /* - * We require columns specified in foreignrel->reltarget.exprs and those + * We require columns specified in foreignrel->reltarget->exprs and those * required for evaluating the local conditions. */ - tlist = add_to_flat_tlist(tlist, foreignrel->reltarget.exprs); + tlist = add_to_flat_tlist(tlist, foreignrel->reltarget->exprs); tlist = add_to_flat_tlist(tlist, pull_var_clause((Node *) fpinfo->local_conds, PVC_RECURSE_PLACEHOLDERS)); diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index aa745f237e259880c272285b73ecfd4a66be5ae4..d4ee2a8548fa0dc485d08c852c9f6d8266c9df63 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -481,7 +481,7 @@ postgresGetForeignRelSize(PlannerInfo *root, * columns used in them. Doesn't seem worth detecting that case though.) */ fpinfo->attrs_used = NULL; - pull_varattnos((Node *) baserel->reltarget.exprs, baserel->relid, + pull_varattnos((Node *) baserel->reltarget->exprs, baserel->relid, &fpinfo->attrs_used); foreach(lc, fpinfo->local_conds) { @@ -532,7 +532,7 @@ postgresGetForeignRelSize(PlannerInfo *root, /* Report estimated baserel size to planner. */ baserel->rows = fpinfo->rows; - baserel->reltarget.width = fpinfo->width; + baserel->reltarget->width = fpinfo->width; } else { @@ -549,7 +549,7 @@ postgresGetForeignRelSize(PlannerInfo *root, { baserel->pages = 10; baserel->tuples = - (10 * BLCKSZ) / (baserel->reltarget.width + + (10 * BLCKSZ) / (baserel->reltarget->width + MAXALIGN(SizeofHeapTupleHeader)); } @@ -2164,7 +2164,7 @@ estimate_path_cost_size(PlannerInfo *root, * between foreign relations. */ rows = foreignrel->rows; - width = foreignrel->reltarget.width; + width = foreignrel->reltarget->width; /* Back into an estimate of the number of retrieved rows. */ retrieved_rows = clamp_row_est(rows / fpinfo->local_conds_sel); @@ -3690,7 +3690,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root, &width, &startup_cost, &total_cost); /* Now update this information in the joinrel */ joinrel->rows = rows; - joinrel->reltarget.width = width; + joinrel->reltarget->width = width; fpinfo->rows = rows; fpinfo->width = width; fpinfo->startup_cost = startup_cost; diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml index e53458ea43c51589bf98cf4d5c04ad0037961a4c..bbc9c03721e43d47ee5fd6ce2399ad6421ed5ddd 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -1173,7 +1173,7 @@ GetForeignServerByName(const char *name, bool missing_ok); it contains restriction quals (<literal>WHERE</> clauses) that should be used to filter the rows to be fetched. (The FDW itself is not required to enforce these quals, as the core executor can check them instead.) - <literal>baserel->reltarget.exprs</> can be used to determine which + <literal>baserel->reltarget->exprs</> can be used to determine which columns need to be fetched; but note that it only lists columns that have to be emitted by the <structname>ForeignScan</> plan node, not columns that are used in qual evaluation but not output by the query. diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index eb0fc1e121b946fb7ea5b6490d80568a35a6bc09..548a3b9e57cc9ef95c6a820ccb4a1da70f4a346c 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1598,22 +1598,8 @@ _outPathInfo(StringInfo str, const Path *node) WRITE_ENUM_FIELD(pathtype, NodeTag); appendStringInfoString(str, " :parent_relids "); _outBitmapset(str, node->parent->relids); - if (node->pathtarget != &(node->parent->reltarget)) - { - WRITE_NODE_FIELD(pathtarget->exprs); - if (node->pathtarget->sortgrouprefs) - { - int i; - - appendStringInfoString(str, " :pathtarget->sortgrouprefs"); - for (i = 0; i < list_length(node->pathtarget->exprs); i++) - appendStringInfo(str, " %u", - node->pathtarget->sortgrouprefs[i]); - } - WRITE_FLOAT_FIELD(pathtarget->cost.startup, "%.2f"); - WRITE_FLOAT_FIELD(pathtarget->cost.per_tuple, "%.2f"); - WRITE_INT_FIELD(pathtarget->width); - } + if (node->pathtarget != node->parent->reltarget) + WRITE_NODE_FIELD(pathtarget); appendStringInfoString(str, " :required_outer "); if (node->param_info) _outBitmapset(str, node->param_info->ppi_req_outer); @@ -2094,11 +2080,7 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node) WRITE_BOOL_FIELD(consider_startup); WRITE_BOOL_FIELD(consider_param_startup); WRITE_BOOL_FIELD(consider_parallel); - WRITE_NODE_FIELD(reltarget.exprs); - /* reltarget.sortgrouprefs is never interesting, at present anyway */ - WRITE_FLOAT_FIELD(reltarget.cost.startup, "%.2f"); - WRITE_FLOAT_FIELD(reltarget.cost.per_tuple, "%.2f"); - WRITE_INT_FIELD(reltarget.width); + WRITE_NODE_FIELD(reltarget); WRITE_NODE_FIELD(pathlist); WRITE_NODE_FIELD(ppilist); WRITE_NODE_FIELD(partial_pathlist); @@ -2201,6 +2183,25 @@ _outPathKey(StringInfo str, const PathKey *node) WRITE_BOOL_FIELD(pk_nulls_first); } +static void +_outPathTarget(StringInfo str, const PathTarget *node) +{ + WRITE_NODE_TYPE("PATHTARGET"); + + WRITE_NODE_FIELD(exprs); + if (node->sortgrouprefs) + { + int i; + + appendStringInfoString(str, " :sortgrouprefs"); + for (i = 0; i < list_length(node->exprs); i++) + appendStringInfo(str, " %u", node->sortgrouprefs[i]); + } + WRITE_FLOAT_FIELD(cost.startup, "%.2f"); + WRITE_FLOAT_FIELD(cost.per_tuple, "%.2f"); + WRITE_INT_FIELD(width); +} + static void _outParamPathInfo(StringInfo str, const ParamPathInfo *node) { @@ -3612,6 +3613,9 @@ _outNode(StringInfo str, const void *obj) case T_PathKey: _outPathKey(str, obj); break; + case T_PathTarget: + _outPathTarget(str, obj); + break; case T_ParamPathInfo: _outParamPathInfo(str, obj); break; diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 05c51ff07e0225a63e18bddf58309b617356de4e..4f60b85861da54204524439b83cf1ed861f689b1 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -936,7 +936,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, /* * CE failed, so finish copying/modifying targetlist and join quals. * - * Note: the resulting childrel->reltarget.exprs may contain arbitrary + * NB: the resulting childrel->reltarget->exprs may contain arbitrary * expressions, which otherwise would not occur in a rel's targetlist. * Code that might be looking at an appendrel child must cope with * such. (Normally, a rel's targetlist would only include Vars and @@ -947,9 +947,9 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, adjust_appendrel_attrs(root, (Node *) rel->joininfo, appinfo); - childrel->reltarget.exprs = (List *) + childrel->reltarget->exprs = (List *) adjust_appendrel_attrs(root, - (Node *) rel->reltarget.exprs, + (Node *) rel->reltarget->exprs, appinfo); /* @@ -994,7 +994,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, Assert(childrel->rows > 0); parent_rows += childrel->rows; - parent_size += childrel->reltarget.width * childrel->rows; + parent_size += childrel->reltarget->width * childrel->rows; /* * Accumulate per-column estimates too. We need not do anything for @@ -1004,8 +1004,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, * * By construction, child's targetlist is 1-to-1 with parent's. */ - forboth(parentvars, rel->reltarget.exprs, - childvars, childrel->reltarget.exprs) + forboth(parentvars, rel->reltarget->exprs, + childvars, childrel->reltarget->exprs) { Var *parentvar = (Var *) lfirst(parentvars); Node *childvar = (Node *) lfirst(childvars); @@ -1040,7 +1040,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, Assert(parent_rows > 0); rel->rows = parent_rows; - rel->reltarget.width = rint(parent_size / parent_rows); + rel->reltarget->width = rint(parent_size / parent_rows); for (i = 0; i < nattrs; i++) rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows); @@ -1515,7 +1515,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel) { /* Set dummy size estimates --- we leave attr_widths[] as zeroes */ rel->rows = 0; - rel->reltarget.width = 0; + rel->reltarget->width = 0; /* Discard any pre-existing paths; no further need for them */ rel->pathlist = NIL; @@ -1771,7 +1771,7 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) * not reference the ordinality column, or at least not in any way * that would be interesting for sorting. */ - foreach(lc, rel->reltarget.exprs) + foreach(lc, rel->reltarget->exprs) { Var *node = (Var *) lfirst(lc); @@ -2717,7 +2717,7 @@ remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel) * isn't computed for inheritance child rels, cf set_append_rel_size(). * (XXX might be worth changing that sometime.) */ - pull_varattnos((Node *) rel->reltarget.exprs, rel->relid, &attrs_used); + pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used); /* Add all the attributes used by un-pushed-down restriction clauses. */ foreach(lc, rel->baserestrictinfo) @@ -3028,7 +3028,7 @@ debug_print_rel(PlannerInfo *root, RelOptInfo *rel) printf("RELOPTINFO ("); print_relids(rel->relids); - printf("): rows=%.0f width=%d\n", rel->rows, rel->reltarget.width); + printf("): rows=%.0f width=%d\n", rel->rows, rel->reltarget->width); if (rel->baserestrictinfo) { diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 5350329998a8e22e9778091d24bd57255b0fd724..943fcde3b8e5b26b3d10fee093741be7fae3d1c0 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4218,7 +4218,7 @@ set_foreign_size_estimates(PlannerInfo *root, RelOptInfo *rel) * that have to be calculated at this relation. This is the amount of data * we'd need to pass upwards in case of a sort, hash, etc. * - * This function also sets reltarget.cost, so it's a bit misnamed now. + * This function also sets reltarget->cost, so it's a bit misnamed now. * * NB: this works best on plain relations because it prefers to look at * real Vars. For subqueries, set_subquery_size_estimates will already have @@ -4239,10 +4239,10 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) ListCell *lc; /* Vars are assumed to have cost zero, but other exprs do not */ - rel->reltarget.cost.startup = 0; - rel->reltarget.cost.per_tuple = 0; + rel->reltarget->cost.startup = 0; + rel->reltarget->cost.per_tuple = 0; - foreach(lc, rel->reltarget.exprs) + foreach(lc, rel->reltarget->exprs) { Node *node = (Node *) lfirst(lc); @@ -4309,7 +4309,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) { /* * We will need to evaluate the PHV's contained expression while - * scanning this rel, so be sure to include it in reltarget.cost. + * scanning this rel, so be sure to include it in reltarget->cost. */ PlaceHolderVar *phv = (PlaceHolderVar *) node; PlaceHolderInfo *phinfo = find_placeholder_info(root, phv, false); @@ -4317,8 +4317,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) tuple_width += phinfo->ph_width; cost_qual_eval_node(&cost, (Node *) phv->phexpr, root); - rel->reltarget.cost.startup += cost.startup; - rel->reltarget.cost.per_tuple += cost.per_tuple; + rel->reltarget->cost.startup += cost.startup; + rel->reltarget->cost.per_tuple += cost.per_tuple; } else { @@ -4335,8 +4335,8 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) tuple_width += item_width; /* Not entirely clear if we need to account for cost, but do so */ cost_qual_eval_node(&cost, node, root); - rel->reltarget.cost.startup += cost.startup; - rel->reltarget.cost.per_tuple += cost.per_tuple; + rel->reltarget->cost.startup += cost.startup; + rel->reltarget->cost.per_tuple += cost.per_tuple; } } @@ -4373,7 +4373,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel) } Assert(tuple_width >= 0); - rel->reltarget.width = tuple_width; + rel->reltarget->width = tuple_width; } /* diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index ddb4ca50c63ded7e92fd6cdafc1a55285a0b22c7..b48f5f28ea9a5ac1c0e60d7d6055852e78118db5 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -1550,7 +1550,7 @@ bitmap_scan_cost_est(PlannerInfo *root, RelOptInfo *rel, Path *ipath) bpath.path.type = T_BitmapHeapPath; bpath.path.pathtype = T_BitmapHeapScan; bpath.path.parent = rel; - bpath.path.pathtarget = &(rel->reltarget); + bpath.path.pathtarget = rel->reltarget; bpath.path.param_info = get_baserel_parampathinfo(root, rel, required_outer); bpath.path.pathkeys = NIL; @@ -1579,7 +1579,7 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths) apath.path.type = T_BitmapAndPath; apath.path.pathtype = T_BitmapAnd; apath.path.parent = rel; - apath.path.pathtarget = &(rel->reltarget); + apath.path.pathtarget = rel->reltarget; apath.path.param_info = NULL; /* not used in bitmap trees */ apath.path.pathkeys = NIL; apath.bitmapquals = paths; @@ -1592,7 +1592,7 @@ bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel, List *paths) bpath.path.type = T_BitmapHeapPath; bpath.path.pathtype = T_BitmapHeapScan; bpath.path.parent = rel; - bpath.path.pathtarget = &(rel->reltarget); + bpath.path.pathtarget = rel->reltarget; bpath.path.param_info = get_baserel_parampathinfo(root, rel, required_outer); bpath.path.pathkeys = NIL; @@ -1815,7 +1815,7 @@ check_index_only(RelOptInfo *rel, IndexOptInfo *index) * look at rel's targetlist, not the attr_needed data, because attr_needed * isn't computed for inheritance child rels. */ - pull_varattnos((Node *) rel->reltarget.exprs, rel->relid, &attrs_used); + pull_varattnos((Node *) rel->reltarget->exprs, rel->relid, &attrs_used); /* Add all the attributes used by restriction clauses. */ foreach(lc, rel->baserestrictinfo) diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 913ac844f09761e478ecd11eea5589848118b0ac..e37bdfd2cfd16704dec49eb4c3900b2b7c55318b 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -3279,7 +3279,7 @@ create_foreignscan_plan(PlannerInfo *root, ForeignPath *best_path, * Note: we must look at rel's targetlist, not the attr_needed data, * because attr_needed isn't computed for inheritance child rels. */ - pull_varattnos((Node *) rel->reltarget.exprs, scan_relid, &attrs_used); + pull_varattnos((Node *) rel->reltarget->exprs, scan_relid, &attrs_used); /* Add all the attributes used by restriction clauses. */ foreach(lc, rel->baserestrictinfo) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 64bc8a8e5977e508557c7a70ac7fde1d9cbdf518..9999eea499171ec66533914640cbe132e91067ba 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -215,8 +215,8 @@ add_vars_to_targetlist(PlannerInfo *root, List *vars, { /* Variable not yet requested, so add to rel's targetlist */ /* XXX is copyObject necessary here? */ - rel->reltarget.exprs = lappend(rel->reltarget.exprs, - copyObject(var)); + rel->reltarget->exprs = lappend(rel->reltarget->exprs, + copyObject(var)); /* reltarget cost and width will be computed later */ } rel->attr_needed[attno] = bms_add_members(rel->attr_needed[attno], diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 443e64e9691bff381d72e9fe6b28b1d5842d9f7c..88d7ea45479b9f4428bd773cb3210d4765a72579 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -83,7 +83,7 @@ query_planner(PlannerInfo *root, List *tlist, /* The only path for it is a trivial Result path */ add_path(final_rel, (Path *) create_result_path(root, final_rel, - &(final_rel->reltarget), + final_rel->reltarget, (List *) parse->jointree->quals)); /* Select cheapest path (pretty easy in this case...) */ diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 8afac0bda73e9fc82afd972c48461eb7a1245c7d..f3a0a44fd889df7bc87532c205e3263f7c23d3ca 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -4534,7 +4534,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) * set_baserel_size_estimates, just do a quick hack for rows and width. */ rel->rows = rel->tuples; - rel->reltarget.width = get_relation_data_width(tableOid, NULL); + rel->reltarget->width = get_relation_data_width(tableOid, NULL); root->total_table_pages = rel->pages; @@ -4550,7 +4550,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) /* Estimate the cost of seq scan + sort */ seqScanPath = create_seqscan_path(root, rel, NULL, 0); cost_sort(&seqScanAndSortPath, root, NIL, - seqScanPath->total_cost, rel->tuples, rel->reltarget.width, + seqScanPath->total_cost, rel->tuples, rel->reltarget->width, comparisonCost, maintenance_work_mem, -1.0); /* Estimate the cost of index scan */ diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 6e7980041f75647123cdbe1e13bd295032441fa8..8f089c59884f7232a94062b810c75c0471a44f92 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -929,7 +929,7 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_SeqScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = parallel_degree > 0 ? true : false; @@ -953,7 +953,7 @@ create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer pathnode->pathtype = T_SampleScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1010,7 +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.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1059,7 +1059,7 @@ create_bitmap_heap_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapHeapScan; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1089,7 +1089,7 @@ create_bitmap_and_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapAnd; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = NULL; /* not used in bitmap trees */ /* @@ -1125,7 +1125,7 @@ create_bitmap_or_path(PlannerInfo *root, pathnode->path.pathtype = T_BitmapOr; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = NULL; /* not used in bitmap trees */ /* @@ -1160,7 +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.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1192,7 +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.pathtarget = rel->reltarget; pathnode->path.param_info = get_appendrel_parampathinfo(rel, required_outer); pathnode->path.parallel_aware = false; @@ -1251,7 +1251,7 @@ create_merge_append_path(PlannerInfo *root, pathnode->path.pathtype = T_MergeAppend; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = get_appendrel_parampathinfo(rel, required_outer); pathnode->path.parallel_aware = false; @@ -1375,7 +1375,7 @@ create_material_path(RelOptInfo *rel, Path *subpath) pathnode->path.pathtype = T_Material; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = subpath->param_info; pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = rel->consider_parallel && @@ -1440,7 +1440,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.pathtarget = rel->reltarget; pathnode->path.param_info = subpath->param_info; pathnode->path.parallel_aware = false; pathnode->path.parallel_safe = rel->consider_parallel && @@ -1656,7 +1656,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.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1692,7 +1692,7 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, pathnode->path.pathtype = T_SubqueryScan; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1720,7 +1720,7 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_FunctionScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1746,7 +1746,7 @@ create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_ValuesScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1771,7 +1771,7 @@ create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer) pathnode->pathtype = T_CteScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1797,7 +1797,7 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->pathtype = T_WorkTableScan; pathnode->parent = rel; - pathnode->pathtarget = &(rel->reltarget); + pathnode->pathtarget = rel->reltarget; pathnode->param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->parallel_aware = false; @@ -1833,7 +1833,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel, pathnode->path.pathtype = T_ForeignScan; pathnode->path.parent = rel; - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; pathnode->path.param_info = get_baserel_parampathinfo(root, rel, required_outer); pathnode->path.parallel_aware = false; @@ -1966,7 +1966,7 @@ create_nestloop_path(PlannerInfo *root, pathnode->path.pathtype = T_NestLoop; pathnode->path.parent = joinrel; - pathnode->path.pathtarget = &(joinrel->reltarget); + pathnode->path.pathtarget = joinrel->reltarget; pathnode->path.param_info = get_joinrel_parampathinfo(root, joinrel, @@ -2029,7 +2029,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.pathtarget = joinrel->reltarget; pathnode->jpath.path.param_info = get_joinrel_parampathinfo(root, joinrel, @@ -2091,7 +2091,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.pathtarget = joinrel->reltarget; pathnode->jpath.path.param_info = get_joinrel_parampathinfo(root, joinrel, @@ -2876,7 +2876,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel, pathnode->path.pathtype = T_ModifyTable; pathnode->path.parent = rel; /* pathtarget is not interesting, just make it minimally valid */ - pathnode->path.pathtarget = &(rel->reltarget); + pathnode->path.pathtarget = rel->reltarget; /* For now, assume we are above any joins, so no parameterization */ pathnode->path.param_info = NULL; pathnode->path.parallel_aware = false; diff --git a/src/backend/optimizer/util/placeholder.c b/src/backend/optimizer/util/placeholder.c index 9e1c0e53333b3186d3264289205b9152abe9e04b..b210914b85391c1397762cb0f795a7c1f055c216 100644 --- a/src/backend/optimizer/util/placeholder.c +++ b/src/backend/optimizer/util/placeholder.c @@ -391,8 +391,8 @@ add_placeholders_to_base_rels(PlannerInfo *root) { RelOptInfo *rel = find_base_rel(root, varno); - rel->reltarget.exprs = lappend(rel->reltarget.exprs, - 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 */ } } @@ -425,9 +425,9 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, if (bms_is_subset(phinfo->ph_eval_at, relids)) { /* Yup, add it to the output */ - joinrel->reltarget.exprs = lappend(joinrel->reltarget.exprs, - phinfo->ph_var); - joinrel->reltarget.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 @@ -447,8 +447,8 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel, 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; + joinrel->reltarget->cost.startup += cost.startup; + joinrel->reltarget->cost.per_tuple += cost.per_tuple; } /* Adjust joinrel's direct_lateral_relids as needed */ diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 763d39d142952be4eba6a4ecf8e7e9b53a2a0190..20e4bf7d125e1b1a744bb8dbf821a5e0a4cc9075 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -24,6 +24,7 @@ #include "optimizer/placeholder.h" #include "optimizer/plancat.h" #include "optimizer/restrictinfo.h" +#include "optimizer/tlist.h" #include "utils/hsearch.h" @@ -106,11 +107,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) 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->reltarget.exprs = NIL; - rel->reltarget.sortgrouprefs = NULL; - rel->reltarget.cost.startup = 0; - rel->reltarget.cost.per_tuple = 0; - rel->reltarget.width = 0; + rel->reltarget = create_empty_pathtarget(); rel->pathlist = NIL; rel->ppilist = NIL; rel->partial_pathlist = NIL; @@ -393,11 +390,7 @@ build_join_rel(PlannerInfo *root, joinrel->consider_startup = (root->tuple_fraction > 0); joinrel->consider_param_startup = false; joinrel->consider_parallel = false; - joinrel->reltarget.exprs = NIL; - joinrel->reltarget.sortgrouprefs = NULL; - joinrel->reltarget.cost.startup = 0; - joinrel->reltarget.cost.per_tuple = 0; - joinrel->reltarget.width = 0; + joinrel->reltarget = create_empty_pathtarget(); joinrel->pathlist = NIL; joinrel->ppilist = NIL; joinrel->partial_pathlist = NIL; @@ -613,7 +606,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, Relids relids = joinrel->relids; ListCell *vars; - foreach(vars, input_rel->reltarget.exprs) + foreach(vars, input_rel->reltarget->exprs) { Var *var = (Var *) lfirst(vars); RelOptInfo *baserel; @@ -643,9 +636,9 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel, if (bms_nonempty_difference(baserel->attr_needed[ndx], relids)) { /* Yup, add it to the output */ - 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]; + 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]; } } } @@ -832,6 +825,7 @@ build_empty_join_rel(PlannerInfo *root) joinrel->relids = NULL; /* empty set */ joinrel->rows = 1; /* we produce one row for such cases */ joinrel->rtekind = RTE_JOIN; + joinrel->reltarget = create_empty_pathtarget(); root->join_rel_list = lappend(root->join_rel_list, joinrel); @@ -882,6 +876,7 @@ fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids) upperrel->consider_startup = (root->tuple_fraction > 0); upperrel->consider_param_startup = false; upperrel->consider_parallel = false; /* might get changed later */ + upperrel->reltarget = create_empty_pathtarget(); upperrel->pathlist = NIL; upperrel->cheapest_startup_path = NULL; upperrel->cheapest_total_path = NULL; diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 9f85dee3872925cb165744c6b99faf00f4cd97b7..b297d87e7ec4abf93f95470f57498f726c85c3b1 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -546,7 +546,7 @@ grouping_is_hashable(List *groupClause) PathTarget * make_pathtarget_from_tlist(List *tlist) { - PathTarget *target = (PathTarget *) palloc0(sizeof(PathTarget)); + PathTarget *target = makeNode(PathTarget); int i; ListCell *lc; @@ -606,7 +606,7 @@ make_tlist_from_pathtarget(PathTarget *target) PathTarget * copy_pathtarget(PathTarget *src) { - PathTarget *dst = (PathTarget *) palloc(sizeof(PathTarget)); + PathTarget *dst = makeNode(PathTarget); /* Copy scalar fields */ memcpy(dst, src, sizeof(PathTarget)); @@ -631,7 +631,7 @@ PathTarget * create_empty_pathtarget(void) { /* This is easy, but we don't want callers to hard-wire this ... */ - return (PathTarget *) palloc0(sizeof(PathTarget)); + return makeNode(PathTarget); } /* diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index fad9988119f0f2c53799cd834303aaad3ce2f589..42c958258b698a952bba43c3f99ff68e1268a4c0 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -259,6 +259,7 @@ typedef enum NodeTag T_EquivalenceClass, T_EquivalenceMember, T_PathKey, + T_PathTarget, T_RestrictInfo, T_PlaceHolderVar, T_SpecialJoinInfo, diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index bdea72c3f4741aa5bfae0f402790678d3a63420c..b48a6183dc2cbedb0aa97d7a0846b57c685abbbd 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -61,34 +61,6 @@ typedef struct AggClauseCosts Size transitionSpace; /* space for pass-by-ref transition data */ } AggClauseCosts; -/* - * This struct contains what we need to know during planning about the - * targetlist (output columns) that a Path will compute. Each RelOptInfo - * includes a default PathTarget, which its individual Paths may merely point - * to. However, in some cases a Path may compute outputs different from other - * Paths, and in that case we make a custom PathTarget struct for it. For - * example, an indexscan might return index expressions that would otherwise - * need to be explicitly calculated. - * - * exprs contains bare expressions; they do not have TargetEntry nodes on top, - * though those will appear in finished Plans. - * - * sortgrouprefs[] is an array of the same length as exprs, containing the - * corresponding sort/group refnos, or zeroes for expressions not referenced - * by sort/group clauses. If sortgrouprefs is NULL (which it always is in - * RelOptInfo.reltarget structs; only upper-level Paths contain this info), we - * have not identified sort/group columns in this tlist. This allows us to - * deal with sort/group refnos when needed with less expense than including - * TargetEntry nodes in the exprs list. - */ -typedef struct PathTarget -{ - List *exprs; /* list of expressions to be computed */ - Index *sortgrouprefs; /* corresponding sort/group refnos, or 0 */ - QualCost cost; /* cost of evaluating the expressions */ - int width; /* estimated avg width of result tuples */ -} PathTarget; - /* * This enum identifies the different types of "upper" (post-scan/join) * relations that we might deal with during planning. @@ -514,7 +486,7 @@ typedef struct RelOptInfo bool consider_parallel; /* consider parallel paths? */ /* default result targetlist for Paths scanning this relation */ - PathTarget reltarget; /* list of Vars/Exprs, cost, width */ + struct PathTarget *reltarget; /* list of Vars/Exprs, cost, width */ /* materialization information */ List *pathlist; /* Path structures */ @@ -765,6 +737,39 @@ typedef struct PathKey } PathKey; +/* + * PathTarget + * + * This struct contains what we need to know during planning about the + * targetlist (output columns) that a Path will compute. Each RelOptInfo + * includes a default PathTarget, which its individual Paths may simply + * reference. However, in some cases a Path may compute outputs different + * from other Paths, and in that case we make a custom PathTarget for it. + * For example, an indexscan might return index expressions that would + * otherwise need to be explicitly calculated. (Note also that "upper" + * relations generally don't have useful default PathTargets.) + * + * exprs contains bare expressions; they do not have TargetEntry nodes on top, + * though those will appear in finished Plans. + * + * sortgrouprefs[] is an array of the same length as exprs, containing the + * corresponding sort/group refnos, or zeroes for expressions not referenced + * by sort/group clauses. If sortgrouprefs is NULL (which it generally is in + * RelOptInfo.reltarget targets; only upper-level Paths contain this info), + * we have not identified sort/group columns in this tlist. This allows us to + * deal with sort/group refnos when needed with less expense than including + * TargetEntry nodes in the exprs list. + */ +typedef struct PathTarget +{ + NodeTag type; + List *exprs; /* list of expressions to be computed */ + Index *sortgrouprefs; /* corresponding sort/group refnos, or 0 */ + QualCost cost; /* cost of evaluating the expressions */ + int width; /* estimated avg width of result tuples */ +} PathTarget; + + /* * ParamPathInfo * @@ -802,7 +807,7 @@ typedef struct ParamPathInfo * "parent" identifies the relation this Path scans, and "pathtarget" * describes the precise set of output columns the Path would compute. * In simple cases all Paths for a given rel share the same targetlist, - * which we represent by having path->pathtarget point to parent->reltarget. + * which we represent by having path->pathtarget equal to parent->reltarget. * * "param_info", if not NULL, links to a ParamPathInfo that identifies outer * relation(s) that provide parameter values to each scan of this path.