提交 cde9f852 编写于 作者: T Tom Lane

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.
上级 606d4f7b
......@@ -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,
......
......@@ -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,
......
......@@ -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 */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册