Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b62fdc1

Browse files
committed
Correct bug in best_innerjoin(): it should check all the
rels that the inner path needs to join to, but it was only checking for the first one. Failure could only have been observed with an OR-clause that mentions 3 or more tables, and then only if the bogus path was actually selected as cheapest ...
1 parent 2f30d5a commit b62fdc1

File tree

3 files changed

+64
-53
lines changed

3 files changed

+64
-53
lines changed

src/backend/optimizer/path/joinpath.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.41 1999/07/16 04:59:15 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.42 1999/07/27 06:23:12 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -147,13 +147,14 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels)
147147
/*
148148
* best_innerjoin
149149
* Find the cheapest index path that has already been identified by
150-
* (indexable_joinclauses) as being a possible inner path for the given
151-
* outer relation in a nestloop join.
150+
* indexable_joinclauses() as being a possible inner path for the given
151+
* outer relation(s) in a nestloop join.
152152
*
153-
* 'join_paths' is a list of join nodes
154-
* 'outer_relid' is the relid of the outer join relation
153+
* 'join_paths' is a list of potential inner indexscan join paths
154+
* 'outer_relids' is the relid list of the outer join relation
155155
*
156-
* Returns the pathnode of the selected path.
156+
* Returns the pathnode of the best path, or NULL if there's no
157+
* usable path.
157158
*/
158159
static Path *
159160
best_innerjoin(List *join_paths, Relids outer_relids)
@@ -165,7 +166,11 @@ best_innerjoin(List *join_paths, Relids outer_relids)
165166
{
166167
Path *path = (Path *) lfirst(join_path);
167168

168-
if (intMember(lfirsti(path->joinid), outer_relids) &&
169+
/* path->joinid is the set of base rels that must be part of
170+
* outer_relids in order to use this inner path, because those
171+
* rels are used in the index join quals of this inner path.
172+
*/
173+
if (is_subset(path->joinid, outer_relids) &&
169174
(cheapest == NULL ||
170175
path_is_cheaper(path, cheapest)))
171176
cheapest = path;

src/backend/optimizer/path/joinrels.c

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.37 1999/07/16 04:59:15 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.38 1999/07/27 06:23:12 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -21,8 +21,6 @@
2121
#include "optimizer/tlist.h"
2222

2323
static List *new_joininfo_list(List *joininfo_list, Relids join_relids);
24-
static bool nonoverlap_sets(List *s1, List *s2);
25-
static bool is_subset(List *s1, List *s2);
2624
static void set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel,
2725
RelOptInfo *inner_rel, JoinInfo *jinfo);
2826
static RelOptInfo *make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel,
@@ -373,8 +371,8 @@ new_joininfo_list(List *joininfo_list, Relids join_relids)
373371
RelOptInfo *
374372
get_cheapest_complete_rel(List *join_rel_list)
375373
{
376-
List *xrel = NIL;
377374
RelOptInfo *final_rel = NULL;
375+
List *xrel;
378376

379377
/*
380378
* find the relations that have no further joins, i.e., its joininfos
@@ -383,8 +381,8 @@ get_cheapest_complete_rel(List *join_rel_list)
383381
foreach(xrel, join_rel_list)
384382
{
385383
RelOptInfo *rel = (RelOptInfo *) lfirst(xrel);
386-
List *xjoininfo = NIL;
387384
bool final = true;
385+
List *xjoininfo;
388386

389387
foreach(xjoininfo, rel->joininfo)
390388
{
@@ -405,36 +403,6 @@ get_cheapest_complete_rel(List *join_rel_list)
405403
return final_rel;
406404
}
407405

408-
static bool
409-
nonoverlap_sets(List *s1, List *s2)
410-
{
411-
List *x = NIL;
412-
413-
foreach(x, s1)
414-
{
415-
int e = lfirsti(x);
416-
417-
if (intMember(e, s2))
418-
return false;
419-
}
420-
return true;
421-
}
422-
423-
static bool
424-
is_subset(List *s1, List *s2)
425-
{
426-
List *x = NIL;
427-
428-
foreach(x, s1)
429-
{
430-
int e = lfirsti(x);
431-
432-
if (!intMember(e, s2))
433-
return false;
434-
}
435-
return true;
436-
}
437-
438406
static void
439407
set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_rel, JoinInfo *jinfo)
440408
{
@@ -466,3 +434,39 @@ set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel, RelOptInfo *inner_r
466434

467435
joinrel->tuples = ntuples;
468436
}
437+
438+
/*
439+
* Subset-inclusion tests on integer lists.
440+
*
441+
* XXX these probably ought to be in nodes/list.c or some such place.
442+
*/
443+
444+
bool
445+
nonoverlap_sets(List *s1, List *s2)
446+
{
447+
List *x;
448+
449+
foreach(x, s1)
450+
{
451+
int e = lfirsti(x);
452+
453+
if (intMember(e, s2))
454+
return false;
455+
}
456+
return true;
457+
}
458+
459+
bool
460+
is_subset(List *s1, List *s2)
461+
{
462+
List *x;
463+
464+
foreach(x, s1)
465+
{
466+
int e = lfirsti(x);
467+
468+
if (!intMember(e, s2))
469+
return false;
470+
}
471+
return true;
472+
}

src/include/optimizer/paths.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/*-------------------------------------------------------------------------
22
*
33
* paths.h
4-
* prototypes for various files in optimizer/paths (were separate
5-
* header files
4+
* prototypes for various files in optimizer/path (were separate
5+
* header files)
66
*
77
*
88
* Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: paths.h,v 1.32 1999/07/27 03:51:01 tgl Exp $
10+
* $Id: paths.h,v 1.33 1999/07/27 06:23:11 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -17,12 +17,12 @@
1717
#include "nodes/relation.h"
1818

1919
/*
20-
* allpaths.h
20+
* allpaths.c
2121
*/
2222
extern RelOptInfo *make_one_rel(Query *root, List *rels);
2323

2424
/*
25-
* indxpath.h
25+
* indxpath.c
2626
* routines to generate index paths
2727
*/
2828
extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
@@ -31,26 +31,26 @@ extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
3131
extern List *expand_indexqual_conditions(List *indexquals);
3232

3333
/*
34-
* joinpath.h
34+
* joinpath.c
3535
* routines to create join paths
3636
*/
3737
extern void update_rels_pathlist_for_joins(Query *root, List *joinrels);
3838

3939

4040
/*
41-
* orindxpath.h
41+
* orindxpath.c
4242
*/
4343
extern List *create_or_index_paths(Query *root, RelOptInfo *rel, List *clauses);
4444

4545
/*
46-
* hashutils.h
46+
* hashutils.c
4747
* routines to deal with hash keys and clauses
4848
*/
4949
extern List *group_clauses_by_hashop(List *restrictinfo_list,
5050
Relids inner_relids);
5151

5252
/*
53-
* joinutils.h
53+
* joinutils.c
5454
* generic join method key/clause routines
5555
*/
5656
extern bool order_joinkeys_by_pathkeys(List *pathkeys,
@@ -65,7 +65,7 @@ extern List *new_join_pathkeys(List *outer_pathkeys,
6565
List *join_rel_tlist, List *joinclauses);
6666

6767
/*
68-
* mergeutils.h
68+
* mergeutils.c
6969
* routines to deal with merge keys and clauses
7070
*/
7171
extern List *group_clauses_by_order(List *restrictinfo_list,
@@ -74,7 +74,7 @@ extern MergeInfo *match_order_mergeinfo(PathOrder *ordering,
7474
List *mergeinfo_list);
7575

7676
/*
77-
* joinrels.h
77+
* joinrels.c
7878
* routines to determine which relations to join
7979
*/
8080
extern List *make_rels_by_joins(Query *root, List *old_rels);
@@ -83,6 +83,8 @@ extern List *make_rels_by_clause_joins(Query *root, RelOptInfo *old_rel,
8383
extern List *make_rels_by_clauseless_joins(RelOptInfo *old_rel,
8484
List *inner_rels);
8585
extern RelOptInfo *get_cheapest_complete_rel(List *join_rel_list);
86+
extern bool nonoverlap_sets(List *s1, List *s2);
87+
extern bool is_subset(List *s1, List *s2);
8688

8789
/*
8890
* prototypes for path/prune.c

0 commit comments

Comments
 (0)