Skip to content

Commit c084f61

Browse files
committed
Make real sure we don't reassociate joins into or out of SEMI/ANTI joins.
Per the discussion in optimizer/README, it's unsafe to reassociate anything into or out of the RHS of a SEMI or ANTI join. An example from Piotr Stefaniak showed that join_is_legal() wasn't sufficiently enforcing this rule, so lock it down a little harder. I couldn't find a reasonably simple example of the optimizer trying to do this, so no new regression test. (Piotr's example involved the random search in GEQO accidentally trying an invalid case and triggering a sanity check way downstream in clause selectivity estimation, which did not seem like a sequence of events that would be useful to memorialize in a regression test as-is.) Back-patch to all active branches.
1 parent f9ab07b commit c084f61

File tree

1 file changed

+9
-6
lines changed

1 file changed

+9
-6
lines changed

src/backend/optimizer/path/joinrels.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
462462
/*
463463
* Otherwise, the proposed join overlaps the RHS but isn't a valid
464464
* implementation of this SJ. It might still be a legal join,
465-
* however, if it does not overlap the LHS.
465+
* however, if it does not overlap the LHS. But we never allow
466+
* violations of the RHS of SEMI or ANTI joins. (In practice,
467+
* therefore, only LEFT joins ever allow RHS violation.)
466468
*/
467-
if (bms_overlap(joinrelids, sjinfo->min_lefthand))
468-
return false;
469+
if (sjinfo->jointype == JOIN_SEMI ||
470+
sjinfo->jointype == JOIN_ANTI ||
471+
bms_overlap(joinrelids, sjinfo->min_lefthand))
472+
return false; /* invalid join path */
469473

470474
/*----------
471475
* If both inputs overlap the RHS, assume that it's OK. Since the
@@ -490,15 +494,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
490494
* Set flag here to check at bottom of loop.
491495
*----------
492496
*/
493-
if (sjinfo->jointype != JOIN_SEMI &&
494-
bms_overlap(rel1->relids, sjinfo->min_righthand) &&
497+
if (bms_overlap(rel1->relids, sjinfo->min_righthand) &&
495498
bms_overlap(rel2->relids, sjinfo->min_righthand))
496499
{
497500
/* both overlap; assume OK */
498501
}
499502
else
500503
{
501-
/* one overlaps, the other doesn't (or it's a semijoin) */
504+
/* one overlaps, the other doesn't */
502505
is_valid_inner = false;
503506
}
504507
}

0 commit comments

Comments
 (0)