Now that switch_outer processing no longer relies on being run after
authorTom Lane
Wed, 15 Jan 2003 23:10:32 +0000 (23:10 +0000)
committerTom Lane
Wed, 15 Jan 2003 23:10:32 +0000 (23:10 +0000)
join_references(), it's practical to consolidate all join_references()
processing into the set_plan_references traversal in setrefs.c.  This
seems considerably cleaner than the old way where we did it for join
quals in createplan.c and for targetlists in setrefs.c.

src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/setrefs.c
src/include/optimizer/planmain.h

index 03ec35384797f41dfb0a5618f3dbfaf146b6ee93..f6e51d0d52f062c4f935bd558a08fc05e6d52080 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.130 2003/01/15 19:35:40 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.131 2003/01/15 23:10:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -651,20 +651,6 @@ create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
  *
  * JOIN METHODS
  *
- * A general note about join_references() processing in these routines:
- * once we have changed a Var node to refer to a subplan output rather than
- * the original relation, it is no longer equal() to an unmodified Var node
- * for the same var.  So, we cannot easily compare reference-adjusted qual
- * clauses to clauses that have not been adjusted. Fortunately, that
- * doesn't seem to be necessary; all the decisions are made before we do
- * the reference adjustments.
- *
- * A cleaner solution would be to not call join_references() here at all,
- * but leave it for setrefs.c to do at the end of plan tree construction.
- * But some care would be needed to get setrefs.c to do the right thing with
- * nestloop inner indexscan quals.  So, we do subplan reference adjustment
- * here for quals of join nodes (and *only* for quals of join nodes).
- *
  *****************************************************************************/
 
 static NestLoop *
