Skip to content

Commit 6af9ee4

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 18382ae commit 6af9ee4

File tree

1 file changed

+9
-6
lines changed

1 file changed

+9
-6
lines changed

src/backend/optimizer/path/joinrels.c

+9-6
Original file line numberDiff line numberDiff line change
@@ -470,10 +470,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
470470
/*
471471
* Otherwise, the proposed join overlaps the RHS but isn't a valid
472472
* implementation of this SJ. It might still be a legal join,
473-
* however, if it does not overlap the LHS.
473+
* however, if it does not overlap the LHS. But we never allow
474+
* violations of the RHS of SEMI or ANTI joins. (In practice,
475+
* therefore, only LEFT joins ever allow RHS violation.)
474476
*/
475-
if (bms_overlap(joinrelids, sjinfo->min_lefthand))
476-
return false;
477+
if (sjinfo->jointype == JOIN_SEMI ||
478+
sjinfo->jointype == JOIN_ANTI ||
479+
bms_overlap(joinrelids, sjinfo->min_lefthand))
480+
return false; /* invalid join path */
477481

478482
/*----------
479483
* If both inputs overlap the RHS, assume that it's OK. Since the
@@ -498,15 +502,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
498502
* Set flag here to check at bottom of loop.
499503
*----------
500504
*/
501-
if (sjinfo->jointype != JOIN_SEMI &&
502-
bms_overlap(rel1->relids, sjinfo->min_righthand) &&
505+
if (bms_overlap(rel1->relids, sjinfo->min_righthand) &&
503506
bms_overlap(rel2->relids, sjinfo->min_righthand))
504507
{
505508
/* both overlap; assume OK */
506509
}
507510
else
508511
{
509-
/* one overlaps, the other doesn't (or it's a semijoin) */
512+
/* one overlaps, the other doesn't */
510513
is_valid_inner = false;
511514
}
512515
}

0 commit comments

Comments
 (0)