aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/pathnode.c26
-rw-r--r--src/backend/optimizer/util/var.c165
2 files changed, 108 insertions, 83 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 00052f5c846..11de5c70d80 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -193,7 +193,7 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
* and cheapest_total. The cheapest_parameterized_paths list collects paths
* that are cheapest-total for their parameterization (i.e., there is no
* cheaper path with the same or weaker parameterization). This list always
- * includes the unparameterized cheapest-total path, too.
+ * includes the unparameterized cheapest-total path, too, if there is one.
*
* This is normally called only after we've finished constructing the path
* list for the rel node.
@@ -250,15 +250,18 @@ set_cheapest(RelOptInfo *parent_rel)
cheapest_total_path = path;
}
- if (cheapest_total_path == NULL)
+ if (cheapest_total_path == NULL && !have_parameterized_paths)
elog(ERROR, "could not devise a query plan for the given query");
parent_rel->cheapest_startup_path = cheapest_startup_path;
parent_rel->cheapest_total_path = cheapest_total_path;
parent_rel->cheapest_unique_path = NULL; /* computed only if needed */
- /* Seed the parameterized-paths list with the cheapest total */
- parent_rel->cheapest_parameterized_paths = list_make1(cheapest_total_path);
+ /* Seed the parameterized-paths list with the cheapest total, if any */
+ if (cheapest_total_path)
+ parent_rel->cheapest_parameterized_paths = list_make1(cheapest_total_path);
+ else
+ parent_rel->cheapest_parameterized_paths = NIL;
/* And, if there are any parameterized paths, add them in one at a time */
if (have_parameterized_paths)
@@ -1131,6 +1134,13 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
int numCols;
ListCell *lc;
+ /* XXX temporary band-aid to not crash on LATERAL queries */
+ if (subpath == NULL)
+ {
+ Assert(subpath == rel->cheapest_total_path);
+ return NULL;
+ }
+
/* Caller made a mistake if subpath isn't cheapest_total ... */
Assert(subpath == rel->cheapest_total_path);
Assert(subpath->parent == rel);
@@ -1657,16 +1667,18 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
* returning the pathnode.
*/
Path *
-create_functionscan_path(PlannerInfo *root, RelOptInfo *rel)
+create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
+ Relids required_outer)
{
Path *pathnode = makeNode(Path);
pathnode->pathtype = T_FunctionScan;
pathnode->parent = rel;
- pathnode->param_info = NULL; /* never parameterized at present */
+ pathnode->param_info = get_baserel_parampathinfo(root, rel,
+ required_outer);
pathnode->pathkeys = NIL; /* for now, assume unordered result */
- cost_functionscan(pathnode, root, rel);
+ cost_functionscan(pathnode, root, rel, pathnode->param_info);
return pathnode;
}
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 9bc90c25313..81332ff1cd1 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -42,16 +42,15 @@ typedef struct
typedef struct
{
- int var_location;
+ List *vars;
int sublevels_up;
-} locate_var_of_level_context;
+} pull_vars_context;
typedef struct
{
int var_location;
- int relid;
int sublevels_up;
-} locate_var_of_relation_context;
+} locate_var_of_level_context;
typedef struct
{
@@ -77,12 +76,11 @@ typedef struct
static bool pull_varnos_walker(Node *node,
pull_varnos_context *context);
static bool pull_varattnos_walker(Node *node, pull_varattnos_context *context);
+static bool pull_vars_walker(Node *node, pull_vars_context *context);
static bool contain_var_clause_walker(Node *node, void *context);
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
static bool locate_var_of_level_walker(Node *node,
locate_var_of_level_context *context);
-static bool locate_var_of_relation_walker(Node *node,
- locate_var_of_relation_context *context);
static bool find_minimum_var_level_walker(Node *node,
find_minimum_var_level_context *context);
static bool pull_var_clause_walker(Node *node,
@@ -122,6 +120,31 @@ pull_varnos(Node *node)
return context.varnos;
}
+/*
+ * pull_varnos_of_level
+ * Create a set of all the distinct varnos present in a parsetree.
+ * Only Vars of the specified level are considered.
+ */
+Relids
+pull_varnos_of_level(Node *node, int levelsup)
+{
+ pull_varnos_context context;
+
+ context.varnos = NULL;
+ context.sublevels_up = levelsup;
+
+ /*
+ * Must be prepared to start with a Query or a bare expression tree; if
+ * it's a Query, we don't want to increment sublevels_up.
+ */
+ query_or_expression_tree_walker(node,
+ pull_varnos_walker,
+ (void *) &context,
+ 0);
+
+ return context.varnos;
+}
+
static bool
pull_varnos_walker(Node *node, pull_varnos_context *context)
{
@@ -231,6 +254,66 @@ pull_varattnos_walker(Node *node, pull_varattnos_context *context)
/*
+ * pull_vars_of_level
+ * Create a list of all Vars referencing the specified query level
+ * in the given parsetree.
+ *
+ * This is used on unplanned parsetrees, so we don't expect to see any
+ * PlaceHolderVars.
+ *
+ * Caution: the Vars are not copied, only linked into the list.
+ */
+List *
+pull_vars_of_level(Node *node, int levelsup)
+{
+ pull_vars_context context;
+
+ context.vars = NIL;
+ context.sublevels_up = levelsup;
+
+ /*
+ * Must be prepared to start with a Query or a bare expression tree; if
+ * it's a Query, we don't want to increment sublevels_up.
+ */
+ query_or_expression_tree_walker(node,
+ pull_vars_walker,
+ (void *) &context,
+ 0);
+
+ return context.vars;
+}
+
+static bool
+pull_vars_walker(Node *node, pull_vars_context *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Var))
+ {
+ Var *var = (Var *) node;
+
+ if (var->varlevelsup == context->sublevels_up)
+ context->vars = lappend(context->vars, var);
+ return false;
+ }
+ Assert(!IsA(node, PlaceHolderVar));
+ if (IsA(node, Query))
+ {
+ /* Recurse into RTE subquery or not-yet-planned sublink subquery */
+ bool result;
+
+ context->sublevels_up++;
+ result = query_tree_walker((Query *) node, pull_vars_walker,
+ (void *) context, 0);
+ context->sublevels_up--;
+ return result;
+ }
+ return expression_tree_walker(node, pull_vars_walker,
+ (void *) context);
+}
+
+
+/*
* contain_var_clause
* Recursively scan a clause to discover whether it contains any Var nodes
* (of the current query level).
@@ -406,76 +489,6 @@ locate_var_of_level_walker(Node *node,
/*
- * locate_var_of_relation
- * Find the parse location of any Var of the specified relation.
- *
- * Returns -1 if no such Var is in the querytree, or if they all have
- * unknown parse location.
- *
- * Will recurse into sublinks. Also, may be invoked directly on a Query.
- */
-int
-locate_var_of_relation(Node *node, int relid, int levelsup)
-{
- locate_var_of_relation_context context;
-
- context.var_location = -1; /* in case we find nothing */
- context.relid = relid;
- context.sublevels_up = levelsup;
-
- (void) query_or_expression_tree_walker(node,
- locate_var_of_relation_walker,
- (void *) &context,
- 0);
-
- return context.var_location;
-}
-
-static bool
-locate_var_of_relation_walker(Node *node,
- locate_var_of_relation_context *context)
-{
- if (node == NULL)
- return false;
- if (IsA(node, Var))
- {
- Var *var = (Var *) node;
-
- if (var->varno == context->relid &&
- var->varlevelsup == context->sublevels_up &&
- var->location >= 0)
- {
- context->var_location = var->location;
- return true; /* abort tree traversal and return true */
- }
- return false;
- }
- if (IsA(node, CurrentOfExpr))
- {
- /* since CurrentOfExpr doesn't carry location, nothing we can do */
- return false;
- }
- /* No extra code needed for PlaceHolderVar; just look in contained expr */
- if (IsA(node, Query))
- {
- /* Recurse into subselects */
- bool result;
-
- context->sublevels_up++;
- result = query_tree_walker((Query *) node,
- locate_var_of_relation_walker,
- (void *) context,
- 0);
- context->sublevels_up--;
- return result;
- }
- return expression_tree_walker(node,
- locate_var_of_relation_walker,
- (void *) context);
-}
-
-
-/*
* find_minimum_var_level
* Recursively scan a clause to find the lowest variable level it
* contains --- for example, zero is returned if there are any local