aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r--src/backend/optimizer/path/allpaths.c26
-rw-r--r--src/backend/optimizer/path/costsize.c20
-rw-r--r--src/backend/optimizer/path/joinpath.c26
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.
*/