summaryrefslogtreecommitdiff
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.c113
1 files changed, 112 insertions, 1 deletions
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index a365b7b159e..bdd5baf521a 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.50 2003/05/28 22:32:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.51 2003/06/06 15:04:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -37,6 +37,12 @@ typedef struct
typedef struct
{
+ int min_varlevel;
+ int sublevels_up;
+} find_minimum_var_level_context;
+
+typedef struct
+{
FastList varlist;
bool includeUpperVars;
} pull_var_clause_context;
@@ -54,6 +60,8 @@ static bool contain_var_reference_walker(Node *node,
static bool contain_var_clause_walker(Node *node, void *context);
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
static bool contain_vars_above_level_walker(Node *node, int *sublevels_up);
+static bool find_minimum_var_level_walker(Node *node,
+ find_minimum_var_level_context *context);
static bool pull_var_clause_walker(Node *node,
pull_var_clause_context *context);
static Node *flatten_join_alias_vars_mutator(Node *node,
@@ -326,6 +334,109 @@ contain_vars_above_level_walker(Node *node, int *sublevels_up)
/*
+ * 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
+ * variables, one if there are no local variables but there are
+ * one-level-up outer references, etc. Subqueries are scanned to see
+ * if they possess relevant outer references. (But any local variables
+ * within subqueries are not relevant.)
+ *
+ * -1 is returned if the clause has no variables at all.
+ *
+ * Will recurse into sublinks. Also, may be invoked directly on a Query.
+ */
+int
+find_minimum_var_level(Node *node)
+{
+ find_minimum_var_level_context context;
+
+ context.min_varlevel = -1; /* signifies nothing found yet */
+ context.sublevels_up = 0;
+
+ (void) query_or_expression_tree_walker(node,
+ find_minimum_var_level_walker,
+ (void *) &context,
+ 0);
+
+ return context.min_varlevel;
+}
+
+static bool
+find_minimum_var_level_walker(Node *node,
+ find_minimum_var_level_context *context)
+{
+ if (node == NULL)
+ return false;
+ if (IsA(node, Var))
+ {
+ int varlevelsup = ((Var *) node)->varlevelsup;
+
+ /* convert levelsup to frame of reference of original query */
+ varlevelsup -= context->sublevels_up;
+ /* ignore local vars of subqueries */
+ if (varlevelsup >= 0)
+ {
+ if (context->min_varlevel < 0 ||
+ context->min_varlevel > varlevelsup)
+ {
+ context->min_varlevel = varlevelsup;
+ /*
+ * As soon as we find a local variable, we can abort the
+ * tree traversal, since min_varlevel is then certainly 0.
+ */
+ if (varlevelsup == 0)
+ return true;
+ }
+ }
+ }
+ /*
+ * An Aggref must be treated like a Var of its level. Normally we'd get
+ * the same result from looking at the Vars in the aggregate's argument,
+ * but this fails in the case of a Var-less aggregate call (COUNT(*)).
+ */
+ if (IsA(node, Aggref))
+ {
+ int agglevelsup = ((Aggref *) node)->agglevelsup;
+
+ /* convert levelsup to frame of reference of original query */
+ agglevelsup -= context->sublevels_up;
+ /* ignore local aggs of subqueries */
+ if (agglevelsup >= 0)
+ {
+ if (context->min_varlevel < 0 ||
+ context->min_varlevel > agglevelsup)
+ {
+ context->min_varlevel = agglevelsup;
+ /*
+ * As soon as we find a local aggregate, we can abort the
+ * tree traversal, since min_varlevel is then certainly 0.
+ */
+ if (agglevelsup == 0)
+ return true;
+ }
+ }
+ }
+ if (IsA(node, Query))
+ {
+ /* Recurse into subselects */
+ bool result;
+
+ context->sublevels_up++;
+ result = query_tree_walker((Query *) node,
+ find_minimum_var_level_walker,
+ (void *) context,
+ 0);
+ context->sublevels_up--;
+ return result;
+ }
+ return expression_tree_walker(node,
+ find_minimum_var_level_walker,
+ (void *) context);
+}
+
+
+/*
* pull_var_clause
* Recursively pulls all var nodes from an expression clause.
*