* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.81 2006/10/24 17:50:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.82 2006/12/12 21:31:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
    /*
     * Join if there is an applicable join clause.
     */
-   if (have_relevant_joinclause(outer_rel, inner_rel))
+   if (have_relevant_joinclause(root, outer_rel, inner_rel))
        return true;
 
    /*
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.81 2006/10/24 17:50:22 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.82 2006/12/12 21:31:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
            ListCell   *other_rels;
            ListCell   *r2;
 
-           if (old_rel->joininfo == NIL)
-               continue;       /* we ignore clauseless joins here */
+           /*
+            * We can ignore clauseless joins here, *except* when there are
+            * outer joins --- then we might have to force a bushy outer
+            * join.  See have_relevant_joinclause().
+            */
+           if (old_rel->joininfo == NIL && root->oj_info_list == NIL)
+               continue;
 
            if (k == other_level)
                other_rels = lnext(r);  /* only consider remaining rels */
                     * pair of rels.  Do so if there is at least one usable
                     * join clause.
                     */
-                   if (have_relevant_joinclause(old_rel, new_rel))
+                   if (have_relevant_joinclause(root, old_rel, new_rel))
                    {
                        RelOptInfo *jrel;
 
        RelOptInfo *other_rel = (RelOptInfo *) lfirst(l);
 
        if (!bms_overlap(old_rel->relids, other_rel->relids) &&
-           have_relevant_joinclause(old_rel, other_rel))
+           have_relevant_joinclause(root, old_rel, other_rel))
        {
            RelOptInfo *jrel;
 
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.44 2006/03/05 15:58:31 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/util/joininfo.c,v 1.45 2006/12/12 21:31:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *     the two given relations.
  */
 bool
-have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2)
+have_relevant_joinclause(PlannerInfo *root,
+                        RelOptInfo *rel1, RelOptInfo *rel2)
 {
    bool        result = false;
    Relids      join_relids;
        }
    }
 
+   /*
+    * It's possible that the rels correspond to the left and right sides
+    * of a degenerate outer join, that is, one with no joinclause mentioning
+    * the non-nullable side.  The above scan will then have failed to locate
+    * any joinclause indicating we should join, but nonetheless we must
+    * allow the join to occur.
+    *
+    * Note: we need no comparable check for IN-joins because we can handle
+    * sequential buildup of an IN-join to multiple outer-side rels; therefore
+    * the "last ditch" case in make_rels_by_joins() always succeeds.  We
+    * could dispense with this hack if we were willing to try bushy plans
+    * in the "last ditch" case, but that seems too expensive.
+    */
+   if (!result)
+   {
+       foreach(l, root->oj_info_list)
+       {
+           OuterJoinInfo *ojinfo = (OuterJoinInfo *) lfirst(l);
+
+           /* ignore full joins --- other mechanisms handle them */
+           if (ojinfo->is_full_join)
+               continue;
+
+           if ((bms_is_subset(ojinfo->min_lefthand, rel1->relids) &&
+                bms_is_subset(ojinfo->min_righthand, rel2->relids)) ||
+               (bms_is_subset(ojinfo->min_lefthand, rel2->relids) &&
+                bms_is_subset(ojinfo->min_righthand, rel1->relids)))
+           {
+               result = true;
+               break;
+           }
+       }
+   }
+
    bms_free(join_relids);
 
    return result;
 
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.31 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/joininfo.h,v 1.32 2006/12/12 21:31:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "nodes/relation.h"
 
 
-extern bool have_relevant_joinclause(RelOptInfo *rel1, RelOptInfo *rel2);
+extern bool have_relevant_joinclause(PlannerInfo *root,
+                                    RelOptInfo *rel1, RelOptInfo *rel2);
 
 extern void add_join_clause_to_rels(PlannerInfo *root,
                        RestrictInfo *restrictinfo,