diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 5fac94f86317f082ee835c29c5dd9be0baf82e69..a587ef5df5ba8f7d4507e2ba085b0e70cb835adc 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.429 2009/04/05 19:59:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.430 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1606,6 +1606,7 @@ _copyRestrictInfo(RestrictInfo *from)
 	COPY_SCALAR_FIELD(pseudoconstant);
 	COPY_BITMAPSET_FIELD(clause_relids);
 	COPY_BITMAPSET_FIELD(required_relids);
+	COPY_BITMAPSET_FIELD(nullable_relids);
 	COPY_BITMAPSET_FIELD(left_relids);
 	COPY_BITMAPSET_FIELD(right_relids);
 	COPY_NODE_FIELD(orclause);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 36f2bcc2d517b4203b06766bfcab7998061352d4..d4c8b7262c10457658cf7fa59b6037a39dd0766b 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.352 2009/04/05 19:59:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.353 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -759,6 +759,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
 	COMPARE_SCALAR_FIELD(is_pushed_down);
 	COMPARE_SCALAR_FIELD(outerjoin_delayed);
 	COMPARE_BITMAPSET_FIELD(required_relids);
+	COMPARE_BITMAPSET_FIELD(nullable_relids);
 
 	/*
 	 * We ignore all the remaining fields, since they may not be set yet, and
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 67f051311fd37570a0e75fae2cff3960ce8073e1..18e9a5792fa5f26466f11b80cdb742fb27d4f709 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.358 2009/04/05 19:59:40 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.359 2009/04/16 20:42:16 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -1613,6 +1613,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
 	WRITE_BOOL_FIELD(pseudoconstant);
 	WRITE_BITMAPSET_FIELD(clause_relids);
 	WRITE_BITMAPSET_FIELD(required_relids);
+	WRITE_BITMAPSET_FIELD(nullable_relids);
 	WRITE_BITMAPSET_FIELD(left_relids);
 	WRITE_BITMAPSET_FIELD(right_relids);
 	WRITE_NODE_FIELD(orclause);
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 2866689b9a7d12d69e5c0882377e024ccbdb9419..db271e4f1eea724bfd1c6bb981596f1e7e2697c0 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.238 2009/03/11 03:32:22 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.239 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2325,11 +2325,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
 				if (boolqual)
 				{
 					resultquals = lappend(resultquals,
-										  make_restrictinfo(boolqual,
-															true,
-															false,
-															false,
-															NULL));
+										  make_simple_restrictinfo(boolqual));
 					continue;
 				}
 			}
@@ -2360,11 +2356,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
 			{
 				Assert(index->amsearchnulls);
 				resultquals = lappend(resultquals,
-									  make_restrictinfo(clause,
-														true,
-														false,
-														false,
-														NULL));
+									  make_simple_restrictinfo(clause));
 			}
 			else
 				elog(ERROR, "unsupported indexqual type: %d",
@@ -2737,7 +2729,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
 								  matching_cols);
 		rc->rargs = list_truncate((List *) copyObject(clause->rargs),
 								  matching_cols);
-		return make_restrictinfo((Expr *) rc, true, false, false, NULL);
+		return make_simple_restrictinfo((Expr *) rc);
 	}
 	else
 	{
@@ -2746,7 +2738,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
 		opexpr = make_opclause(linitial_oid(new_ops), BOOLOID, false,
 							   copyObject(linitial(clause->largs)),
 							   copyObject(linitial(clause->rargs)));
-		return make_restrictinfo(opexpr, true, false, false, NULL);
+		return make_simple_restrictinfo(opexpr);
 	}
 }
 
@@ -2832,7 +2824,7 @@ prefix_quals(Node *leftop, Oid opfamily,
 			elog(ERROR, "no = operator for opfamily %u", opfamily);
 		expr = make_opclause(oproid, BOOLOID, false,
 							 (Expr *) leftop, (Expr *) prefix_const);
-		result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
+		result = list_make1(make_simple_restrictinfo(expr));
 		return result;
 	}
 
@@ -2847,7 +2839,7 @@ prefix_quals(Node *leftop, Oid opfamily,
 		elog(ERROR, "no >= operator for opfamily %u", opfamily);
 	expr = make_opclause(oproid, BOOLOID, false,
 						 (Expr *) leftop, (Expr *) prefix_const);
-	result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
+	result = list_make1(make_simple_restrictinfo(expr));
 
 	/*-------
 	 * If we can create a string larger than the prefix, we can say
@@ -2864,8 +2856,7 @@ prefix_quals(Node *leftop, Oid opfamily,
 	{
 		expr = make_opclause(oproid, BOOLOID, false,
 							 (Expr *) leftop, (Expr *) greaterstr);
-		result = lappend(result,
-						 make_restrictinfo(expr, true, false, false, NULL));
+		result = lappend(result, make_simple_restrictinfo(expr));
 	}
 
 	return result;
@@ -2928,7 +2919,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
 						 (Expr *) leftop,
 						 (Expr *) makeConst(datatype, -1, -1, opr1right,
 											false, false));
-	result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
+	result = list_make1(make_simple_restrictinfo(expr));
 
 	/* create clause "key <= network_scan_last( rightop )" */
 
