diff options
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 26 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 20 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 26 |
3 files changed, 63 insertions, 9 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 91acebc3729..dfb0b38448b 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1210,15 +1210,33 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) * set_values_pathlist * Build the (single) access path for a VALUES RTE * - * There can be no need for a parameterized path here. (Although the SQL - * spec does allow LATERAL (VALUES (x)), the parser will transform that - * into a subquery, so it doesn't end up here.) + * As with subqueries, a VALUES RTE's path might be parameterized due to + * LATERAL references, but that's inherent in the values expressions and + * not a result of pushing down join quals. */ static void set_values_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) { + Relids required_outer; + + /* + * If it's a LATERAL RTE, it might contain some Vars of the current query + * level, requiring it to be treated as parameterized. (NB: even though + * the parser never marks VALUES RTEs as LATERAL, they could be so marked + * by now, as a result of subquery pullup.) + */ + if (rte->lateral) + { + required_outer = pull_varnos_of_level((Node *) rte->values_lists, 0); + /* Enforce convention that empty required_outer is exactly NULL */ + if (bms_is_empty(required_outer)) + required_outer = NULL; + } + else + required_outer = NULL; + /* Generate appropriate path */ - add_path(rel, create_valuesscan_path(root, rel)); + add_path(rel, create_valuesscan_path(root, rel, required_outer)); /* Select cheapest path (pretty easy in this case...) */ set_cheapest(rel); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index d3f04eea4b1..c7d21d00310 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1046,20 +1046,28 @@ cost_functionscan(Path *path, PlannerInfo *root, /* * cost_valuesscan * Determines and returns the cost of scanning a VALUES RTE. + * + * 'baserel' is the relation to be scanned + * 'param_info' is the ParamPathInfo if this is a parameterized path, else NULL */ void -cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel) +cost_valuesscan(Path *path, PlannerInfo *root, + RelOptInfo *baserel, ParamPathInfo *param_info) { Cost startup_cost = 0; Cost run_cost = 0; + QualCost qpqual_cost; Cost cpu_per_tuple; /* Should only be applied to base relations that are values lists */ Assert(baserel->relid > 0); Assert(baserel->rtekind == RTE_VALUES); - /* valuesscans are never parameterized */ - path->rows = baserel->rows; + /* Mark the path with the correct row estimate */ + if (param_info) + path->rows = param_info->ppi_rows; + else + path->rows = baserel->rows; /* * For now, estimate list evaluation cost at one operator eval per list @@ -1068,8 +1076,10 @@ cost_valuesscan(Path *path, PlannerInfo *root, RelOptInfo *baserel) cpu_per_tuple = cpu_operator_cost; /* Add scanning CPU costs */ - startup_cost += baserel->baserestrictcost.startup; - cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost.per_tuple; + get_restriction_qual_cost(root, baserel, param_info, &qpqual_cost); + + startup_cost += qpqual_cost.startup; + cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple; run_cost += cpu_per_tuple * baserel->tuples; path->startup_cost = startup_cost; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index fe0e4d7c201..f54c3931ce4 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -148,6 +148,32 @@ add_paths_to_joinrel(PlannerInfo *root, } /* + * However, when a LATERAL subquery is involved, we have to be a bit + * laxer, because there may simply not be any paths for the joinrel that + * aren't parameterized by whatever the subquery is parameterized by. + * Hence, add to param_source_rels anything that is in the minimum + * parameterization of either input (and not in the other input). + * + * XXX need a more principled way of determining minimum parameterization. + */ + if (outerrel->cheapest_total_path == NULL) + { + Path *cheapest = (Path *) linitial(outerrel->cheapest_parameterized_paths); + + param_source_rels = bms_join(param_source_rels, + bms_difference(PATH_REQ_OUTER(cheapest), + innerrel->relids)); + } + if (innerrel->cheapest_total_path == NULL) + { + Path *cheapest = (Path *) linitial(innerrel->cheapest_parameterized_paths); + + param_source_rels = bms_join(param_source_rels, + bms_difference(PATH_REQ_OUTER(cheapest), + outerrel->relids)); + } + + /* * 1. Consider mergejoin paths where both relations must be explicitly * sorted. Skip this if we can't mergejoin. */ |