diff options
author | Tom Lane | 2009-07-21 02:02:44 +0000 |
---|---|---|
committer | Tom Lane | 2009-07-21 02:02:44 +0000 |
commit | 1c61073e53caad8f6276ff3d66d90996fe5f8b81 (patch) | |
tree | d86bef4add8fc85e80ac43dcde68d6fc7a2b8ff1 | |
parent | 6c803e77e0c27bc31222e2cee90a119a18066993 (diff) |
Fix another semijoin-ordering bug. We already knew that we couldn't
reorder a semijoin into or out of the righthand side of another semijoin,
but actually it doesn't work to reorder it into or out of the righthand
side of a left or antijoin, either. Per bug #4906 from Mathieu Fenniak.
This was sloppy thinking on my part. This identity does work:
( A left join B on (Pab) ) semijoin C on (Pac)
==
( A semijoin C on (Pac) ) left join B on (Pab)
but I failed to see that that doesn't mean this does:
( A left join B on (Pab) ) semijoin C on (Pbc)
!=
A left join ( B semijoin C on (Pbc) ) on (Pab)
-rw-r--r-- | src/backend/optimizer/README | 8 | ||||
-rw-r--r-- | src/backend/optimizer/plan/initsplan.c | 9 |
2 files changed, 9 insertions, 8 deletions
diff --git a/src/backend/optimizer/README b/src/backend/optimizer/README index e378ad74f6..4cc6f3f808 100644 --- a/src/backend/optimizer/README +++ b/src/backend/optimizer/README @@ -214,10 +214,10 @@ out of the nullable side of an outer join: != (A leftjoin B on (Pab)) join C on (Pbc) SEMI joins work a little bit differently. A semijoin can be reassociated -into or out of the lefthand side of another semijoin, but not into or out -of the righthand side. Likewise, an inner join, left join, or antijoin -can be reassociated into or out of the lefthand side of a semijoin, but -not into or out of the righthand side. +into or out of the lefthand side of another semijoin, left join, or +antijoin, but not into or out of the righthand side. Likewise, an inner +join, left join, or antijoin can be reassociated into or out of the +lefthand side of a semijoin, but not into or out of the righthand side. ANTI joins work approximately like LEFT joins, except that identity 3 fails if the join to C is an antijoin (even if Pbc is strict, and in diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 37c89c7bbb..804ff7ed27 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -630,8 +630,8 @@ make_outerjoininfo(PlannerInfo *root, * min_lefthand + min_righthand. This is because there might be other * OJs below this one that this one can commute with, but we cannot * commute with them if we don't with this one.) Also, if the current - * join is an antijoin, we must preserve ordering regardless of - * strictness. + * join is a semijoin or antijoin, we must preserve ordering + * regardless of strictness. * * Note: I believe we have to insist on being strict for at least one * rel in the lower OJ's min_righthand, not its whole syn_righthand. @@ -639,7 +639,7 @@ make_outerjoininfo(PlannerInfo *root, if (bms_overlap(left_rels, otherinfo->syn_righthand)) { if (bms_overlap(clause_relids, otherinfo->syn_righthand) && - (jointype == JOIN_ANTI || + (jointype == JOIN_SEMI || jointype == JOIN_ANTI || !bms_overlap(strict_relids, otherinfo->min_righthand))) { min_lefthand = bms_add_members(min_lefthand, @@ -655,7 +655,7 @@ make_outerjoininfo(PlannerInfo *root, * can interchange the ordering of the two OJs; otherwise we must add * lower OJ's full syntactic relset to min_righthand. Here, we must * preserve ordering anyway if either the current join is a semijoin, - * or the lower OJ is an antijoin. + * or the lower OJ is either a semijoin or an antijoin. * * Here, we have to consider that "our join condition" includes any * clauses that syntactically appeared above the lower OJ and below @@ -672,6 +672,7 @@ make_outerjoininfo(PlannerInfo *root, { if (bms_overlap(clause_relids, otherinfo->syn_righthand) || jointype == JOIN_SEMI || + otherinfo->jointype == JOIN_SEMI || otherinfo->jointype == JOIN_ANTI || !otherinfo->lhs_strict || otherinfo->delay_upper_joins) { |