@@ -2943,8 +2934,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opfamily, Datum rightop)
 						 (Expr *) leftop,
 						 (Expr *) makeConst(datatype, -1, -1, opr2right,
 											false, false));
-	result = lappend(result,
-					 make_restrictinfo(expr, true, false, false, NULL));
+	result = lappend(result, make_simple_restrictinfo(expr));
 
 	return result;
 }
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index 2f8a67394e2839364206acd64594d551c685c60b..c84591fe0ce66f9e2851aeedeabdb0ee33960df2 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.88 2009/02/15 20:16:21 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.89 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,12 +89,18 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
 	ListCell   *i;
 
 	/*
-	 * Find potentially interesting OR joinclauses.  Note we must ignore any
-	 * joinclauses that are marked outerjoin_delayed or !is_pushed_down,
-	 * because they cannot be pushed down to the per-relation level due to
-	 * outer-join rules.  (XXX in some cases it might be possible to allow
-	 * this, but it would require substantially more bookkeeping about where
-	 * the clause came from.)
+	 * Find potentially interesting OR joinclauses.
+	 *
+	 * We must ignore clauses for which the target rel is in nullable_relids;
+	 * that means there's an outer join below the clause and so it can't be
+	 * enforced at the relation scan level.
+	 *
+	 * We must also ignore clauses that are marked !is_pushed_down (ie they
+	 * are themselves outer-join clauses).  It would be safe to extract an
+	 * index condition from such a clause if we are within the nullable rather
+	 * than the non-nullable side of its join, but we haven't got enough
+	 * context here to tell which applies.  OR clauses in outer-join quals
+	 * aren't exactly common, so we'll let that case go unoptimized for now.
 	 */
 	foreach(i, rel->joininfo)
 	{
@@ -102,7 +108,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
 
 		if (restriction_is_or_clause(rinfo) &&
 			rinfo->is_pushed_down &&
-			!rinfo->outerjoin_delayed)
+			!bms_is_member(rel->relid, rinfo->nullable_relids))
 		{
 			/*
 			 * Use the generate_bitmap_or_paths() machinery to estimate the
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index cf05f033b9ab03469593fbd4bc4ff7a5e240bdc3..952fd7649fd708b1ae8b92ec078156027a383f5a 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.149 2009/02/27 22:41:38 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.150 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,7 +53,7 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 						Relids ojscope,
 						Relids outerjoin_nonnullable);
 static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
-					  bool is_pushed_down);
+					  Relids *nullable_relids_p, bool is_pushed_down);
 static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
 static void check_mergejoinable(RestrictInfo *restrictinfo);
 static void check_hashjoinable(RestrictInfo *restrictinfo);
@@ -755,6 +755,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 	bool		pseudoconstant = false;
 	bool		maybe_equivalence;
 	bool		maybe_outer_join;
+	Relids		nullable_relids;
 	RestrictInfo *restrictinfo;
 
 	/*
@@ -861,6 +862,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 		Assert(!ojscope);
 		is_pushed_down = true;
 		outerjoin_delayed = false;
+		nullable_relids = NULL;
 		/* Don't feed it back for more deductions */
 		maybe_equivalence = false;
 		maybe_outer_join = false;
@@ -882,7 +884,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 		maybe_outer_join = true;
 
 		/* Check to see if must be delayed by lower outer join */
-		outerjoin_delayed = check_outerjoin_delay(root, &relids, false);
+		outerjoin_delayed = check_outerjoin_delay(root,
+												  &relids,
+												  &nullable_relids,
+												  false);
 
 		/*
 		 * Now force the qual to be evaluated exactly at the level of joining
@@ -907,7 +912,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 		is_pushed_down = true;
 
 		/* Check to see if must be delayed by lower outer join */
-		outerjoin_delayed = check_outerjoin_delay(root, &relids, true);
+		outerjoin_delayed = check_outerjoin_delay(root,
+												  &relids,
+												  &nullable_relids,
+												  true);
 
 		if (outerjoin_delayed)
 		{
@@ -957,7 +965,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 									 is_pushed_down,
 									 outerjoin_delayed,
 									 pseudoconstant,
-									 relids);
+									 relids,
+									 nullable_relids);
 
 	/*
 	 * If it's a join clause (either naturally, or because delayed by
@@ -1064,7 +1073,9 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  * If the qual must be delayed, add relids to *relids_p to reflect the lowest
  * safe level for evaluating the qual, and return TRUE.  Any extra delay for
  * higher-level joins is reflected by setting delay_upper_joins to TRUE in
- * SpecialJoinInfo structs.
+ * SpecialJoinInfo structs.  We also compute nullable_relids, the set of
+ * referenced relids that are nullable by lower outer joins (note that this
+ * can be nonempty even for a non-delayed qual).
  *
  * For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have
  * all the rels it mentions, and (2) we are at or above any outer joins that
@@ -1087,8 +1098,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  * mentioning only C cannot be applied below the join to A.
  *
  * For a non-pushed-down qual, this isn't going to determine where we place the
- * qual, but we need to determine outerjoin_delayed anyway for possible use
- * in reconsider_outer_join_clauses().
+ * qual, but we need to determine outerjoin_delayed and nullable_relids anyway
+ * for use later in the planning process.
  *
  * Lastly, a pushed-down qual that references the nullable side of any current
  * join_info_list member and has to be evaluated above that OJ (because its
@@ -1104,13 +1115,26 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
  * two OJs to commute.)
  */
 static bool
