*
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.97 2009/06/11 14:48:57 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.97.2.1 2010/01/05 23:25:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
     * want to report that the tuples are equal.  Instead, if result is still
     * 0, change it to +1.  This will result in advancing the inner side of
     * the join.
+    *
+    * Likewise, if there was a constant-false joinqual, do not report
+    * equality.  We have to check this as part of the mergequals, else the
+    * rescan logic will do the wrong thing.
     */
-   if (nulleqnull && result == 0)
+   if (result == 0 &&
+       (nulleqnull || mergestate->mj_ConstFalseJoin))
        result = 1;
 
    MemoryContextSwitchTo(oldContext);
 }
 
 
+/*
+ * Check that a qual condition is constant true or constant false.
+ * If it is constant false (or null), set *is_const_false to TRUE.
+ *
+ * Constant true would normally be represented by a NIL list, but we allow an
+ * actual bool Const as well.  We do expect that the planner will have thrown
+ * away any non-constant terms that have been ANDed with a constant false.
+ */
+static bool
+check_constant_qual(List *qual, bool *is_const_false)
+{
+   ListCell   *lc;
+
+   foreach(lc, qual)
+   {
+       Const  *con = (Const *) lfirst(lc);
+
+       if (!con || !IsA(con, Const))
+           return false;
+       if (con->constisnull || !DatumGetBool(con->constvalue))
+           *is_const_false = true;
+   }
+   return true;
+}
+
+
 /* ----------------------------------------------------------------
  *     ExecMergeTupleDump
  *
                     * state for the rescanned inner tuples.  We know all of
                     * them will match this new outer tuple and therefore
                     * won't be emitted as fill tuples.  This works *only*
-                    * because we require the extra joinquals to be nil when
-                    * doing a right or full join --- otherwise some of the
-                    * rescanned tuples might fail the extra joinquals.
+                    * because we require the extra joinquals to be constant
+                    * when doing a right or full join --- otherwise some of
+                    * the rescanned tuples might fail the extra joinquals.
+                    * This obviously won't happen for a constant-true extra
+                    * joinqual, while the constant-false case is handled by
+                    * forcing the merge clause to never match, so we never
+                    * get here.
                     */
                    ExecRestrPos(innerPlan);
 
    mergestate->js.joinqual = (List *)
        ExecInitExpr((Expr *) node->join.joinqual,
                     (PlanState *) mergestate);
+   mergestate->mj_ConstFalseJoin = false;
    /* mergeclauses are handled below */
 
    /*
                              ExecGetResultType(outerPlanState(mergestate)));
 
            /*
-            * Can't handle right or full join with non-nil extra joinclauses.
-            * This should have been caught by planner.
+            * Can't handle right or full join with non-constant extra
+            * joinclauses.  This should have been caught by planner.
             */
-           if (node->join.joinqual != NIL)
+           if (!check_constant_qual(node->join.joinqual,
+                                    &mergestate->mj_ConstFalseJoin))
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("RIGHT JOIN is only supported with merge-joinable join conditions")));
                              ExecGetResultType(innerPlanState(mergestate)));
 
            /*
-            * Can't handle right or full join with non-nil extra joinclauses.
+            * Can't handle right or full join with non-constant extra
+            * joinclauses.  This should have been caught by planner.
             */
-           if (node->join.joinqual != NIL)
+           if (!check_constant_qual(node->join.joinqual,
+                                    &mergestate->mj_ConstFalseJoin))
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                         errmsg("FULL JOIN is only supported with merge-joinable join conditions")));
 
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.122 2009/06/11 14:48:59 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.122.2.1 2010/01/05 23:25:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
        if (isouterjoin && restrictinfo->is_pushed_down)
            continue;
 
+       /* Check that clause is a mergeable operator clause */
        if (!restrictinfo->can_join ||
            restrictinfo->mergeopfamilies == NIL)
        {
-           have_nonmergeable_joinclause = true;
+           /*
+            * The executor can handle extra joinquals that are constants,
+            * but not anything else, when doing right/full merge join.  (The
+            * reason to support constants is so we can do FULL JOIN ON
+            * FALSE.)
+            */
+           if (!restrictinfo->clause || !IsA(restrictinfo->clause, Const))
+               have_nonmergeable_joinclause = true;
            continue;           /* not mergejoinable */
        }
 
 
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.205.2.1 2009/08/23 18:26:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.205.2.2 2010/01/05 23:25:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *     Clauses            info for each mergejoinable clause
  *     JoinState          current "state" of join.  see execdefs.h
  *     ExtraMarks         true to issue extra Mark operations on inner scan
+ *     ConstFalseJoin     true if we have a constant-false joinqual
  *     FillOuter          true if should emit unjoined outer tuples anyway
  *     FillInner          true if should emit unjoined inner tuples anyway
  *     MatchedOuter       true if found a join match for current outer tuple
    MergeJoinClause mj_Clauses; /* array of length mj_NumClauses */
    int         mj_JoinState;
    bool        mj_ExtraMarks;
+   bool        mj_ConstFalseJoin;
    bool        mj_FillOuter;
    bool        mj_FillInner;
    bool        mj_MatchedOuter;