diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2015-08-05 14:39:07 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2015-08-05 14:39:07 -0400 |
commit | 4d94b5f1f003404f86b2659eff9814466d03640e (patch) | |
tree | 8fd531f64ad1bc662b642249dbcae8630da8eb6c /src | |
parent | aa9f8cb131a91df16db69fd271f81e761db29625 (diff) | |
download | postgresql-4d94b5f1f003404f86b2659eff9814466d03640e.tar.gz postgresql-4d94b5f1f003404f86b2659eff9814466d03640e.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index bb2aa99ded1..9ed7487ef8f 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -470,10 +470,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, /* * Otherwise, the proposed join overlaps the RHS but isn't a valid * implementation of this SJ. It might still be a legal join, - * however, if it does not overlap the LHS. + * however, if it does not overlap the LHS. But we never allow + * violations of the RHS of SEMI or ANTI joins. (In practice, + * therefore, only LEFT joins ever allow RHS violation.) */ - if (bms_overlap(joinrelids, sjinfo->min_lefthand)) - return false; + if (sjinfo->jointype == JOIN_SEMI || + sjinfo->jointype == JOIN_ANTI || + bms_overlap(joinrelids, sjinfo->min_lefthand)) + return false; /* invalid join path */ /*---------- * 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, * Set flag here to check at bottom of loop. *---------- */ - if (sjinfo->jointype != JOIN_SEMI && - bms_overlap(rel1->relids, sjinfo->min_righthand) && + if (bms_overlap(rel1->relids, sjinfo->min_righthand) && bms_overlap(rel2->relids, sjinfo->min_righthand)) { /* both overlap; assume OK */ } else { - /* one overlaps, the other doesn't (or it's a semijoin) */ + /* one overlaps, the other doesn't */ is_valid_inner = false; } } |