Commit cde9f852 authored by Tom Lane's avatar 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.
parent 606d4f7b
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -651,20 +651,6 @@ create_functionscan_plan(Path *best_path, List *tlist, List *scan_clauses)
* *
* JOIN METHODS * 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 * static NestLoop *
...@@ -676,8 +662,6 @@ create_nestloop_plan(Query *root, ...@@ -676,8 +662,6 @@ create_nestloop_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *outer_tlist = outer_plan->targetlist;
List *inner_tlist = inner_plan->targetlist;
NestLoop *join_plan; NestLoop *join_plan;
if (IsA(inner_plan, IndexScan)) if (IsA(inner_plan, IndexScan))
...@@ -685,86 +669,27 @@ create_nestloop_plan(Query *root, ...@@ -685,86 +669,27 @@ create_nestloop_plan(Query *root,
/* /*
* An index is being used to reduce the number of tuples scanned * An index is being used to reduce the number of tuples scanned
* in the inner relation. If there are join clauses being used * in the inner relation. If there are join clauses being used
* with the index, we must update their outer-rel var nodes to * with the index, we may remove those join clauses from the list of
* refer to the outer side of the join. * clauses that have to be checked as qpquals at the join node ---
* * but only if there's just one indexscan in the inner path
* We can also remove those join clauses from the list of clauses * (otherwise, several different sets of clauses are being ORed
* that have to be checked as qpquals at the join node, but only * together).
* 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 * Note we must compare against indxqualorig not the "fixed" indxqual
* checked as qpquals in the indexscan. We can still remove them * (which has index attnos instead of relation attnos, and may have
* from the nestloop's qpquals, but we gotta update the outer-rel * been commuted as well).
* 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.
*/ */
IndexScan *innerscan = (IndexScan *) inner_plan; IndexScan *innerscan = (IndexScan *) inner_plan;
List *indxqualorig = innerscan->indxqualorig; List *indxqualorig = innerscan->indxqualorig;
/* No work needed if indxqual refers only to its own relation... */ if (length(indxqualorig) == 1) /* single indexscan? */
if (NumRelids((Node *) indxqualorig) > 1)
{ {
Index innerrel = innerscan->scan.scanrelid; /* No work needed if indxqual refers only to its own relation... */
if (NumRelids((Node *) indxqualorig) > 1)
/*
* 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? */
joinclauses = set_difference(joinclauses, joinclauses = set_difference(joinclauses,
lfirst(indxqualorig)); 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, join_plan = make_nestloop(tlist,
joinclauses, joinclauses,
...@@ -787,8 +712,6 @@ create_mergejoin_plan(Query *root, ...@@ -787,8 +712,6 @@ create_mergejoin_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *outer_tlist = outer_plan->targetlist;
List *inner_tlist = inner_plan->targetlist;
List *mergeclauses; List *mergeclauses;
MergeJoin *join_plan; MergeJoin *join_plan;
...@@ -806,25 +729,6 @@ create_mergejoin_plan(Query *root, ...@@ -806,25 +729,6 @@ create_mergejoin_plan(Query *root,
mergeclauses = get_switched_clauses(best_path->path_mergeclauses, mergeclauses = get_switched_clauses(best_path->path_mergeclauses,
best_path->jpath.outerjoinpath->parent->relids); 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 * Create explicit sort nodes for the outer and inner join paths if
* necessary. The sort cost was already accounted for in the path. * necessary. The sort cost was already accounted for in the path.
...@@ -868,8 +772,6 @@ create_hashjoin_plan(Query *root, ...@@ -868,8 +772,6 @@ create_hashjoin_plan(Query *root,
Plan *outer_plan, Plan *outer_plan,
Plan *inner_plan) Plan *inner_plan)
{ {
List *outer_tlist = outer_plan->targetlist;
List *inner_tlist = inner_plan->targetlist;
List *hashclauses; List *hashclauses;
HashJoin *join_plan; HashJoin *join_plan;
Hash *hash_plan; Hash *hash_plan;
...@@ -890,25 +792,6 @@ create_hashjoin_plan(Query *root, ...@@ -890,25 +792,6 @@ create_hashjoin_plan(Query *root,
hashclauses = get_switched_clauses(best_path->path_hashclauses, hashclauses = get_switched_clauses(best_path->path_hashclauses,
best_path->jpath.outerjoinpath->parent->relids); 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) * Extract the inner hash keys (right-hand operands of the hashclauses)
* to put in the Hash node. * to put in the Hash node.
...@@ -922,7 +805,9 @@ create_hashjoin_plan(Query *root, ...@@ -922,7 +805,9 @@ create_hashjoin_plan(Query *root,
/* /*
* Build the hash node and hash join node. * 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, join_plan = make_hashjoin(tlist,
joinclauses, joinclauses,
otherclauses, otherclauses,
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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); ...@@ -44,6 +44,11 @@ static void fix_expr_references(Plan *plan, Node *node);
static bool fix_expr_references_walker(Node *node, void *context); static bool fix_expr_references_walker(Node *node, void *context);
static void set_join_references(Join *join, List *rtable); static void set_join_references(Join *join, List *rtable);
static void set_uppernode_references(Plan *plan, Index subvarno); 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, static Node *join_references_mutator(Node *node,
join_references_context *context); join_references_context *context);
static Node *replace_vars_with_subplan_refs(Node *node, static Node *replace_vars_with_subplan_refs(Node *node,
...@@ -157,12 +162,26 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -157,12 +162,26 @@ set_plan_references(Plan *plan, List *rtable)
fix_expr_references(plan, fix_expr_references(plan,
(Node *) ((HashJoin *) plan)->hashclauses); (Node *) ((HashJoin *) plan)->hashclauses);
break; 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_Material:
case T_Sort: case T_Sort:
case T_Unique: case T_Unique:
case T_SetOp: case T_SetOp:
case T_Limit: case T_Limit:
case T_Hash:
/* /*
* These plan types don't actually bother to evaluate their * These plan types don't actually bother to evaluate their
...@@ -270,20 +289,14 @@ fix_expr_references_walker(Node *node, void *context) ...@@ -270,20 +289,14 @@ fix_expr_references_walker(Node *node, void *context)
/* /*
* set_join_references * set_join_references
* Modifies the target list of a join node to reference its subplans, * Modifies the target list and quals of a join node to reference its
* by setting the varnos to OUTER or INNER and setting attno values to the * subplans, by setting the varnos to OUTER or INNER and setting attno
* result domain number of either the corresponding outer or inner join * values to the result domain number of either the corresponding outer
* tuple item. * 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() * In the case of a nestloop with inner indexscan, we will also need to
* comparisons between qual and tlist var nodes during the time between * apply the same transformation to any outer vars appearing in the
* creation of a plan node by createplan.c and its fixing by this module. * quals of the child indexscan.
* Fortunately, there doesn't seem to be any need to do that.
* *
* 'join' is a join plan node * 'join' is a join plan node
* 'rtable' is the associated range table * 'rtable' is the associated range table
...@@ -291,16 +304,103 @@ fix_expr_references_walker(Node *node, void *context) ...@@ -291,16 +304,103 @@ fix_expr_references_walker(Node *node, void *context)
static void static void
set_join_references(Join *join, List *rtable) set_join_references(Join *join, List *rtable)
{ {
Plan *outer = join->plan.lefttree; Plan *outer_plan = join->plan.lefttree;
Plan *inner = join->plan.righttree; Plan *inner_plan = join->plan.righttree;
List *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist); List *outer_tlist = outer_plan->targetlist;
List *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist); List *inner_tlist = inner_plan->targetlist;
/* All join plans have tlist, qual, and joinqual */
join->plan.targetlist = join_references(join->plan.targetlist, join->plan.targetlist = join_references(join->plan.targetlist,
rtable, rtable,
outer_tlist, outer_tlist,
inner_tlist, inner_tlist,
(Index) 0); (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) ...@@ -400,7 +500,7 @@ set_uppernode_references(Plan *plan, Index subvarno)
* Returns the new expression tree. The original clause structure is * Returns the new expression tree. The original clause structure is
* not modified. * not modified.
*/ */
List * static List *
join_references(List *clauses, join_references(List *clauses,
List *rtable, List *rtable,
List *outer_tlist, List *outer_tlist,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -63,9 +63,6 @@ extern bool exprs_known_equal(Query *root, Node *item1, Node *item2);
* prototypes for plan/setrefs.c * prototypes for plan/setrefs.c
*/ */
extern void set_plan_references(Plan *plan, List *rtable); 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); extern void fix_opfuncids(Node *node);
#endif /* PLANMAIN_H */ #endif /* PLANMAIN_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment