Skip to content

Commit 4a1c5cb

Browse files
committed
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.
1 parent 158fd5f commit 4a1c5cb

File tree

1 file changed

+57
-53
lines changed

1 file changed

+57
-53
lines changed

src/backend/optimizer/plan/createplan.c

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.68 1999/08/09 06:20:26 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.69 1999/08/10 02:58:56 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -426,55 +426,55 @@ create_nestloop_node(NestPath *best_path,
426426
Plan *inner_node,
427427
List *inner_tlist)
428428
{
429-
NestLoop *join_node = (NestLoop *) NULL;
429+
NestLoop *join_node;
430430

431431
if (IsA(inner_node, IndexScan))
432432
{
433-
434433
/*
435434
* An index is being used to reduce the number of tuples scanned
436-
* in the inner relation. There will never be more than one index
437-
* used in the inner scan path, so we need only consider the first
438-
* set of qualifications in indxqual.
435+
* in the inner relation. If there are join clauses being used
436+
* with the index, we must update their outer-rel var nodes to
437+
* refer to the outer relation.
439438
*
440-
* But there may be more than one clause in this "first set" in the
441-
* case of multi-column indices. - vadim 03/18/97
442-
*/
443-
444-
List *inner_indxqual = lfirst(((IndexScan *) inner_node)->indxqual);
445-
List *inner_qual;
446-
bool found = false;
447-
448-
foreach(inner_qual, inner_indxqual)
449-
{
450-
if (!qual_clause_p((Node *) lfirst(inner_qual)))
451-
{
452-
found = true;
453-
break;
454-
}
455-
}
456-
457-
/*
458-
* If we have in fact found a join index qualification, remove
459-
* these index clauses from the nestloop's join clauses and reset
460-
* the inner(index) scan's qualification so that the var nodes
461-
* refer to the proper outer join relation attributes.
439+
* We can also remove those join clauses from the list of clauses
440+
* that have to be checked as qpquals at the join node, but only
441+
* if there's just one indexscan in the inner path (otherwise,
442+
* several different sets of clauses are being ORed together).
443+
*
444+
* Note: if the index is lossy, the same clauses may also be getting
445+
* checked as qpquals in the indexscan. We can still remove them
446+
* from the nestloop's qpquals, but we gotta update the outer-rel
447+
* vars in the indexscan's qpquals too...
462448
*
463-
* XXX Removing index clauses doesn't work properly: 1.
464-
* fix_indxqual_references may change varattno-s in
465-
* inner_indxqual; 2. clauses may be commuted I havn't time to fix
466-
* it at the moment. - vadim 04/24/97
449+
* XXX as of 8/99, removal of redundant joinclauses doesn't work
450+
* all the time, since it will fail to recognize clauses that have
451+
* been commuted in the indexqual. I hope to make this problem go
452+
* away soon by not commuting indexqual clauses --- tgl.
467453
*/
468-
if (found)
454+
IndexScan *innerscan = (IndexScan *) inner_node;
455+
List *indxqualorig = innerscan->indxqualorig;
456+
457+
/* No work needed if indxqual refers only to its own relation... */
458+
if (NumRelids((Node *) indxqualorig) > 1)
469459
{
470-
List *new_inner_qual;
460+
/* Remove redundant tests from my clauses, if possible.
461+
* Note we must compare against indxqualorig not the "fixed"
462+
* indxqual (which has index attnos instead of relation attnos).
463+
*/
464+
if (length(indxqualorig) == 1) /* single indexscan? */
465+
clauses = set_difference(clauses, lfirst(indxqualorig));
471466

472-
clauses = set_difference(clauses, inner_indxqual); /* XXX */
473467
/* only refs to outer vars get changed in the inner indexqual */
474-
new_inner_qual = join_references(inner_indxqual,
475-
outer_tlist,
476-
NIL);
477-
((IndexScan *) inner_node)->indxqual = lcons(new_inner_qual, NIL);
468+
innerscan->indxqualorig = join_references(indxqualorig,
469+
outer_tlist,
470+
NIL);
471+
innerscan->indxqual = join_references(innerscan->indxqual,
472+
outer_tlist,
473+
NIL);
474+
if (NumRelids((Node *) inner_node->qual) > 1)
475+
inner_node->qual = join_references(inner_node->qual,
476+
outer_tlist,
477+
NIL);
478478
}
479479
}
480480
else if (IsA_Join(inner_node))
@@ -512,10 +512,10 @@ create_mergejoin_node(MergePath *best_path,
512512
*mergeclauses;
513513
MergeJoin *join_node;
514514

515-
516515
/*
517-
* Separate the mergeclauses from the other join qualification clauses
518-
* and set those clauses to contain references to lower attributes.
516+
* Remove the mergeclauses from the list of join qual clauses,
517+
* leaving the list of quals that must be checked as qpquals.
518+
* Set those clauses to contain INNER/OUTER var references.
519519
*/
520520
qpqual = join_references(set_difference(clauses,
521521
best_path->path_mergeclauses),
@@ -571,14 +571,6 @@ create_mergejoin_node(MergePath *best_path,
571571
return join_node;
572572
}
573573

574-
/*
575-
* create_hashjoin_node-- XXX HASH
576-
*
577-
* Returns a new hashjoin node.
578-
*
579-
* XXX hash join ops are totally bogus -- how the hell do we choose
580-
* these?? at runtime? what about a hash index?
581-
*/
582574
static HashJoin *
583575
create_hashjoin_node(HashPath *best_path,
584576
List *tlist,
@@ -595,8 +587,16 @@ create_hashjoin_node(HashPath *best_path,
595587
Var *innerhashkey;
596588

597589
/*
598-
* Separate the hashclauses from the other join qualification clauses
599-
* and set those clauses to contain references to lower attributes.
590+
* NOTE: there will always be exactly one hashclause in the list
591+
* best_path->path_hashclauses (cf. hash_inner_and_outer()).
592+
* We represent it as a list anyway for convenience with routines
593+
* that want to work on lists of clauses.
594+
*/
595+
596+
/*
597+
* Remove the hashclauses from the list of join qual clauses,
598+
* leaving the list of quals that must be checked as qpquals.
599+
* Set those clauses to contain INNER/OUTER var references.
600600
*/
601601
qpqual = join_references(set_difference(clauses,
602602
best_path->path_hashclauses),
@@ -611,8 +611,12 @@ create_hashjoin_node(HashPath *best_path,
611611
outer_tlist,
612612
inner_tlist));
613613

614+
/* Now the righthand op of the sole hashclause is the inner hash key. */
614615
innerhashkey = get_rightop(lfirst(hashclauses));
615616

617+
/*
618+
* Build the hash node and hash join node.
619+
*/
616620
hash_node = make_hash(inner_tlist, innerhashkey, inner_node);
617621
join_node = make_hashjoin(tlist,
618622
qpqual,
@@ -791,7 +795,7 @@ switch_outer(List *clauses)
791795
Assert(is_opclause((Node *) clause));
792796
op = (Node *) get_rightop(clause);
793797
Assert(op != (Node *) NULL);
794-
if (IsA(op, ArrayRef))
798+
if (IsA(op, ArrayRef)) /* I think this test is dead code ... tgl */
795799
op = ((ArrayRef *) op)->refexpr;
796800
Assert(IsA(op, Var));
797801
if (var_is_outer((Var *) op))

0 commit comments

Comments
 (0)