-check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
+check_outerjoin_delay(PlannerInfo *root,
+					  Relids *relids_p,				/* in/out parameter */
+					  Relids *nullable_relids_p,	/* output parameter */
 					  bool is_pushed_down)
 {
-	Relids		relids = *relids_p;
+	Relids		relids;
+	Relids		nullable_relids;
 	bool		outerjoin_delayed;
 	bool		found_some;
 
+	/* fast path if no special joins */
+	if (root->join_info_list == NIL)
+	{
+		*nullable_relids_p = NULL;
+		return false;
+	}
+
+	/* must copy relids because we need the original value at the end */
+	relids = bms_copy(*relids_p);
+	nullable_relids = NULL;
 	outerjoin_delayed = false;
 	do
 	{
@@ -1126,18 +1150,23 @@ check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
 				(sjinfo->jointype == JOIN_FULL &&
 				 bms_overlap(relids, sjinfo->min_lefthand)))
 			{
-				/* yes, so set the result flag */
-				outerjoin_delayed = true;
-				/* have we included all its rels in relids? */
+				/* yes; have we included all its rels in relids? */
 				if (!bms_is_subset(sjinfo->min_lefthand, relids) ||
 					!bms_is_subset(sjinfo->min_righthand, relids))
 				{
 					/* no, so add them in */
 					relids = bms_add_members(relids, sjinfo->min_lefthand);
 					relids = bms_add_members(relids, sjinfo->min_righthand);
+					outerjoin_delayed = true;
 					/* we'll need another iteration */
 					found_some = true;
 				}
+				/* track all the nullable rels of relevant OJs */
+				nullable_relids = bms_add_members(nullable_relids,
+												  sjinfo->min_righthand);
+				if (sjinfo->jointype == JOIN_FULL)
+					nullable_relids = bms_add_members(nullable_relids,
+													  sjinfo->min_lefthand);
 				/* set delay_upper_joins if needed */
 				if (is_pushed_down && sjinfo->jointype != JOIN_FULL &&
 					bms_overlap(relids, sjinfo->min_lefthand))
@@ -1146,7 +1175,13 @@ check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
 		}
 	} while (found_some);
 
+	/* identify just the actually-referenced nullable rels */
+	nullable_relids = bms_int_members(nullable_relids, *relids_p);
+
+	/* replace *relids_p, and return nullable_relids */
+	bms_free(*relids_p);
 	*relids_p = relids;
+	*nullable_relids_p = nullable_relids;
 	return outerjoin_delayed;
 }
 
