aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/var.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/var.c')
-rw-r--r--src/backend/optimizer/util/var.c81
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);
}
/*