Commit 4a1c5cb9 authored by Tom Lane's avatar Tom Lane

Revise create_nestloop_node's handling of inner indexscan to

work under a wider range of scenarios than it did --- it formerly did not
handle a multi-pass inner scan, nor cases in which the inner scan's
indxqualorig or non-index qual contained outer var references.  I am not
sure that these limitations could be hit in the existing optimizer, but
they need to be fixed for future expansion.
parent 158fd5f1
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.68 1999/08/09 06:20:26 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.69 1999/08/10 02:58:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -426,55 +426,55 @@ create_nestloop_node(NestPath *best_path, ...@@ -426,55 +426,55 @@ create_nestloop_node(NestPath *best_path,
Plan *inner_node, Plan *inner_node,
List *inner_tlist) List *inner_tlist)
{ {
NestLoop *join_node = (NestLoop *) NULL; NestLoop *join_node;
if (IsA(inner_node, IndexScan)) if (IsA(inner_node, IndexScan))
{ {
/* /*
* 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. There will never be more than one index * in the inner relation. If there are join clauses being used
* used in the inner scan path, so we need only consider the first * with the index, we must update their outer-rel var nodes to
* set of qualifications in indxqual. * refer to the outer relation.
*
* 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).
* *
* But there may be more than one clause in this "first set" in the * Note: if the index is lossy, the same clauses may also be getting
* case of multi-column indices. - vadim 03/18/97 * 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...
*
* XXX as of 8/99, removal of redundant joinclauses doesn't work
* all the time, since it will fail to recognize clauses that have
* been commuted in the indexqual. I hope to make this problem go
* away soon by not commuting indexqual clauses --- tgl.
*/ */
IndexScan *innerscan = (IndexScan *) inner_node;
List *indxqualorig = innerscan->indxqualorig;
List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual); /* No work needed if indxqual refers only to its own relation... */
List *inner_qual; if (NumRelids((Node *) indxqualorig) > 1)
bool found = false;
foreach(inner_qual, inner_indxqual)
{ {
if (!qual_clause_p((Node *) lfirst(inner_qual))) /* Remove redundant tests from my clauses, if possible.
{ * Note we must compare against indxqualorig not the "fixed"
found = true; * indxqual (which has index attnos instead of relation attnos).
break;
}
}
/*
* If we have in fact found a join index qualification, remove
* these index clauses from the nestloop's join clauses and reset
* the inner(index) scan's qualification so that the var nodes
* refer to the proper outer join relation attributes.
*
* XXX Removing index clauses doesn't work properly: 1.
* fix_indxqual_references may change varattno-s in
* inner_indxqual; 2. clauses may be commuted I havn't time to fix
* it at the moment. - vadim 04/24/97
*/ */
if (found) if (length(indxqualorig) == 1) /* single indexscan? */
{ clauses = set_difference(clauses, lfirst(indxqualorig));
List *new_inner_qual;
clauses = set_difference(clauses, inner_indxqual); /* XXX */
/* only refs to outer vars get changed in the inner indexqual */ /* only refs to outer vars get changed in the inner indexqual */
new_inner_qual = join_references(inner_indxqual, innerscan->indxqualorig = join_references(indxqualorig,
outer_tlist,
NIL);
innerscan->indxqual = join_references(innerscan->indxqual,
outer_tlist,
NIL);
if (NumRelids((Node *) inner_node->qual) > 1)
inner_node->qual = join_references(inner_node->qual,
outer_tlist, outer_tlist,
NIL); NIL);
((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL);
} }
} }
else if (IsA_Join(inner_node)) else if (IsA_Join(inner_node))
...@@ -512,10 +512,10 @@ create_mergejoin_node(MergePath *best_path, ...@@ -512,10 +512,10 @@ create_mergejoin_node(MergePath *best_path,
*mergeclauses; *mergeclauses;
MergeJoin *join_node; MergeJoin *join_node;
/* /*
* Separate the mergeclauses from the other join qualification clauses * Remove the mergeclauses from the list of join qual clauses,
* and set those clauses to contain references to lower attributes. * leaving the list of quals that must be checked as qpquals.
* Set those clauses to contain INNER/OUTER var references.
*/ */
qpqual = join_references(set_difference(clauses, qpqual = join_references(set_difference(clauses,
best_path->path_mergeclauses), best_path->path_mergeclauses),
...@@ -571,14 +571,6 @@ create_mergejoin_node(MergePath *best_path, ...@@ -571,14 +571,6 @@ create_mergejoin_node(MergePath *best_path,
return join_node; return join_node;
} }
/*
* create_hashjoin_node-- XXX HASH
*
* Returns a new hashjoin node.
*
* XXX hash join ops are totally bogus -- how the hell do we choose
* these?? at runtime? what about a hash index?
*/
static HashJoin * static HashJoin *
create_hashjoin_node(HashPath *best_path, create_hashjoin_node(HashPath *best_path,
List *tlist, List *tlist,
...@@ -595,8 +587,16 @@ create_hashjoin_node(HashPath *best_path, ...@@ -595,8 +587,16 @@ create_hashjoin_node(HashPath *best_path,
Var *innerhashkey; Var *innerhashkey;
/* /*
* Separate the hashclauses from the other join qualification clauses * NOTE: there will always be exactly one hashclause in the list
* and set those clauses to contain references to lower attributes. * best_path->path_hashclauses (cf. hash_inner_and_outer()).
* We represent it as a list anyway for convenience with routines
* that want to work on lists of clauses.
*/
/*
* Remove the hashclauses from the list of join qual clauses,
* leaving the list of quals that must be checked as qpquals.
* Set those clauses to contain INNER/OUTER var references.
*/ */
qpqual = join_references(set_difference(clauses, qpqual = join_references(set_difference(clauses,
best_path->path_hashclauses), best_path->path_hashclauses),
...@@ -611,8 +611,12 @@ create_hashjoin_node(HashPath *best_path, ...@@ -611,8 +611,12 @@ create_hashjoin_node(HashPath *best_path,
outer_tlist, outer_tlist,
inner_tlist)); inner_tlist));
/* Now the righthand op of the sole hashclause is the inner hash key. */
innerhashkey = get_rightop(lfirst(hashclauses)); innerhashkey = get_rightop(lfirst(hashclauses));
/*
* Build the hash node and hash join node.
*/
hash_node = make_hash(inner_tlist, innerhashkey, inner_node); hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
join_node = make_hashjoin(tlist, join_node = make_hashjoin(tlist,
qpqual, qpqual,
...@@ -791,7 +795,7 @@ switch_outer(List *clauses) ...@@ -791,7 +795,7 @@ switch_outer(List *clauses)
Assert(is_opclause((Node *) clause)); Assert(is_opclause((Node *) clause));
op = (Node *) get_rightop(clause); op = (Node *) get_rightop(clause);
Assert(op != (Node *) NULL); Assert(op != (Node *) NULL);
if (IsA(op, ArrayRef)) if (IsA(op, ArrayRef)) /* I think this test is dead code ... tgl */
op = ((ArrayRef *) op)->refexpr; op = ((ArrayRef *) op)->refexpr;
Assert(IsA(op, Var)); Assert(IsA(op, Var));
if (var_is_outer((Var *) op)) if (var_is_outer((Var *) op))
......
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