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.
This commit is contained in:
Tom Lane 2003-01-15 23:10:32 +00:00
parent 606d4f7b38
commit cde9f852e0
3 changed files with 136 additions and 154 deletions

View 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.
* 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,

View 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.
* 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,

View 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 */