diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 362181c26f4ae073a981ffc08cefd88752298ebd..0c611015134ef668f84e2f6339f99bb99362ad0e 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -398,8 +398,13 @@ MJCompare(MergeJoinState *mergestate)
 	 * 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);
@@ -487,6 +492,32 @@ MJFillInner(MergeJoinState *node)
 }
 
 
+/*
+ * 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
  *
@@ -1025,9 +1056,13 @@ ExecMergeJoin(MergeJoinState *node)
 					 * 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);
 
@@ -1439,6 +1474,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
 	mergestate->js.joinqual = (List *)
 		ExecInitExpr((Expr *) node->join.joinqual,
 					 (PlanState *) mergestate);
+	mergestate->mj_ConstFalseJoin = false;
 	/* mergeclauses are handled below */
 
 	/*
@@ -1498,10 +1534,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
 							  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")));
@@ -1517,9 +1554,11 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
 							  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")));
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index f69ffbed7a8d94b23897839fadc5132458340553..2e208cb6210bb184d41efc4f285ef186b489ea98 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1184,10 +1184,18 @@ select_mergejoin_clauses(PlannerInfo *root,
 		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 */
 		}
 
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e091d0b1d4371641b7ff04291b0daabac248be42..866cd3ef3fdd765b641dec67af726f33b8deb08d 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -1396,6 +1396,7 @@ typedef struct NestLoopState
  *		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
@@ -1419,6 +1420,7 @@ typedef struct MergeJoinState
 	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;
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index fed424cb33b99ae65df93f7fe6ff93a418a51c60..f2b346e50841bb05287dba3100321efb2fc6b4b9 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -2443,3 +2443,51 @@ group by t1.q2 order by 1;
   4567890123456789 |     6
 (4 rows)
 
+--
+-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
+--
+select * from int4_tbl a full join int4_tbl b on true;
+     f1      |     f1      
+-------------+-------------
+           0 |           0
+           0 |      123456
+           0 |     -123456
+           0 |  2147483647
+           0 | -2147483647
+      123456 |           0
+      123456 |      123456
+      123456 |     -123456
+      123456 |  2147483647
+      123456 | -2147483647
+     -123456 |           0
+     -123456 |      123456
+     -123456 |     -123456
+     -123456 |  2147483647
+     -123456 | -2147483647
+  2147483647 |           0
+  2147483647 |      123456
+  2147483647 |     -123456
+  2147483647 |  2147483647
+  2147483647 | -2147483647
+ -2147483647 |           0
+ -2147483647 |      123456
+ -2147483647 |     -123456
+ -2147483647 |  2147483647
+ -2147483647 | -2147483647
+(25 rows)
+
+select * from int4_tbl a full join int4_tbl b on false;
+     f1      |     f1      
+-------------+-------------
+             |           0
+             |      123456
+             |     -123456
+             |  2147483647
+             | -2147483647
+           0 |            
+      123456 |            
+     -123456 |            
+  2147483647 |            
+ -2147483647 |            
+(10 rows)
+
diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql
index 46ff66c6909803437816825dd4d119117b09a5f3..977765551d5a020c6bda8f55b16539ff67212c3a 100644
--- a/src/test/regress/sql/join.sql
+++ b/src/test/regress/sql/join.sql
@@ -561,3 +561,9 @@ from int8_tbl t1 left join
   (select q1, case when q2=1 then 1 else q2 end as q2 from int8_tbl) t2
   on (t1.q2 = t2.q1)
 group by t1.q2 order by 1;
+
+--
+-- test the corner cases FULL JOIN ON TRUE and FULL JOIN ON FALSE
+--
+select * from int4_tbl a full join int4_tbl b on true;
+select * from int4_tbl a full join int4_tbl b on false;