Fix another semijoin-ordering bug. We already knew that we couldn't
authorTom Lane <[email protected]>
Tue, 21 Jul 2009 02:02:44 +0000 (02:02 +0000)
committerTom Lane <[email protected]>
Tue, 21 Jul 2009 02:02:44 +0000 (02:02 +0000)
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)

src/backend/optimizer/README
src/backend/optimizer/plan/initsplan.c

index e378ad74f6fc8370d374d43b95ddf1dd55f5e70f..4cc6f3f808a202b237c7d1d51ec5c373a7272afb 100644 (file)
@@ -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
index 37c89c7bbb28747a6a3bbf811a101271706cc492..804ff7ed27662c061b68598ecff6ec35b9546e25 100644 (file)
@@ -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)
                        {