Clean up some mistakes in handling of uplevel Vars in planner.
authorTom Lane
Thu, 26 Aug 1999 05:09:06 +0000 (05:09 +0000)
committerTom Lane
Thu, 26 Aug 1999 05:09:06 +0000 (05:09 +0000)
Most parts of the planner should ignore, or indeed never even see, uplevel
Vars because they will be or have been replaced by Params.  There were a
couple of places that got it wrong though, probably my fault from recent
changes...

src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/tlist.c
src/backend/optimizer/util/var.c
src/include/optimizer/var.h

index a89c40b943598bde2181c7637a0f98782cb51806..20a01902efc143b28afd5f47c6435177a24b1731 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.38 1999/08/22 20:14:47 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.39 1999/08/26 05:07:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
 void
 make_var_only_tlist(Query *root, List *tlist)
 {
-   List       *tlist_vars = pull_var_clause((Node *) tlist);
+   List       *tlist_vars = pull_var_clause((Node *) tlist, false);
 
    add_vars_to_targetlist(root, tlist_vars);
    freeList(tlist_vars);
index 3c7a665563c85212c2a27bcb0cf4156d3142ae49..b5c8d7d3de8161917c786468166328bdf33095b0 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.65 1999/08/22 23:56:45 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.66 1999/08/26 05:07:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -296,26 +296,27 @@ union_planner(Query *parse)
 
    /*
     * If we have a HAVING clause, do the necessary things with it.
+    * This code should parallel query_planner()'s initial processing
+    * of the WHERE clause.
     */
    if (parse->havingQual)
    {
        List       *ql;
 
-       /* convert the havingQual to conjunctive normal form (cnf) */
-       parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
+       /* Replace uplevel Vars with Params */
+       if (PlannerQueryLevel > 1)
+           parse->havingQual = SS_replace_correlation_vars(parse->havingQual);
 
        if (parse->hasSubLinks)
        {
-           /*
-            * There may be a subselect in the havingQual, so we have to
-            * process it using the same function as for a subselect in
-            * 'where'
-            */
+           /* Expand SubLinks to SubPlans */
            parse->havingQual = SS_process_sublinks(parse->havingQual);
 
            /*
             * Check for ungrouped variables passed to subplans. (Probably
-            * this should be done for the targetlist as well???)
+            * this should be done for the targetlist as well???  But we
+            * should NOT do it for the WHERE qual, since WHERE is
+            * evaluated pre-GROUP.)
             */
            if (check_subplans_for_ungrouped_vars(parse->havingQual,
                                                  parse->groupClause,
@@ -323,6 +324,9 @@ union_planner(Query *parse)
                elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
        }
 
+       /* convert the havingQual to conjunctive normal form (cnf) */
+       parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
+
        /*
         * Require an aggregate function to appear in each clause of the
         * havingQual (else it could have been done as a WHERE constraint).
@@ -428,10 +432,11 @@ make_subplanTargetList(Query *parse,
 
    /*
     * Otherwise, start with a "flattened" tlist (having just the vars
-    * mentioned in the targetlist and HAVING qual).
+    * mentioned in the targetlist and HAVING qual --- but not upper-
+    * level Vars; they will be replaced by Params later on).
     */
    sub_tlist = flatten_tlist(tlist);
-   extravars = pull_var_clause(parse->havingQual);
+   extravars = pull_var_clause(parse->havingQual, false);
    sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
    freeList(extravars);
 
index 2d960b5cf03ac21cb9b284b062101f262ae0120d..1ab09217c5928e32a8c56cd1a582d3399df58169 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.49 1999/08/25 23:21:41 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.50 1999/08/26 05:09:05 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -339,7 +339,7 @@ make_ands_implicit(Expr *clause)
 /*
  * pull_constant_clauses
  *   Scans through a list of qualifications and find those that
- *   contain no variables.
+ *   contain no variables (of the current query level).
  *
  * Returns a list of the constant clauses in constantQual and the remaining
  * quals as the return value.
@@ -480,11 +480,14 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
  *     Var nodes are considered distinct if they have different varno
  *     or varattno values.  If there are several occurrences of the same
  *     varno/varattno, you get a randomly chosen one...
+ *
+ * Note that upper-level vars are ignored, since they normally will
+ * become Params with respect to this query level.
  */
 void
 clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
 {
-   List       *clvars = pull_var_clause(clause);
+   List       *clvars = pull_var_clause(clause, false);
    List       *varno_list = NIL;
    List       *var_list = NIL;
    List       *i;
@@ -494,7 +497,6 @@ clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
        Var        *var = (Var *) lfirst(i);
        List       *vi;
 
-       Assert(var->varlevelsup == 0);
        if (!intMember(var->varno, varno_list))
            varno_list = lconsi(var->varno, varno_list);
        foreach(vi, var_list)
index dfe2963581feec6d9b934956226bfd64ea3272b1..43007f33fff8685b490928d7f060efd1730e1bec 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.40 1999/08/22 20:14:54 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.41 1999/08/26 05:09:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -147,6 +147,10 @@ new_unsorted_tlist(List *targetlist)
  * flatten_tlist
  *   Create a target list that only contains unique variables.
  *
+ * Note that Vars with varlevelsup > 0 are not included in the output
+ * tlist.  We expect that those will eventually be replaced with Params,
+ * but that probably has not happened at the time this routine is called.
+ *
  * 'tlist' is the current target list
  *
  * Returns the "flattened" new target list.
@@ -157,7 +161,7 @@ new_unsorted_tlist(List *targetlist)
 List *
 flatten_tlist(List *tlist)
 {
-   List       *vlist = pull_var_clause((Node *) tlist);
+   List       *vlist = pull_var_clause((Node *) tlist, false);
    List       *new_tlist;
 
    new_tlist = add_to_flat_tlist(NIL, vlist);
index a544041122b2f4aff43b692330665c4ce9a33b76..af58b2556d6011eac6dc463ed5075dab18e56ee8 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.23 1999/08/22 20:14:54 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.24 1999/08/26 05:09:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "optimizer/var.h"
 
 
+typedef struct {
+   List       *varlist;
+   bool        includeUpperVars;
+} pull_var_clause_context;
+
 static bool pull_varnos_walker(Node *node, List **listptr);
 static bool contain_var_clause_walker(Node *node, void *context);
-static bool pull_var_clause_walker(Node *node, List **listptr);
+static bool pull_var_clause_walker(Node *node,
+                                  pull_var_clause_context *context);
 
 
 /*
  *     pull_varnos
  *
  *     Create a list of all the distinct varnos present in a parsetree
- *     (tlist or qual).
+ *     (tlist or qual).  Note that only varnos attached to level-zero
+ *     Vars are considered --- upper Vars refer to some other rtable!
  */
 List *
 pull_varnos(Node *node)
@@ -47,7 +54,7 @@ pull_varnos_walker(Node *node, List **listptr)
    if (IsA(node, Var))
    {
        Var    *var = (Var *) node;
-       if (!intMember(var->varno, *listptr))
+       if (var->varlevelsup == 0 && !intMember(var->varno, *listptr))
            *listptr = lconsi(var->varno, *listptr);
        return false;
    }
@@ -56,7 +63,8 @@ pull_varnos_walker(Node *node, List **listptr)
 
 /*
  * contain_var_clause
- *   Recursively scan a clause to discover whether it contains any Var nodes.
+ *   Recursively scan a clause to discover whether it contains any Var nodes
+ *   (of the current query level).
  *
  *   Returns true if any varnode found.
  */
@@ -72,7 +80,11 @@ contain_var_clause_walker(Node *node, void *context)
    if (node == NULL)
        return false;
    if (IsA(node, Var))
-       return true;            /* abort the tree traversal and return true */
+   {
+       if (((Var *) node)->varlevelsup == 0)
+           return true;        /* abort the tree traversal and return true */
+       return false;
+   }
    return expression_tree_walker(node, contain_var_clause_walker, context);
 }
 
@@ -80,28 +92,36 @@ contain_var_clause_walker(Node *node, void *context)
  * pull_var_clause
  *   Recursively pulls all var nodes from an expression clause.
  *
+ *   Upper-level vars (with varlevelsup > 0) are included only
+ *   if includeUpperVars is true.  Most callers probably want
+ *   to ignore upper-level vars.
+ *
  *   Returns list of varnodes found.  Note the varnodes themselves are not
  *   copied, only referenced.
  */
 List *
-pull_var_clause(Node *clause)
+pull_var_clause(Node *clause, bool includeUpperVars)
 {
-   List       *result = NIL;
+   pull_var_clause_context     context;
 
-   pull_var_clause_walker(clause, &result);
-   return result;
+   context.varlist = NIL;
+   context.includeUpperVars = includeUpperVars;
+
+   pull_var_clause_walker(clause, &context);
+   return context.varlist;
 }
 
 static bool
-pull_var_clause_walker(Node *node, List **listptr)
+pull_var_clause_walker(Node *node, pull_var_clause_context *context)
 {
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
-       *listptr = lappend(*listptr, node);
+       if (((Var *) node)->varlevelsup == 0 || context->includeUpperVars)
+           context->varlist = lappend(context->varlist, node);
        return false;
    }
    return expression_tree_walker(node, pull_var_clause_walker,
-                                 (void *) listptr);
+                                 (void *) context);
 }
index 440b62f49adc75d5b6bf5c693c9bfb48f8958288..e2d5390876bff9036a66a4c2b3955fad4db3f53d 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: var.h,v 1.9 1999/08/22 20:14:57 tgl Exp $
+ * $Id: var.h,v 1.10 1999/08/26 05:06:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,6 @@
 
 extern List *pull_varnos(Node *me);
 extern bool contain_var_clause(Node *clause);
-extern List *pull_var_clause(Node *clause);
+extern List *pull_var_clause(Node *clause, bool includeUpperVars);
 
 #endif  /* VAR_H */