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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy