*
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.99 2010/01/02 16:57:44 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeMergejoin.c,v 1.100 2010/01/05 23:25:36 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.128 2010/01/02 16:57:46 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.129 2010/01/05 23:25:36 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-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.216 2010/01/02 16:58:04 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.217 2010/01/05 23:25:36 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;