@@ -1352,7 +1387,8 @@ build_implied_join_equality(Oid opno,
 									 true,		/* is_pushed_down */
 									 false,		/* outerjoin_delayed */
 									 false,		/* pseudoconstant */
-									 qualscope);
+									 qualscope,	/* required_relids */
+									 NULL);		/* nullable_relids */
 
 	/* Set mergejoinability info always, and hashjoinability if enabled */
 	check_mergejoinable(restrictinfo);
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 22e2aeb493e6b0fb705d76eafa8477766407542b..0fcfd0ed509d724253e0e143383cf8f349bd4bcd 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.57 2009/02/06 23:43:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.58 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,12 +27,14 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
 						   bool is_pushed_down,
 						   bool outerjoin_delayed,
 						   bool pseudoconstant,
-						   Relids required_relids);
+						   Relids required_relids,
+						   Relids nullable_relids);
 static Expr *make_sub_restrictinfos(Expr *clause,
 					   bool is_pushed_down,
 					   bool outerjoin_delayed,
 					   bool pseudoconstant,
-					   Relids required_relids);
+					   Relids required_relids,
+					   Relids nullable_relids);
 static bool join_clause_is_redundant(PlannerInfo *root,
 						 RestrictInfo *rinfo,
 						 List *reference_list);
@@ -44,9 +46,9 @@ static bool join_clause_is_redundant(PlannerInfo *root,
  * Build a RestrictInfo node containing the given subexpression.
  *
  * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the
- * RestrictInfo must be supplied by the caller.  required_relids can be NULL,
- * in which case it defaults to the actual clause contents (i.e.,
- * clause_relids).
+ * RestrictInfo must be supplied by the caller, as well as the correct value
+ * for nullable_relids.  required_relids can be NULL, in which case it
+ * defaults to the actual clause contents (i.e., clause_relids).
  *
  * We initialize fields that depend only on the given subexpression, leaving
  * others that depend on context (or may never be needed at all) to be filled
@@ -57,7 +59,8 @@ make_restrictinfo(Expr *clause,
 				  bool is_pushed_down,
 				  bool outerjoin_delayed,
 				  bool pseudoconstant,
-				  Relids required_relids)
+				  Relids required_relids,
+				  Relids nullable_relids)
 {
 	/*
 	 * If it's an OR clause, build a modified copy with RestrictInfos inserted
@@ -68,7 +71,8 @@ make_restrictinfo(Expr *clause,
 													   is_pushed_down,
 													   outerjoin_delayed,
 													   pseudoconstant,
-													   required_relids);
+													   required_relids,
+													   nullable_relids);
 
 	/* Shouldn't be an AND clause, else AND/OR flattening messed up */
 	Assert(!and_clause((Node *) clause));
@@ -78,7 +82,8 @@ make_restrictinfo(Expr *clause,
 									  is_pushed_down,
 									  outerjoin_delayed,
 									  pseudoconstant,
-									  required_relids);
+									  required_relids,
+									  nullable_relids);
 }
 
 /*
@@ -92,8 +97,8 @@ make_restrictinfo(Expr *clause,
  * RestrictInfos.
  *
  * The caller must pass is_pushed_down, but we assume outerjoin_delayed
- * and pseudoconstant are false (no such qual should ever get into a
- * bitmapqual).
+ * and pseudoconstant are false and nullable_relids is NULL (no other
+ * kind of qual should ever get into a bitmapqual).
  *
  * If include_predicates is true, we add any partial index predicates to
  * the explicit index quals.  When this is not true, we return a condition
@@ -224,6 +229,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
 													  is_pushed_down,
 													  false,
 													  false,
+													  NULL,
 													  NULL));
 		}
 	}
@@ -250,6 +256,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
 													   is_pushed_down,
 													   false,
 													   false,
+													   NULL,
 													   NULL));
 			}
 		}
@@ -274,7 +281,8 @@ make_restrictinfo_internal(Expr *clause,
 						   bool is_pushed_down,
 						   bool outerjoin_delayed,
 						   bool pseudoconstant,
-						   Relids required_relids)
+						   Relids required_relids,
+						   Relids nullable_relids)
 {
 	RestrictInfo *restrictinfo = makeNode(RestrictInfo);
 
@@ -284,6 +292,7 @@ make_restrictinfo_internal(Expr *clause,
 	restrictinfo->outerjoin_delayed = outerjoin_delayed;
 	restrictinfo->pseudoconstant = pseudoconstant;
 	restrictinfo->can_join = false;		/* may get set below */
