*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
* 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 *
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))
/*
* 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,
Plan *outer_plan,
Plan *inner_plan)
{
- List *outer_tlist = outer_plan->targetlist;
- List *inner_tlist = inner_plan->targetlist;
List *mergeclauses;
MergeJoin *join_plan;
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.
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;
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.
/*
* 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,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
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
/*
* 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
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);
+ }
}
/*
* Returns the new expression tree. The original clause structure is
* not modified.
*/
-List *
+static List *
join_references(List *clauses,
List *rtable,
List *outer_tlist,
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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 */