From cde9f852e0d91774a3ed633f6bce935343920a08 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 15 Jan 2003 23:10:32 +0000 Subject: [PATCH] Now that switch_outer processing no longer relies on being run after 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 | 145 +++--------------------- src/backend/optimizer/plan/setrefs.c | 140 +++++++++++++++++++---- src/include/optimizer/planmain.h | 5 +- 3 files changed, 136 insertions(+), 154 deletions(-) diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 03ec353847..f6e51d0d52 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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. + * 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). * - * 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). - * - * 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, diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 1c9f8a27cf..513480c4e2 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -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. + * 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. * - * 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.) - * - * 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, diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index f260452700..6692593160 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -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 */