Skip to content

Commit 1ca695d

Browse files
committed
Fix another thinko in join_is_legal's handling of semijoins: we have to test
for the case that the semijoin was implemented within either input by unique-ifying its RHS before we test to see if it appears to match the current join situation. The previous coding would select semijoin logic in situations where we'd already unique-ified the RHS and joined it to some unrelated relation(s), and then came to join it to the semijoin's LHS. That still gave the right answer as far as the semijoin itself was concerned, but would lead to incorrectly examining only an arbitrary one of the matchable rows from the unrelated relation(s). The cause of this thinko was incorrect unification of the pre-8.4 logic for IN joins and OUTER joins --- the comparable case for outer joins can be handled after making the match test, but that's because there is nothing like the unique-ification escape hatch for outer joins. Per bug #4934 from Benjamin Reed.
1 parent 00f0b47 commit 1ca695d

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

src/backend/optimizer/path/joinrels.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.101 2009/07/19 20:32:48 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.102 2009/07/23 17:42:06 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -399,6 +399,22 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
399399
bms_is_subset(sjinfo->min_righthand, rel2->relids))
400400
continue;
401401

402+
/*
403+
* If it's a semijoin and we already joined the RHS to any other
404+
* rels within either input, then we must have unique-ified the RHS
405+
* at that point (see below). Therefore the semijoin is no longer
406+
* relevant in this join path.
407+
*/
408+
if (sjinfo->jointype == JOIN_SEMI)
409+
{
410+
if (bms_is_subset(sjinfo->syn_righthand, rel1->relids) &&
411+
!bms_equal(sjinfo->syn_righthand, rel1->relids))
412+
continue;
413+
if (bms_is_subset(sjinfo->syn_righthand, rel2->relids) &&
414+
!bms_equal(sjinfo->syn_righthand, rel2->relids))
415+
continue;
416+
}
417+
402418
/*
403419
* If one input contains min_lefthand and the other contains
404420
* min_righthand, then we can perform the SJ at this join.
@@ -491,9 +507,6 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
491507
* We assume that make_outerjoininfo() set things up correctly
492508
* so that we'll only match to some SJ if the join is valid.
493509
* Set flag here to check at bottom of loop.
494-
*
495-
* For a semijoin, assume it's okay if either side fully contains
496-
* the RHS (per the unique-ification case above).
497510
*----------
498511
*/
499512
if (sjinfo->jointype != JOIN_SEMI &&
@@ -503,12 +516,6 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
503516
/* seems OK */
504517
Assert(!bms_overlap(joinrelids, sjinfo->min_lefthand));
505518
}
506-
else if (sjinfo->jointype == JOIN_SEMI &&
507-
(bms_is_subset(sjinfo->syn_righthand, rel1->relids) ||
508-
bms_is_subset(sjinfo->syn_righthand, rel2->relids)))
509-
{
510-
/* seems OK */
511-
}
512519
else
513520
is_valid_inner = false;
514521
}

0 commit comments

Comments
 (0)