+	restrictinfo->nullable_relids = nullable_relids;
 
 	/*
 	 * If it's a binary opclause, set up left/right relids info. In any case
@@ -369,7 +378,8 @@ make_restrictinfo_internal(Expr *clause,
  * simple clauses are valid RestrictInfos.
  *
  * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag
- * values can be applied to all RestrictInfo nodes in the result.
+ * values can be applied to all RestrictInfo nodes in the result.  Likewise
+ * for nullable_relids.
  *
  * The given required_relids are attached to our top-level output,
  * but any OR-clause constituents are allowed to default to just the
@@ -380,7 +390,8 @@ make_sub_restrictinfos(Expr *clause,
 					   bool is_pushed_down,
 					   bool outerjoin_delayed,
 					   bool pseudoconstant,
-					   Relids required_relids)
+					   Relids required_relids,
+					   Relids nullable_relids)
 {
 	if (or_clause((Node *) clause))
 	{
@@ -393,13 +404,15 @@ make_sub_restrictinfos(Expr *clause,
 													is_pushed_down,
 													outerjoin_delayed,
 													pseudoconstant,
-													NULL));
+													NULL,
+													nullable_relids));
 		return (Expr *) make_restrictinfo_internal(clause,
 												   make_orclause(orlist),
 												   is_pushed_down,
 												   outerjoin_delayed,
 												   pseudoconstant,
-												   required_relids);
+												   required_relids,
+												   nullable_relids);
 	}
 	else if (and_clause((Node *) clause))
 	{
@@ -412,7 +425,8 @@ make_sub_restrictinfos(Expr *clause,
 													 is_pushed_down,
 													 outerjoin_delayed,
 													 pseudoconstant,
-													 required_relids));
+													 required_relids,
+													 nullable_relids));
 		return make_andclause(andlist);
 	}
 	else
@@ -421,7 +435,8 @@ make_sub_restrictinfos(Expr *clause,
 												   is_pushed_down,
 												   outerjoin_delayed,
 												   pseudoconstant,
-												   required_relids);
+												   required_relids,
+												   nullable_relids);
 }
 
 /*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index cf567b997461cca77a8ab82a09c86b7a9634a7d3..6a72504a2f79b752e52c1ad1c0ab7729a54e3d43 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.171 2009/03/26 17:15:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.172 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -920,8 +920,14 @@ typedef struct HashPath
  *
  * RestrictInfo nodes also contain an outerjoin_delayed flag, which is true
  * if the clause's applicability must be delayed due to any outer joins
- * appearing below its own syntactic level (ie, it references any Vars from
- * the nullable side of any lower outer join).
+ * appearing below it (ie, it has to be postponed to some join level higher
+ * than the set of relations it actually references).  There is also a
+ * nullable_relids field, which is the set of rels it references that can be
+ * forced null by some outer join below the clause.  outerjoin_delayed = true
+ * is subtly different from nullable_relids != NULL: a clause might reference
+ * some nullable rels and yet not be outerjoin_delayed because it also
+ * references all the other rels of the outer join(s).  A clause that is not
+ * outerjoin_delayed can be enforced anywhere it is computable.
  *
  * In general, the referenced clause might be arbitrarily complex.	The
  * kinds of clauses we can handle as indexscan quals, mergejoin clauses,
@@ -983,6 +989,9 @@ typedef struct RestrictInfo
 	/* The set of relids required to evaluate the clause: */
 	Relids		required_relids;
 
+	/* The relids used in the clause that are nullable by lower outer joins: */
+	Relids		nullable_relids;
+
 	/* These fields are set for any binary opclause: */
 	Relids		left_relids;	/* relids in left side of clause */
 	Relids		right_relids;	/* relids in right side of clause */
diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h
index 7791afe947b762aae1de78c79cc2b0b894d7ef4f..52d256ed2849e296319339e598819b2e162e6eac 100644
--- a/src/include/optimizer/restrictinfo.h
+++ b/src/include/optimizer/restrictinfo.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.42 2009/01/01 17:24:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.43 2009/04/16 20:42:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,11 +17,16 @@
 #include "nodes/relation.h"
 
 
+/* Convenience macro for the common case of a valid-everywhere qual */
+#define make_simple_restrictinfo(clause)  \
+	make_restrictinfo(clause, true, false, false, NULL, NULL)
+
 extern RestrictInfo *make_restrictinfo(Expr *clause,
 				  bool is_pushed_down,
 				  bool outerjoin_delayed,
 				  bool pseudoconstant,
-				  Relids required_relids);
+				  Relids required_relids,
+				  Relids nullable_relids);
 extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
 								  bool is_pushed_down,
 								  bool include_predicates);