diff options
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 562 |
1 files changed, 410 insertions, 152 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index b085553a1ad..19bf7340ad4 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -46,13 +46,28 @@ int geqo_threshold; join_search_hook_type join_search_hook = NULL; +static void set_base_rel_sizes(PlannerInfo *root); static void set_base_rel_pathlists(PlannerInfo *root); +static void set_rel_size(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte); static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); +static void set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte); static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); +static void set_foreign_size(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte); +static void set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte); +static void set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte); static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); +static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels, + List *all_child_pathkeys, + Relids required_outer); static List *accumulate_append_subpath(List *subpaths, Path *path); static void set_dummy_rel_pathlist(RelOptInfo *rel); static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -65,8 +80,6 @@ static void set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); static void set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); -static void set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, - RangeTblEntry *rte); static RelOptInfo *make_rel_from_joinlist(PlannerInfo *root, List *joinlist); static bool subquery_is_pushdown_safe(Query *subquery, Query *topquery, bool *differentTypes); @@ -91,10 +104,33 @@ RelOptInfo * make_one_rel(PlannerInfo *root, List *joinlist) { RelOptInfo *rel; + Index rti; + + /* + * Construct the all_baserels Relids set. + */ + root->all_baserels = NULL; + for (rti = 1; rti < root->simple_rel_array_size; rti++) + { + RelOptInfo *brel = root->simple_rel_array[rti]; + + /* there may be empty slots corresponding to non-baserel RTEs */ + if (brel == NULL) + continue; + + Assert(brel->relid == rti); /* sanity check on array */ + + /* ignore RTEs that are "other rels" */ + if (brel->reloptkind != RELOPT_BASEREL) + continue; + + root->all_baserels = bms_add_member(root->all_baserels, brel->relid); + } /* * Generate access paths for the base rels. */ + set_base_rel_sizes(root); set_base_rel_pathlists(root); /* @@ -105,33 +141,39 @@ make_one_rel(PlannerInfo *root, List *joinlist) /* * The result should join all and only the query's base rels. */ -#ifdef USE_ASSERT_CHECKING - { - int num_base_rels = 0; - Index rti; + Assert(bms_equal(rel->relids, root->all_baserels)); - for (rti = 1; rti < root->simple_rel_array_size; rti++) - { - RelOptInfo *brel = root->simple_rel_array[rti]; + return rel; +} - if (brel == NULL) - continue; +/* + * set_base_rel_sizes + * Set the size estimates (rows and widths) for each base-relation entry. + * + * We do this in a separate pass over the base rels so that rowcount + * estimates are available for parameterized path generation. + */ +static void +set_base_rel_sizes(PlannerInfo *root) +{ + Index rti; - Assert(brel->relid == rti); /* sanity check on array */ + for (rti = 1; rti < root->simple_rel_array_size; rti++) + { + RelOptInfo *rel = root->simple_rel_array[rti]; - /* ignore RTEs that are "other rels" */ - if (brel->reloptkind != RELOPT_BASEREL) - continue; + /* there may be empty slots corresponding to non-baserel RTEs */ + if (rel == NULL) + continue; - Assert(bms_is_member(rti, rel->relids)); - num_base_rels++; - } + Assert(rel->relid == rti); /* sanity check on array */ - Assert(bms_num_members(rel->relids) == num_base_rels); - } -#endif + /* ignore RTEs that are "other rels" */ + if (rel->reloptkind != RELOPT_BASEREL) + continue; - return rel; + set_rel_size(root, rel, rti, root->simple_rte_array[rti]); + } } /* @@ -164,11 +206,11 @@ set_base_rel_pathlists(PlannerInfo *root) } /* - * set_rel_pathlist - * Build access paths for a base relation + * set_rel_size + * Set size estimates for a base relation */ static void -set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, +set_rel_size(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte) { if (rel->reloptkind == RELOPT_BASEREL && @@ -179,13 +221,18 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, * so set up a single dummy path for it. Here we only check this for * regular baserels; if it's an otherrel, CE was already checked in * set_append_rel_pathlist(). + * + * In this case, we go ahead and set up the relation's path right away + * instead of leaving it for set_rel_pathlist to do. This is because + * we don't have a convention for marking a rel as dummy except by + * assigning a dummy path to it. */ set_dummy_rel_pathlist(rel); } else if (rte->inh) { /* It's an "append relation", process accordingly */ - set_append_rel_pathlist(root, rel, rti, rte); + set_append_rel_size(root, rel, rti, rte); } else { @@ -195,28 +242,32 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, if (rte->relkind == RELKIND_FOREIGN_TABLE) { /* Foreign table */ - set_foreign_pathlist(root, rel, rte); + set_foreign_size(root, rel, rte); } else { /* Plain relation */ - set_plain_rel_pathlist(root, rel, rte); + set_plain_rel_size(root, rel, rte); } break; case RTE_SUBQUERY: - /* Subquery --- generate a separate plan for it */ + /* + * Subqueries don't support parameterized paths, so just go + * ahead and build their paths immediately. + */ set_subquery_pathlist(root, rel, rti, rte); break; case RTE_FUNCTION: - /* RangeFunction --- generate a suitable path for it */ - set_function_pathlist(root, rel, rte); + set_function_size_estimates(root, rel); break; case RTE_VALUES: - /* Values list --- generate a suitable path for it */ - set_values_pathlist(root, rel, rte); + set_values_size_estimates(root, rel); break; case RTE_CTE: - /* CTE reference --- generate a suitable path for it */ + /* + * CTEs don't support parameterized paths, so just go ahead + * and build their paths immediately. + */ if (rte->self_reference) set_worktable_pathlist(root, rel, rte); else @@ -227,6 +278,60 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, break; } } +} + +/* + * set_rel_pathlist + * Build access paths for a base relation + */ +static void +set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte) +{ + if (IS_DUMMY_REL(rel)) + { + /* We already proved the relation empty, so nothing more to do */ + } + else if (rte->inh) + { + /* It's an "append relation", process accordingly */ + set_append_rel_pathlist(root, rel, rti, rte); + } + else + { + switch (rel->rtekind) + { + case RTE_RELATION: + if (rte->relkind == RELKIND_FOREIGN_TABLE) + { + /* Foreign table */ + set_foreign_pathlist(root, rel, rte); + } + else + { + /* Plain relation */ + set_plain_rel_pathlist(root, rel, rte); + } + break; + case RTE_SUBQUERY: + /* Subquery --- fully handled during set_rel_size */ + break; + case RTE_FUNCTION: + /* RangeFunction */ + set_function_pathlist(root, rel, rte); + break; + case RTE_VALUES: + /* Values list */ + set_values_pathlist(root, rel, rte); + break; + case RTE_CTE: + /* CTE reference --- fully handled during set_rel_size */ + break; + default: + elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind); + break; + } + } #ifdef OPTIMIZER_DEBUG debug_print_rel(root, rel); @@ -234,11 +339,11 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, } /* - * set_plain_rel_pathlist - * Build access paths for a plain relation (no subquery, no inheritance) + * set_plain_rel_size + * Set size estimates for a plain relation (no subquery, no inheritance) */ static void -set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { /* * Test any partial indexes of rel for applicability. We must do this @@ -259,15 +364,15 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) check_partial_indexes(root, rel); set_baserel_size_estimates(root, rel); } +} - /* - * Generate paths and add them to the rel's pathlist. - * - * Note: add_path() will discard any paths that are dominated by another - * available path, keeping only those paths that are superior along at - * least one dimension of cost or sortedness. - */ - +/* + * set_plain_rel_pathlist + * Build access paths for a plain relation (no subquery, no inheritance) + */ +static void +set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ /* Consider sequential scan */ add_path(rel, create_seqscan_path(root, rel)); @@ -282,8 +387,33 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) } /* - * set_append_rel_pathlist - * Build access paths for an "append relation" + * set_foreign_size + * Set size estimates for a foreign table RTE + */ +static void +set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* Mark rel with estimated output rows, width, etc */ + set_foreign_size_estimates(root, rel); +} + +/* + * set_foreign_pathlist + * Build the (single) access path for a foreign table RTE + */ +static void +set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* Generate appropriate path */ + add_path(rel, (Path *) create_foreignscan_path(root, rel)); + + /* Select cheapest path (pretty easy in this case...) */ + set_cheapest(rel); +} + +/* + * set_append_rel_size + * Set size estimates for an "append relation" * * The passed-in rel and RTE represent the entire append relation. The * relation's contents are computed by appending together the output of @@ -293,13 +423,10 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) * a good thing because their outputs are not the same size. */ static void -set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte) +set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte) { int parentRTindex = rti; - List *live_childrels = NIL; - List *subpaths = NIL; - List *all_child_pathkeys = NIL; double parent_rows; double parent_size; double *parent_attrsizes; @@ -325,10 +452,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, nattrs = rel->max_attr - rel->min_attr + 1; parent_attrsizes = (double *) palloc0(nattrs * sizeof(double)); - /* - * Generate access paths for each member relation, and pick the cheapest - * path for each one. - */ foreach(l, root->append_rel_list) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); @@ -337,7 +460,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *childrel; List *childquals; Node *childqual; - ListCell *lcp; ListCell *parentvars; ListCell *childvars; @@ -394,8 +516,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, { /* * This child need not be scanned, so we can omit it from the - * appendrel. Mark it with a dummy cheapest-path though, in case - * best_appendrel_indexscan() looks at it later. + * appendrel. */ set_dummy_rel_pathlist(childrel); continue; @@ -438,65 +559,20 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, */ /* - * Compute the child's access paths. + * Compute the child's size. */ - set_rel_pathlist(root, childrel, childRTindex, childRTE); + set_rel_size(root, childrel, childRTindex, childRTE); /* * It is possible that constraint exclusion detected a contradiction * within a child subquery, even though we didn't prove one above. - * If what we got back was a dummy path, we can skip this child. + * If so, we can skip this child. */ - if (IS_DUMMY_PATH(childrel->cheapest_total_path)) + if (IS_DUMMY_REL(childrel)) continue; /* - * Child is live, so add its cheapest access path to the Append path - * we are constructing for the parent. - */ - subpaths = accumulate_append_subpath(subpaths, - childrel->cheapest_total_path); - - /* Remember which childrels are live, for MergeAppend logic below */ - live_childrels = lappend(live_childrels, childrel); - - /* - * Collect a list of all the available path orderings for all the - * children. We use this as a heuristic to indicate which sort - * orderings we should build MergeAppend paths for. - */ - foreach(lcp, childrel->pathlist) - { - Path *childpath = (Path *) lfirst(lcp); - List *childkeys = childpath->pathkeys; - ListCell *lpk; - bool found = false; - - /* Ignore unsorted paths */ - if (childkeys == NIL) - continue; - - /* Have we already seen this ordering? */ - foreach(lpk, all_child_pathkeys) - { - List *existing_pathkeys = (List *) lfirst(lpk); - - if (compare_pathkeys(existing_pathkeys, - childkeys) == PATHKEYS_EQUAL) - { - found = true; - break; - } - } - if (!found) - { - /* No, so add it to all_child_pathkeys */ - all_child_pathkeys = lappend(all_child_pathkeys, childkeys); - } - } - - /* - * Accumulate size information from each child. + * Accumulate size information from each live child. */ if (childrel->rows > 0) { @@ -560,24 +636,208 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, rel->tuples = parent_rows; pfree(parent_attrsizes); +} + +/* + * set_append_rel_pathlist + * Build access paths for an "append relation" + */ +static void +set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte) +{ + int parentRTindex = rti; + List *live_childrels = NIL; + List *subpaths = NIL; + List *all_child_pathkeys = NIL; + List *all_child_outers = NIL; + ListCell *l; /* - * Next, build an unordered Append path for the rel. (Note: this is - * correct even if we have zero or one live subpath due to constraint - * exclusion.) + * Generate access paths for each member relation, and remember the + * cheapest path for each one. Also, identify all pathkeys (orderings) + * and parameterizations (required_outer sets) available for the member + * relations. + */ + foreach(l, root->append_rel_list) + { + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + int childRTindex; + RangeTblEntry *childRTE; + RelOptInfo *childrel; + ListCell *lcp; + + /* append_rel_list contains all append rels; ignore others */ + if (appinfo->parent_relid != parentRTindex) + continue; + + /* Re-locate the child RTE and RelOptInfo */ + childRTindex = appinfo->child_relid; + childRTE = root->simple_rte_array[childRTindex]; + childrel = root->simple_rel_array[childRTindex]; + + /* + * Compute the child's access paths. + */ + set_rel_pathlist(root, childrel, childRTindex, childRTE); + + /* + * If child is dummy, ignore it. + */ + if (IS_DUMMY_REL(childrel)) + continue; + + /* + * Child is live, so add its cheapest access path to the Append path + * we are constructing for the parent. + */ + subpaths = accumulate_append_subpath(subpaths, + childrel->cheapest_total_path); + + /* Remember which childrels are live, for logic below */ + live_childrels = lappend(live_childrels, childrel); + + /* + * Collect lists of all the available path orderings and + * parameterizations for all the children. We use these as a + * heuristic to indicate which sort orderings and parameterizations we + * should build Append and MergeAppend paths for. + */ + foreach(lcp, childrel->pathlist) + { + Path *childpath = (Path *) lfirst(lcp); + List *childkeys = childpath->pathkeys; + Relids childouter = childpath->required_outer; + + /* Unsorted paths don't contribute to pathkey list */ + if (childkeys != NIL) + { + ListCell *lpk; + bool found = false; + + /* Have we already seen this ordering? */ + foreach(lpk, all_child_pathkeys) + { + List *existing_pathkeys = (List *) lfirst(lpk); + + if (compare_pathkeys(existing_pathkeys, + childkeys) == PATHKEYS_EQUAL) + { + found = true; + break; + } + } + if (!found) + { + /* No, so add it to all_child_pathkeys */ + all_child_pathkeys = lappend(all_child_pathkeys, + childkeys); + } + } + + /* Unparameterized paths don't contribute to param-set list */ + if (childouter) + { + ListCell *lco; + bool found = false; + + /* Have we already seen this param set? */ + foreach(lco, all_child_outers) + { + Relids existing_outers = (Relids) lfirst(lco); + + if (bms_equal(existing_outers, childouter)) + { + found = true; + break; + } + } + if (!found) + { + /* No, so add it to all_child_outers */ + all_child_outers = lappend(all_child_outers, + childouter); + } + } + } + } + + /* + * Next, build an unordered, unparameterized Append path for the rel. + * (Note: this is correct even if we have zero or one live subpath due to + * constraint exclusion.) */ add_path(rel, (Path *) create_append_path(rel, subpaths)); /* - * Next, build MergeAppend paths based on the collected list of child - * pathkeys. We consider both cheapest-startup and cheapest-total cases, - * ie, for each interesting ordering, collect all the cheapest startup - * subpaths and all the cheapest total paths, and build a MergeAppend path - * for each list. + * Build unparameterized MergeAppend paths based on the collected list of + * child pathkeys. + */ + generate_mergeappend_paths(root, rel, live_childrels, + all_child_pathkeys, NULL); + + /* + * Build Append and MergeAppend paths for each parameterization seen + * among the child rels. (This may look pretty expensive, but in most + * cases of practical interest, the child relations will tend to expose + * the same parameterizations and pathkeys, so that not that many cases + * actually get considered here.) */ - foreach(l, all_child_pathkeys) + foreach(l, all_child_outers) + { + Relids required_outer = (Relids) lfirst(l); + ListCell *lcr; + + /* Select the child paths for an Append with this parameterization */ + subpaths = NIL; + foreach(lcr, live_childrels) + { + RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr); + Path *cheapest_total; + + cheapest_total = + get_cheapest_path_for_pathkeys(childrel->pathlist, + NIL, + required_outer, + TOTAL_COST); + Assert(cheapest_total != NULL); + + subpaths = accumulate_append_subpath(subpaths, cheapest_total); + } + add_path(rel, (Path *) create_append_path(rel, subpaths)); + + /* And build parameterized MergeAppend paths */ + generate_mergeappend_paths(root, rel, live_childrels, + all_child_pathkeys, required_outer); + } + + /* Select cheapest paths */ + set_cheapest(rel); +} + +/* + * generate_mergeappend_paths + * Generate MergeAppend paths for an append relation + * + * Generate a path for each ordering (pathkey list) appearing in + * all_child_pathkeys. If required_outer isn't NULL, accept paths having + * those relations as required outer relations. + * + * We consider both cheapest-startup and cheapest-total cases, ie, for each + * interesting ordering, collect all the cheapest startup subpaths and all the + * cheapest total paths, and build a MergeAppend path for each case. + */ +static void +generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels, + List *all_child_pathkeys, + Relids required_outer) +{ + ListCell *lcp; + + foreach(lcp, all_child_pathkeys) { - List *pathkeys = (List *) lfirst(l); + List *pathkeys = (List *) lfirst(lcp); List *startup_subpaths = NIL; List *total_subpaths = NIL; bool startup_neq_total = false; @@ -594,20 +854,32 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, cheapest_startup = get_cheapest_path_for_pathkeys(childrel->pathlist, pathkeys, + required_outer, STARTUP_COST); cheapest_total = get_cheapest_path_for_pathkeys(childrel->pathlist, pathkeys, + required_outer, TOTAL_COST); /* - * If we can't find any paths with the right order just add the - * cheapest-total path; we'll have to sort it. + * If we can't find any paths with the right order just use the + * cheapest-total path; we'll have to sort it later. We can + * use the cheapest path for the parameterization, though. */ - if (cheapest_startup == NULL) - cheapest_startup = childrel->cheapest_total_path; - if (cheapest_total == NULL) - cheapest_total = childrel->cheapest_total_path; + if (cheapest_startup == NULL || cheapest_total == NULL) + { + if (required_outer) + cheapest_startup = cheapest_total = + get_cheapest_path_for_pathkeys(childrel->pathlist, + NIL, + required_outer, + TOTAL_COST); + else + cheapest_startup = cheapest_total = + childrel->cheapest_total_path; + Assert(cheapest_total != NULL); + } /* * Notice whether we actually have different paths for the @@ -634,9 +906,6 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, total_subpaths, pathkeys)); } - - /* Select cheapest path */ - set_cheapest(rel); } /* @@ -667,7 +936,7 @@ accumulate_append_subpath(List *subpaths, Path *path) * Build a dummy path for a relation that's been excluded by constraints * * Rather than inventing a special "dummy" path type, we represent this as an - * AppendPath with no members (see also IS_DUMMY_PATH macro). + * AppendPath with no members (see also IS_DUMMY_PATH/IS_DUMMY_REL macros). */ static void set_dummy_rel_pathlist(RelOptInfo *rel) @@ -676,6 +945,9 @@ set_dummy_rel_pathlist(RelOptInfo *rel) rel->rows = 0; rel->width = 0; + /* Discard any pre-existing paths; no further need for them */ + rel->pathlist = NIL; + add_path(rel, (Path *) create_append_path(rel, NIL)); /* Select cheapest path (pretty easy in this case...) */ @@ -707,6 +979,9 @@ has_multiple_baserels(PlannerInfo *root) /* * set_subquery_pathlist * Build the (single) access path for a subquery RTE + * + * There's no need for a separate set_subquery_size phase, since we don't + * support parameterized paths for subqueries. */ static void set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, @@ -847,9 +1122,6 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, static void set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { - /* Mark rel with estimated output rows, width, etc */ - set_function_size_estimates(root, rel); - /* Generate appropriate path */ add_path(rel, create_functionscan_path(root, rel)); @@ -864,9 +1136,6 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { - /* Mark rel with estimated output rows, width, etc */ - set_values_size_estimates(root, rel); - /* Generate appropriate path */ add_path(rel, create_valuesscan_path(root, rel)); @@ -877,6 +1146,9 @@ set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* * set_cte_pathlist * Build the (single) access path for a non-self-reference CTE RTE + * + * There's no need for a separate set_cte_size phase, since we don't + * support parameterized paths for CTEs. */ static void set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) @@ -935,6 +1207,9 @@ set_cte_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) /* * set_worktable_pathlist * Build the (single) access path for a self-reference CTE RTE + * + * There's no need for a separate set_worktable_size phase, since we don't + * support parameterized paths for CTEs. */ static void set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) @@ -974,23 +1249,6 @@ set_worktable_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) } /* - * set_foreign_pathlist - * Build the (single) access path for a foreign table RTE - */ -static void -set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) -{ - /* Mark rel with estimated output rows, width, etc */ - set_foreign_size_estimates(root, rel); - - /* Generate appropriate path */ - add_path(rel, (Path *) create_foreignscan_path(root, rel)); - - /* Select cheapest path (pretty easy in this case...) */ - set_cheapest(rel); -} - -/* * make_rel_from_joinlist * Build access paths using a "joinlist" to guide the join path search. * |