diff options
Diffstat (limited to 'src/backend/optimizer/util/var.c')
-rw-r--r-- | src/backend/optimizer/util/var.c | 81 |
1 files changed, 69 insertions, 12 deletions
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c index bed7be7f08a..ec9f9dafd0b 100644 --- a/src/backend/optimizer/util/var.c +++ b/src/backend/optimizer/util/var.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.26 2000/04/12 17:15:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.27 2000/09/12 21:06:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "postgres.h" +#include "nodes/plannodes.h" #include "optimizer/clauses.h" #include "optimizer/var.h" @@ -23,10 +24,17 @@ typedef struct { List *varlist; + int sublevels_up; +} pull_varnos_context; + +typedef struct +{ + List *varlist; bool includeUpperVars; } pull_var_clause_context; -static bool pull_varnos_walker(Node *node, List **listptr); +static bool pull_varnos_walker(Node *node, + pull_varnos_context *context); static bool contain_var_clause_walker(Node *node, void *context); static bool pull_var_clause_walker(Node *node, pull_var_clause_context *context); @@ -35,21 +43,39 @@ static bool pull_var_clause_walker(Node *node, /* * pull_varnos * - * Create a list of all the distinct varnos present in a parsetree - * (tlist or qual). Note that only varnos attached to level-zero - * Vars are considered --- upper Vars refer to some other rtable! + * Create a list of all the distinct varnos present in a parsetree. + * Only varnos that reference level-zero rtable entries are considered. + * + * NOTE: unlike other routines in this file, pull_varnos() is used on + * not-yet-planned expressions. It may therefore find bare SubLinks, + * and if so it needs to recurse into them to look for uplevel references + * to the desired rtable level! But when we find a completed SubPlan, + * we only need to look at the parameters passed to the subplan. */ List * pull_varnos(Node *node) { - List *result = NIL; + pull_varnos_context context; + + context.varlist = NIL; + context.sublevels_up = 0; + + /* + * Must be prepared to start with a Query or a bare expression tree; + * if it's a Query, go straight to query_tree_walker to make sure that + * sublevels_up doesn't get incremented prematurely. + */ + if (node && IsA(node, Query)) + query_tree_walker((Query *) node, pull_varnos_walker, + (void *) &context); + else + pull_varnos_walker(node, &context); - pull_varnos_walker(node, &result); - return result; + return context.varlist; } static bool -pull_varnos_walker(Node *node, List **listptr) +pull_varnos_walker(Node *node, pull_varnos_context *context) { if (node == NULL) return false; @@ -57,11 +83,42 @@ pull_varnos_walker(Node *node, List **listptr) { Var *var = (Var *) node; - if (var->varlevelsup == 0 && !intMember(var->varno, *listptr)) - *listptr = lconsi(var->varno, *listptr); + if (var->varlevelsup == context->sublevels_up && + !intMember(var->varno, context->varlist)) + context->varlist = lconsi(var->varno, context->varlist); + return false; + } + if (is_subplan(node)) + { + /* + * Already-planned subquery. Examine the args list (parameters + * to be passed to subquery), as well as the "oper" list which + * is executed by the outer query. But short-circuit recursion into + * the subquery itself, which would be a waste of effort. + */ + Expr *expr = (Expr *) node; + + if (pull_varnos_walker((Node*) ((SubPlan*) expr->oper)->sublink->oper, + context)) + return true; + if (pull_varnos_walker((Node *) expr->args, + context)) + return true; return false; } - return expression_tree_walker(node, pull_varnos_walker, (void *) listptr); + if (IsA(node, Query)) + { + /* Recurse into not-yet-planned subquery */ + bool result; + + context->sublevels_up++; + result = query_tree_walker((Query *) node, pull_varnos_walker, + (void *) context); + context->sublevels_up--; + return result; + } + return expression_tree_walker(node, pull_varnos_walker, + (void *) context); } /* |