diff options
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/pathnode.c | 26 | ||||
-rw-r--r-- | src/backend/optimizer/util/var.c | 165 |
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 |