]> granicus.if.org Git - postgresql/commitdiff
Fix another semijoin-ordering bug. We already knew that we couldn't
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 21 Jul 2009 02:02:44 +0000 (02:02 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 a3ce21b690e4b7d241ce3519f987342778ea6e69..f406e642db32ef0d0d6326a90ec929c134da65c0 100644 (file)
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/optimizer/README,v 1.49 2009/02/27 22:41:37 tgl Exp $
+$PostgreSQL: pgsql/src/backend/optimizer/README,v 1.50 2009/07/21 02:02:44 tgl Exp $
 
 Optimizer
 =========
@@ -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 8a189d4443db68246643e2b6b68f8e840d27bf35..9ea928ed9d49f0089a24628ac3c0d6967fe10d87 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.154 2009/06/11 14:48:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.155 2009/07/21 02:02:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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)
                        {