@@ -676,8 +662,6 @@ create_nestloop_plan(Query *root,
                     Plan *outer_plan,
                     Plan *inner_plan)
 {
-   List       *outer_tlist = outer_plan->targetlist;
-   List       *inner_tlist = inner_plan->targetlist;
    NestLoop   *join_plan;
 
    if (IsA(inner_plan, IndexScan))
@@ -685,86 +669,27 @@ create_nestloop_plan(Query *root,
        /*
         * An index is being used to reduce the number of tuples scanned
         * in the inner relation.  If there are join clauses being used
-        * with the index, we must update their outer-rel var nodes to
-        * refer to the outer side of the join.
-        *
-        * We can also remove those join clauses from the list of clauses
-        * that have to be checked as qpquals at the join node, but only
-        * if there's just one indexscan in the inner path (otherwise,
-        * several different sets of clauses are being ORed together).
+        * with the index, we may remove those join clauses from the list of
+        * clauses that have to be checked as qpquals at the join node ---
+        * but only if there's just one indexscan in the inner path
+        * (otherwise, several different sets of clauses are being ORed
+        * together).
         *
-        * Note: if the index is lossy, the same clauses may also be getting
-        * checked as qpquals in the indexscan.  We can still remove them
-        * from the nestloop's qpquals, but we gotta update the outer-rel
-        * vars in the indexscan's qpquals too.
-        *
-        * Note: we can safely do set_difference() against my clauses and
-        * join_references() because the innerscan is a primitive plan,
-        * and therefore has not itself done join_references renumbering
-        * of the vars in its quals.
+        * Note we must compare against indxqualorig not the "fixed" indxqual
+        * (which has index attnos instead of relation attnos, and may have
+        * been commuted as well).
         */
        IndexScan  *innerscan = (IndexScan *) inner_plan;
        List       *indxqualorig = innerscan->indxqualorig;
 
-       /* No work needed if indxqual refers only to its own relation... */
-       if (NumRelids((Node *) indxqualorig) > 1)
+       if (length(indxqualorig) == 1) /* single indexscan? */
        {
-           Index       innerrel = innerscan->scan.scanrelid;
-
-           /*
-            * Remove redundant tests from my clauses, if possible. Note
-            * we must compare against indxqualorig not the "fixed"
-            * indxqual (which has index attnos instead of relation
-            * attnos, and may have been commuted as well).
-            */
-           if (length(indxqualorig) == 1)      /* single indexscan? */
+           /* No work needed if indxqual refers only to its own relation... */
+           if (NumRelids((Node *) indxqualorig) > 1)
                joinclauses = set_difference(joinclauses,
                                             lfirst(indxqualorig));
-
-           /* only refs to outer vars get changed in the inner indexqual */
-           innerscan->indxqualorig = join_references(indxqualorig,
-                                                     root->rtable,
-                                                     outer_tlist,
-                                                     NIL,
-                                                     innerrel);
-           innerscan->indxqual = join_references(innerscan->indxqual,
-                                                 root->rtable,
-                                                 outer_tlist,
-                                                 NIL,
-                                                 innerrel);
-           /* fix the inner qpqual too, if it has join clauses */
-           if (NumRelids((Node *) inner_plan->qual) > 1)
-               inner_plan->qual = join_references(inner_plan->qual,
-                                                  root->rtable,
-                                                  outer_tlist,
-                                                  NIL,
-                                                  innerrel);
        }
    }
-   else if (IsA(inner_plan, TidScan))
-   {
-       TidScan    *innerscan = (TidScan *) inner_plan;
-
-       innerscan->tideval = join_references(innerscan->tideval,
-                                            root->rtable,
-                                            outer_tlist,
-                                            inner_tlist,
-                                            innerscan->scan.scanrelid);
-   }
-
-   /*
-    * Set quals to contain INNER/OUTER var references.
-    */
-   joinclauses = join_references(joinclauses,
-                                 root->rtable,
-                                 outer_tlist,
-                                 inner_tlist,
-                                 (Index) 0);
-   otherclauses = join_references(otherclauses,
-                                  root->rtable,
-                                  outer_tlist,
-                                  inner_tlist,
-                                  (Index) 0);
 
    join_plan = make_nestloop(tlist,
                              joinclauses,
@@ -787,8 +712,6 @@ create_mergejoin_plan(Query *root,
                      Plan *outer_plan,
                      Plan *inner_plan)
 {
-   List       *outer_tlist = outer_plan->targetlist;
-   List       *inner_tlist = inner_plan->targetlist;
    List       *mergeclauses;
    MergeJoin  *join_plan;
 
@@ -806,25 +729,6 @@ create_mergejoin_plan(Query *root,
    mergeclauses = get_switched_clauses(best_path->path_mergeclauses,
                                        best_path->jpath.outerjoinpath->parent->relids);
 
-   /*
-    * Fix all the join clauses to contain INNER/OUTER var references.
-    */
-   joinclauses = join_references(joinclauses,
-                                 root->rtable,
-                                 outer_tlist,
-                                 inner_tlist,
-                                 (Index) 0);
-   otherclauses = join_references(otherclauses,
-                                  root->rtable,
-                                  outer_tlist,
-                                  inner_tlist,
-                                  (Index) 0);
-   mergeclauses = join_references(mergeclauses,
-                                  root->rtable,
-                                  outer_tlist,
-                                  inner_tlist,
-                                  (Index) 0);
-
    /*
     * Create explicit sort nodes for the outer and inner join paths if
     * necessary.  The sort cost was already accounted for in the path.
@@ -868,8 +772,6 @@ create_hashjoin_plan(Query *root,
                     Plan *outer_plan,
                     Plan *inner_plan)
 {
-   List       *outer_tlist = outer_plan->targetlist;
-   List       *inner_tlist = inner_plan->targetlist;
    List       *hashclauses;
    HashJoin   *join_plan;
    Hash       *hash_plan;
@@ -890,25 +792,6 @@ create_hashjoin_plan(Query *root,
    hashclauses = get_switched_clauses(best_path->path_hashclauses,
                                       best_path->jpath.outerjoinpath->parent->relids);
 
-   /*
-    * Fix all the join clauses to contain INNER/OUTER var references.
-    */
-   joinclauses = join_references(joinclauses,
-                                 root->rtable,
-                                 outer_tlist,
-                                 inner_tlist,
-                                 (Index) 0);
-   otherclauses = join_references(otherclauses,
-                                  root->rtable,
-                                  outer_tlist,
-                                  inner_tlist,
-                                  (Index) 0);
-   hashclauses = join_references(hashclauses,
-                                 root->rtable,
-                                 outer_tlist,
-                                 inner_tlist,
-                                 (Index) 0);
-
    /*
     * Extract the inner hash keys (right-hand operands of the hashclauses)
     * to put in the Hash node.
@@ -922,7 +805,9 @@ create_hashjoin_plan(Query *root,
    /*
     * Build the hash node and hash join node.
     */
-   hash_plan = make_hash(inner_tlist, innerhashkeys, inner_plan);
+   hash_plan = make_hash(inner_plan->targetlist,
+                         innerhashkeys,
+                         inner_plan);
    join_plan = make_hashjoin(tlist,
                              joinclauses,
                              otherclauses,
index 1c9f8a27cff9044b7eac8887ecd81f967f5626e9..513480c4e20691d0964671c900f360e101bbd981 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.89 2003/01/15 19:35:43 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.90 2003/01/15 23:10:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,6 +44,11 @@ static void fix_expr_references(Plan *plan, Node *node);
 static bool fix_expr_references_walker(Node *node, void *context);
 static void set_join_references(Join *join, List *rtable);
 static void set_uppernode_references(Plan *plan, Index subvarno);
+static List *join_references(List *clauses,
+                            List *rtable,
+                            List *outer_tlist,
+                            List *inner_tlist,
+                            Index acceptable_rel);
 static Node *join_references_mutator(Node *node,
                        join_references_context *context);
 static Node *replace_vars_with_subplan_refs(Node *node,
@@ -157,12 +162,26 @@ set_plan_references(Plan *plan, List *rtable)
            fix_expr_references(plan,
                              (Node *) ((HashJoin *) plan)->hashclauses);
            break;
+       case T_Hash:
+           /*
+            * Hash does not evaluate its targetlist or quals, so don't
+            * touch those (see comments below).  But we do need to fix its
+            * hashkeys.  The hashkeys are a little bizarre because they
+            * need to match the hashclauses of the parent HashJoin node,
+            * so we use join_references to fix them.
+            */
+           ((Hash *) plan)->hashkeys =
+               join_references(((Hash *) plan)->hashkeys,
+                               rtable,
+                               NIL,
+                               plan->lefttree->targetlist,
+                               (Index) 0);
+           break;
        case T_Material:
        case T_Sort:
        case T_Unique:
        case T_SetOp:
        case T_Limit:
-       case T_Hash:
 
            /*
             * These plan types don't actually bother to evaluate their
@@ -270,20 +289,14 @@ fix_expr_references_walker(Node *node, void *context)
 
 /*
  * set_join_references
- *   Modifies the target list of a join node to reference its subplans,
- *   by setting the varnos to OUTER or INNER and setting attno values to the
- *   result domain number of either the corresponding outer or inner join
- *   tuple item.
- *
- * Note: this same transformation has already been applied to the quals
- * of the join by createplan.c.  It's a little odd to do it here for the
- * targetlist and there for the quals, but it's easier that way.  (Look
- * at the handling of nestloop inner indexscans to see why.)
+ *   Modifies the target list and quals of a join node to reference its
+ *   subplans, by setting the varnos to OUTER or INNER and setting attno
+ *   values to the result domain number of either the corresponding outer
+ *   or inner join tuple item.
  *
- * Because the quals are reference-adjusted sooner, we cannot do equal()
- * comparisons between qual and tlist var nodes during the time between
- * creation of a plan node by createplan.c and its fixing by this module.
- * Fortunately, there doesn't seem to be any need to do that.
+ * In the case of a nestloop with inner indexscan, we will also need to
+ * apply the same transformation to any outer vars appearing in the
+ * quals of the child indexscan.
  *
  * 'join' is a join plan node
  * 'rtable' is the associated range table
@@ -291,16 +304,103 @@ fix_expr_references_walker(Node *node, void *context)
 static void
 set_join_references(Join *join, List *rtable)
 {
-   Plan       *outer = join->plan.lefttree;
-   Plan       *inner = join->plan.righttree;
-   List       *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
-   List       *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
+   Plan       *outer_plan = join->plan.lefttree;
+   Plan       *inner_plan = join->plan.righttree;
+   List       *outer_tlist = outer_plan->targetlist;
+   List       *inner_tlist = inner_plan->targetlist;
 
+   /* All join plans have tlist, qual, and joinqual */
    join->plan.targetlist = join_references(join->plan.targetlist,
                                            rtable,
                                            outer_tlist,
                                            inner_tlist,
                                            (Index) 0);
+   join->plan.qual = join_references(join->plan.qual,
+                                     rtable,
+                                     outer_tlist,
+                                     inner_tlist,
+                                     (Index) 0);
+   join->joinqual = join_references(join->joinqual,
+                                    rtable,
+                                    outer_tlist,
+                                    inner_tlist,
+                                    (Index) 0);
+
+   /* Now do join-type-specific stuff */
+   if (IsA(join, NestLoop))
+   {
+       if (IsA(inner_plan, IndexScan))
+       {
+           /*
+            * An index is being used to reduce the number of tuples scanned
+            * in the inner relation.  If there are join clauses being used
+            * with the index, we must update their outer-rel var nodes to
+            * refer to the outer side of the join.
+            */
+           IndexScan  *innerscan = (IndexScan *) inner_plan;
+           List       *indxqualorig = innerscan->indxqualorig;
+
+           /* No work needed if indxqual refers only to its own rel... */
+           if (NumRelids((Node *) indxqualorig) > 1)
+           {
+               Index       innerrel = innerscan->scan.scanrelid;
+
+               /* only refs to outer vars get changed in the inner qual */
+               innerscan->indxqualorig = join_references(indxqualorig,
+                                                         rtable,
+                                                         outer_tlist,
+                                                         NIL,
+                                                         innerrel);
+               innerscan->indxqual = join_references(innerscan->indxqual,
+                                                     rtable,
+                                                     outer_tlist,
+                                                     NIL,
+                                                     innerrel);
+               /*
+                * We must fix the inner qpqual too, if it has join clauses
+                * (this could happen if the index is lossy: some indxquals
+                * may get rechecked as qpquals).
+                */
+               if (NumRelids((Node *) inner_plan->qual) > 1)
+                   inner_plan->qual = join_references(inner_plan->qual,
+                                                      rtable,
+                                                      outer_tlist,
+                                                      NIL,
+                                                      innerrel);
+           }
+       }
+       else if (IsA(inner_plan, TidScan))
+       {
+           TidScan    *innerscan = (TidScan *) inner_plan;
+           Index       innerrel = innerscan->scan.scanrelid;
+
+           innerscan->tideval = join_references(innerscan->tideval,
+                                                rtable,
+                                                outer_tlist,
+                                                NIL,
+                                                innerrel);
+       }
+   }
+   else if (IsA(join, MergeJoin))
+   {
+       MergeJoin  *mj = (MergeJoin *) join;
+
+       mj->mergeclauses = join_references(mj->mergeclauses,
+                                          rtable,
+                                          outer_tlist,
+                                          inner_tlist,
+                                          (Index) 0);
+   }
+   else if (IsA(join, HashJoin))
+   {
+       HashJoin   *hj = (HashJoin *) join;
+
+       hj->hashclauses = join_references(hj->hashclauses,
+                                         rtable,
+                                         outer_tlist,
+                                         inner_tlist,
+                                         (Index) 0);
+   }
 }
 
 /*
@@ -400,7 +500,7 @@ set_uppernode_references(Plan *plan, Index subvarno)
  * Returns the new expression tree.  The original clause structure is
  * not modified.
  */
-List *
+static List *
 join_references(List *clauses,
                List *rtable,
                List *outer_tlist,
index f2604527001e039ffb1048e293b2fde2d3bfa876..66925931609054be37326186074989a126202aaf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: planmain.h,v 1.65 2003/01/15 19:35:47 tgl Exp $
+ * $Id: planmain.h,v 1.66 2003/01/15 23:10:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,9 +63,6 @@ extern bool exprs_known_equal(Query *root, Node *item1, Node *item2);
  * prototypes for plan/setrefs.c
  */
 extern void set_plan_references(Plan *plan, List *rtable);
-extern List *join_references(List *clauses, List *rtable,
-               List *outer_tlist, List *inner_tlist,
-               Index acceptable_rel);
 extern void fix_opfuncids(Node *node);
 
 #endif   /* PLANMAIN_H */