diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b6c6331d17085809b4d6ea59a02a23a0e416d8ac..c6393effcd649006f5c3519b58059b08a6767736 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.382 2007/09/03 18:46:30 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.383 2007/10/11 18:05:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,6 +83,7 @@ _copyPlannedStmt(PlannedStmt *from)
 	COPY_BITMAPSET_FIELD(rewindPlanIDs);
 	COPY_NODE_FIELD(returningLists);
 	COPY_NODE_FIELD(rowMarks);
+	COPY_NODE_FIELD(relationOids);
 	COPY_SCALAR_FIELD(nParamExec);
 
 	return newnode;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index db0bf7c050defcb2ef9f2e5433d79aacb32e5896..005879b8c910e5ef892dacd09612719045e5a87d 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.314 2007/08/31 01:44:05 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.315 2007/10/11 18:05:27 tgl Exp $
  *
  * NOTES
  *	  Every node type that can appear in stored rules' parsetrees *must*
@@ -250,6 +250,7 @@ _outPlannedStmt(StringInfo str, PlannedStmt *node)
 	WRITE_BITMAPSET_FIELD(rewindPlanIDs);
 	WRITE_NODE_FIELD(returningLists);
 	WRITE_NODE_FIELD(rowMarks);
+	WRITE_NODE_FIELD(relationOids);
 	WRITE_INT_FIELD(nParamExec);
 }
 
@@ -1300,6 +1301,7 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
 	WRITE_NODE_FIELD(subrtables);
 	WRITE_BITMAPSET_FIELD(rewindPlanIDs);
 	WRITE_NODE_FIELD(finalrtable);
+	WRITE_NODE_FIELD(relationOids);
 }
 
 static void
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index e36ba97f6b860fadae82642712135e3a1345c73a..c55f89da78d592f19e1524d480b5850d96f68394 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.222 2007/09/20 17:56:31 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.223 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,6 +134,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	glob->subrtables = NIL;
 	glob->rewindPlanIDs = NULL;
 	glob->finalrtable = NIL;
+	glob->relationOids = NIL;
 	glob->transientPlan = false;
 
 	/* Determine what fraction of the plan is likely to be scanned */
@@ -194,6 +195,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	result->rewindPlanIDs = glob->rewindPlanIDs;
 	result->returningLists = root->returningLists;
 	result->rowMarks = parse->rowMarks;
+	result->relationOids = glob->relationOids;
 	result->nParamExec = list_length(glob->paramlist);
 
 	return result;
@@ -1184,7 +1186,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 		List	   *rlist;
 
 		Assert(parse->resultRelation);
-		rlist = set_returning_clause_references(parse->returningList,
+		rlist = set_returning_clause_references(root->glob,
+												parse->returningList,
 												result_plan,
 												parse->resultRelation);
 		root->returningLists = list_make1(rlist);
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 055b47beec7d6791aa055749eafe65f4299ccc0b..bc8ce00d4e8ba68393b97d4b9dcbcd04de2118e7 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -2,19 +2,20 @@
  *
  * setrefs.c
  *	  Post-processing of a completed plan tree: fix references to subplan
- *	  vars, and compute regproc values for operators
+ *	  vars, compute regproc values for operators, etc
  *
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.136 2007/06/11 01:16:23 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.137 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
+#include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
@@ -42,11 +43,13 @@ typedef struct
 
 typedef struct
 {
+	PlannerGlobal *glob;
 	int			rtoffset;
 } fix_scan_expr_context;
 
 typedef struct
 {
+	PlannerGlobal *glob;
 	indexed_tlist *outer_itlist;
 	indexed_tlist *inner_itlist;
 	Index		acceptable_rel;
@@ -55,24 +58,25 @@ typedef struct
 
 typedef struct
 {
+	PlannerGlobal *glob;
 	indexed_tlist *subplan_itlist;
 	int			rtoffset;
 } fix_upper_expr_context;
 
-#define fix_scan_list(lst, rtoffset) \
-	((List *) fix_scan_expr((Node *) (lst), rtoffset))
+#define fix_scan_list(glob, lst, rtoffset) \
+	((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset))
 
 static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset);
 static Plan *set_subqueryscan_references(PlannerGlobal *glob,
 										 SubqueryScan *plan,
 										 int rtoffset);
 static bool trivial_subqueryscan(SubqueryScan *plan);
-static Node *fix_scan_expr(Node *node, int rtoffset);
+static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset);
 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context);
-static void set_join_references(Join *join, int rtoffset);
-static void set_inner_join_references(Plan *inner_plan,
+static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset);
+static void set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
 						  indexed_tlist *outer_itlist);
-static void set_upper_references(Plan *plan, int rtoffset);
+static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset);
 static void set_dummy_tlist_references(Plan *plan, int rtoffset);
 static indexed_tlist *build_tlist_index(List *tlist);
 static Var *search_indexed_tlist_for_var(Var *var,
@@ -82,13 +86,15 @@ static Var *search_indexed_tlist_for_var(Var *var,
 static Var *search_indexed_tlist_for_non_var(Node *node,
 								 indexed_tlist *itlist,
 								 Index newvarno);
-static List *fix_join_expr(List *clauses,
+static List *fix_join_expr(PlannerGlobal *glob,
+						   List *clauses,
 						   indexed_tlist *outer_itlist,
 						   indexed_tlist *inner_itlist,
 						   Index acceptable_rel, int rtoffset);
 static Node *fix_join_expr_mutator(Node *node,
 								   fix_join_expr_context *context);
-static Node *fix_upper_expr(Node *node,
+static Node *fix_upper_expr(PlannerGlobal *glob,
+							Node *node,
 							indexed_tlist *subplan_itlist,
 							int rtoffset);
 static Node *fix_upper_expr_mutator(Node *node,
@@ -120,6 +126,11 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * 4. We compute regproc OIDs for operators (ie, we look up the function
  * that implements each op).
  *
+ * 5. We create a list of OIDs of relations that the plan depends on.
+ * This will be used by plancache.c to drive invalidation of cached plans.
+ * (Someday we might want to generalize this to include other types of
+ * objects, but for now tracking relations seems to solve most problems.)
+ *
  * We also perform one final optimization step, which is to delete
  * SubqueryScan plan nodes that aren't doing anything useful (ie, have
  * no qual and a no-op targetlist).  The reason for doing this last is that
@@ -128,7 +139,7 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * wouldn't match up with the Vars in the outer plan tree.  The SubqueryScan
  * serves a necessary function as a buffer between outer query and subquery
  * variable numbering ... but after we've flattened the rangetable this is
- * no longer a problem, since there's only one rtindex namespace.
+ * no longer a problem, since then there's only one rtindex namespace.
  *
  * set_plan_references recursively traverses the whole plan tree.
  *
@@ -140,7 +151,8 @@ static bool fix_opfuncids_walker(Node *node, void *context);
  * The return value is normally the same Plan node passed in, but can be
  * different when the passed-in Plan is a SubqueryScan we decide isn't needed.
  *
- * The flattened rangetable entries are appended to glob->finalrtable.
+ * The flattened rangetable entries are appended to glob->finalrtable, and
+ * the list of relation OIDs is appended to glob->relationOids.
  *
  * Notice that we modify Plan nodes in-place, but use expression_tree_mutator
  * to process targetlist and qual expressions.  We can assume that the Plan
@@ -177,6 +189,22 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, List *rtable)
 		newrte->joinaliasvars = NIL;
 
 		glob->finalrtable = lappend(glob->finalrtable, newrte);
+
+		/*
+		 * If it's a plain relation RTE, add the table to relationOids.
+		 *
+		 * We do this even though the RTE might be unreferenced in the
+		 * plan tree; this would correspond to cases such as views that
+		 * were expanded, child tables that were eliminated by constraint
+		 * exclusion, etc.  Schema invalidation on such a rel must still
+		 * force rebuilding of the plan.
+		 *
+		 * Note we don't bother to avoid duplicate list entries.  We could,
+		 * but it would probably cost more cycles than it would save.
+		 */
+		if (newrte->rtekind == RTE_RELATION)
+			glob->relationOids = lappend_oid(glob->relationOids,
+											 newrte->relid);
 	}
 
 	/* Now fix the Plan tree */
@@ -205,9 +233,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scanrelid += rtoffset;
 				splan->plan.targetlist =
-					fix_scan_list(splan->plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->plan.targetlist, rtoffset);
 				splan->plan.qual =
-					fix_scan_list(splan->plan.qual, rtoffset);
+					fix_scan_list(glob, splan->plan.qual, rtoffset);
 			}
 			break;
 		case T_IndexScan:
@@ -216,13 +244,13 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 				splan->scan.plan.qual =
-					fix_scan_list(splan->scan.plan.qual, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
 				splan->indexqual =
-					fix_scan_list(splan->indexqual, rtoffset);
+					fix_scan_list(glob, splan->indexqual, rtoffset);
 				splan->indexqualorig =
-					fix_scan_list(splan->indexqualorig, rtoffset);
+					fix_scan_list(glob, splan->indexqualorig, rtoffset);
 			}
 			break;
 		case T_BitmapIndexScan:
@@ -234,9 +262,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 				Assert(splan->scan.plan.targetlist == NIL);
 				Assert(splan->scan.plan.qual == NIL);
 				splan->indexqual =
-					fix_scan_list(splan->indexqual, rtoffset);
+					fix_scan_list(glob, splan->indexqual, rtoffset);
 				splan->indexqualorig =
-					fix_scan_list(splan->indexqualorig, rtoffset);
+					fix_scan_list(glob, splan->indexqualorig, rtoffset);
 			}
 			break;
 		case T_BitmapHeapScan:
@@ -245,11 +273,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 				splan->scan.plan.qual =
-					fix_scan_list(splan->scan.plan.qual, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
 				splan->bitmapqualorig =
-					fix_scan_list(splan->bitmapqualorig, rtoffset);
+					fix_scan_list(glob, splan->bitmapqualorig, rtoffset);
 			}
 			break;
 		case T_TidScan:
@@ -258,11 +286,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 				splan->scan.plan.qual =
-					fix_scan_list(splan->scan.plan.qual, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
 				splan->tidquals =
-					fix_scan_list(splan->tidquals, rtoffset);
+					fix_scan_list(glob, splan->tidquals, rtoffset);
 			}
 			break;
 		case T_SubqueryScan:
@@ -276,11 +304,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 				splan->scan.plan.qual =
-					fix_scan_list(splan->scan.plan.qual, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
 				splan->funcexpr =
-					fix_scan_expr(splan->funcexpr, rtoffset);
+					fix_scan_expr(glob, splan->funcexpr, rtoffset);
 			}
 			break;
 		case T_ValuesScan:
@@ -289,18 +317,18 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 
 				splan->scan.scanrelid += rtoffset;
 				splan->scan.plan.targetlist =
-					fix_scan_list(splan->scan.plan.targetlist, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 				splan->scan.plan.qual =
-					fix_scan_list(splan->scan.plan.qual, rtoffset);
+					fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
 				splan->values_lists =
-					fix_scan_list(splan->values_lists, rtoffset);
+					fix_scan_list(glob, splan->values_lists, rtoffset);
 			}
 			break;
 
 		case T_NestLoop:
 		case T_MergeJoin:
 		case T_HashJoin:
-			set_join_references((Join *) plan, rtoffset);
+			set_join_references(glob, (Join *) plan, rtoffset);
 			break;
 
 		case T_Hash:
@@ -337,14 +365,14 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 				Assert(splan->plan.qual == NIL);
 
 				splan->limitOffset =
-					fix_scan_expr(splan->limitOffset, rtoffset);
+					fix_scan_expr(glob, splan->limitOffset, rtoffset);
 				splan->limitCount =
-					fix_scan_expr(splan->limitCount, rtoffset);
+					fix_scan_expr(glob, splan->limitCount, rtoffset);
 			}
 			break;
 		case T_Agg:
 		case T_Group:
-			set_upper_references(plan, rtoffset);
+			set_upper_references(glob, plan, rtoffset);
 			break;
 		case T_Result:
 			{
@@ -355,17 +383,17 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset)
 				 * like a scan node than an upper node.
 				 */
 				if (splan->plan.lefttree != NULL)
-					set_upper_references(plan, rtoffset);
+					set_upper_references(glob, plan, rtoffset);
 				else
 				{
 					splan->plan.targetlist =
-						fix_scan_list(splan->plan.targetlist, rtoffset);
+						fix_scan_list(glob, splan->plan.targetlist, rtoffset);
 					splan->plan.qual =
-						fix_scan_list(splan->plan.qual, rtoffset);
+						fix_scan_list(glob, splan->plan.qual, rtoffset);
 				}
 				/* resconstantqual can't contain any subplan variable refs */
 				splan->resconstantqual =
-					fix_scan_expr(splan->resconstantqual, rtoffset);
+					fix_scan_expr(glob, splan->resconstantqual, rtoffset);
 			}
 			break;
 		case T_Append:
@@ -497,9 +525,9 @@ set_subqueryscan_references(PlannerGlobal *glob,
 		 */
 		plan->scan.scanrelid += rtoffset;
 		plan->scan.plan.targetlist =
-			fix_scan_list(plan->scan.plan.targetlist, rtoffset);
+			fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset);
 		plan->scan.plan.qual =
-			fix_scan_list(plan->scan.plan.qual, rtoffset);
+			fix_scan_list(glob, plan->scan.plan.qual, rtoffset);
 
 		result = (Plan *) plan;
 	}
@@ -585,14 +613,16 @@ copyVar(Var *var)
  * fix_scan_expr
  *		Do set_plan_references processing on a scan-level expression
  *
- * This consists of incrementing all Vars' varnos by rtoffset and
- * looking up operator opcode info for OpExpr and related nodes.
+ * This consists of incrementing all Vars' varnos by rtoffset,
+ * looking up operator opcode info for OpExpr and related nodes,
+ * and adding OIDs from regclass Const nodes into glob->relationOids.
  */
 static Node *
-fix_scan_expr(Node *node, int rtoffset)
+fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset)
 {
 	fix_scan_expr_context context;
 
+	context.glob = glob;
 	context.rtoffset = rtoffset;
 	return fix_scan_expr_mutator(node, &context);
 }
@@ -639,6 +669,17 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
 		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */
 	else if (IsA(node, ScalarArrayOpExpr))
 		set_sa_opfuncid((ScalarArrayOpExpr *) node);
+	else if (IsA(node, Const))
+	{
+		Const	   *con = (Const *) node;
+
+		/* Check for regclass reference */
+		if (con->consttype == REGCLASSOID && !con->constisnull)
+			context->glob->relationOids =
+				lappend_oid(context->glob->relationOids,
+							DatumGetObjectId(con->constvalue));
+		/* Fall through to let expression_tree_mutator copy it */
+	}
 	return expression_tree_mutator(node, fix_scan_expr_mutator,
 								   (void *) context);
 }
@@ -649,14 +690,14 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context)
  *	  subplans, by setting the varnos to OUTER or INNER and setting attno
  *	  values to the result domain number of either the corresponding outer
  *	  or inner join tuple item.  Also perform opcode lookup for these
- *	  expressions.
+ *	  expressions. and add regclass OIDs to glob->relationOids.
  *
  * In the case of a nestloop with inner indexscan, we will also need to
  * apply the same transformation to any outer vars appearing in the
  * quals of the child indexscan.  set_inner_join_references does that.
  */
 static void
-set_join_references(Join *join, int rtoffset)
+set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
 {
 	Plan	   *outer_plan = join->plan.lefttree;
 	Plan	   *inner_plan = join->plan.righttree;
@@ -667,17 +708,20 @@ set_join_references(Join *join, int rtoffset)
 	inner_itlist = build_tlist_index(inner_plan->targetlist);
 
 	/* All join plans have tlist, qual, and joinqual */
-	join->plan.targetlist = fix_join_expr(join->plan.targetlist,
+	join->plan.targetlist = fix_join_expr(glob,
+										  join->plan.targetlist,
 										  outer_itlist,
 										  inner_itlist,
 										  (Index) 0,
 										  rtoffset);
-	join->plan.qual = fix_join_expr(join->plan.qual,
+	join->plan.qual = fix_join_expr(glob,
+									join->plan.qual,
 									outer_itlist,
 									inner_itlist,
 									(Index) 0,
 									rtoffset);
-	join->joinqual = fix_join_expr(join->joinqual,
+	join->joinqual = fix_join_expr(glob,
+								   join->joinqual,
 								   outer_itlist,
 								   inner_itlist,
 								   (Index) 0,
@@ -687,13 +731,14 @@ set_join_references(Join *join, int rtoffset)
 	if (IsA(join, NestLoop))
 	{
 		/* This processing is split out to handle possible recursion */
-		set_inner_join_references(inner_plan, outer_itlist);
+		set_inner_join_references(glob, inner_plan, outer_itlist);
 	}
 	else if (IsA(join, MergeJoin))
 	{
 		MergeJoin  *mj = (MergeJoin *) join;
 
-		mj->mergeclauses = fix_join_expr(mj->mergeclauses,
+		mj->mergeclauses = fix_join_expr(glob,
+										 mj->mergeclauses,
 										 outer_itlist,
 										 inner_itlist,
 										 (Index) 0,
@@ -703,7 +748,8 @@ set_join_references(Join *join, int rtoffset)
 	{
 		HashJoin   *hj = (HashJoin *) join;
 
-		hj->hashclauses = fix_join_expr(hj->hashclauses,
+		hj->hashclauses = fix_join_expr(glob,
+										hj->hashclauses,
 										outer_itlist,
 										inner_itlist,
 										(Index) 0,
@@ -728,7 +774,8 @@ set_join_references(Join *join, int rtoffset)
  * recursion reaches the inner indexscan, and so we'd have done it twice.
  */
 static void
-set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
+set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
+						  indexed_tlist *outer_itlist)
 {
 	if (IsA(inner_plan, IndexScan))
 	{
@@ -747,12 +794,14 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 			Index		innerrel = innerscan->scan.scanrelid;
 
 			/* only refs to outer vars get changed in the inner qual */
-			innerscan->indexqualorig = fix_join_expr(indexqualorig,
+			innerscan->indexqualorig = fix_join_expr(glob,
+													 indexqualorig,
 													 outer_itlist,
 													 NULL,
 													 innerrel,
 													 0);
-			innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+			innerscan->indexqual = fix_join_expr(glob,
+												 innerscan->indexqual,
 												 outer_itlist,
 												 NULL,
 												 innerrel,
@@ -764,7 +813,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 			 * may get rechecked as qpquals).
 			 */
 			if (NumRelids((Node *) inner_plan->qual) > 1)
-				inner_plan->qual = fix_join_expr(inner_plan->qual,
+				inner_plan->qual = fix_join_expr(glob,
+												 inner_plan->qual,
 												 outer_itlist,
 												 NULL,
 												 innerrel,
@@ -785,12 +835,14 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 			Index		innerrel = innerscan->scan.scanrelid;
 
 			/* only refs to outer vars get changed in the inner qual */
-			innerscan->indexqualorig = fix_join_expr(indexqualorig,
+			innerscan->indexqualorig = fix_join_expr(glob,
+													 indexqualorig,
 													 outer_itlist,
 													 NULL,
 													 innerrel,
 													 0);
-			innerscan->indexqual = fix_join_expr(innerscan->indexqual,
+			innerscan->indexqual = fix_join_expr(glob,
+												 innerscan->indexqual,
 												 outer_itlist,
 												 NULL,
 												 innerrel,
@@ -814,7 +866,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
 		/* only refs to outer vars get changed in the inner qual */
 		if (NumRelids((Node *) bitmapqualorig) > 1)
-			innerscan->bitmapqualorig = fix_join_expr(bitmapqualorig,
+			innerscan->bitmapqualorig = fix_join_expr(glob,
+													  bitmapqualorig,
 													  outer_itlist,
 													  NULL,
 													  innerrel,
@@ -826,14 +879,15 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 		 * get rechecked as qpquals).
 		 */
 		if (NumRelids((Node *) inner_plan->qual) > 1)
-			inner_plan->qual = fix_join_expr(inner_plan->qual,
+			inner_plan->qual = fix_join_expr(glob,
+											 inner_plan->qual,
 											 outer_itlist,
 											 NULL,
 											 innerrel,
 											 0);
 
 		/* Now recurse */
-		set_inner_join_references(inner_plan->lefttree, outer_itlist);
+		set_inner_join_references(glob, inner_plan->lefttree, outer_itlist);
 	}
 	else if (IsA(inner_plan, BitmapAnd))
 	{
@@ -843,7 +897,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
 		foreach(l, innerscan->bitmapplans)
 		{
-			set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
 		}
 	}
 	else if (IsA(inner_plan, BitmapOr))
@@ -854,7 +908,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
 		foreach(l, innerscan->bitmapplans)
 		{
-			set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
 		}
 	}
 	else if (IsA(inner_plan, TidScan))
@@ -862,7 +916,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 		TidScan    *innerscan = (TidScan *) inner_plan;
 		Index		innerrel = innerscan->scan.scanrelid;
 
-		innerscan->tidquals = fix_join_expr(innerscan->tidquals,
+		innerscan->tidquals = fix_join_expr(glob,
+											innerscan->tidquals,
 											outer_itlist,
 											NULL,
 											innerrel,
@@ -879,7 +934,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 
 		foreach(l, appendplan->appendplans)
 		{
-			set_inner_join_references((Plan *) lfirst(l), outer_itlist);
+			set_inner_join_references(glob, (Plan *) lfirst(l), outer_itlist);
 		}
 	}
 	else if (IsA(inner_plan, Result))
@@ -888,7 +943,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
 		Result	   *result = (Result *) inner_plan;
 
 		if (result->plan.lefttree)
-			set_inner_join_references(result->plan.lefttree, outer_itlist);
+			set_inner_join_references(glob, result->plan.lefttree, outer_itlist);
 	}
 }
 
@@ -896,7 +951,8 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
  * set_upper_references
  *	  Update the targetlist and quals of an upper-level plan node
  *	  to refer to the tuples returned by its lefttree subplan.
- *	  Also perform opcode lookup for these expressions.
+ *	  Also perform opcode lookup for these expressions, and
+ *	  add regclass OIDs to glob->relationOids.
  *
  * This is used for single-input plan types like Agg, Group, Result.
  *
@@ -910,7 +966,7 @@ set_inner_join_references(Plan *inner_plan, indexed_tlist *outer_itlist)
  * the expression.
  */
 static void
-set_upper_references(Plan *plan, int rtoffset)
+set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset)
 {
 	Plan	   *subplan = plan->lefttree;
 	indexed_tlist *subplan_itlist;
@@ -925,7 +981,8 @@ set_upper_references(Plan *plan, int rtoffset)
 		TargetEntry *tle = (TargetEntry *) lfirst(l);
 		Node	   *newexpr;
 
-		newexpr = fix_upper_expr((Node *) tle->expr,
+		newexpr = fix_upper_expr(glob,
+								 (Node *) tle->expr,
 								 subplan_itlist,
 								 rtoffset);
 		tle = flatCopyTargetEntry(tle);
@@ -935,7 +992,8 @@ set_upper_references(Plan *plan, int rtoffset)
 	plan->targetlist = output_targetlist;
 
 	plan->qual = (List *)
-		fix_upper_expr((Node *) plan->qual,
+		fix_upper_expr(glob,
+					   (Node *) plan->qual,
 					   subplan_itlist,
 					   rtoffset);
 
@@ -1166,7 +1224,8 @@ search_indexed_tlist_for_non_var(Node *node,
  *	   Create a new set of targetlist entries or join qual clauses by
  *	   changing the varno/varattno values of variables in the clauses
  *	   to reference target list values from the outer and inner join
- *	   relation target lists.  Also perform opcode lookup.
+ *	   relation target lists.  Also perform opcode lookup and add
+ *	   regclass OIDs to glob->relationOids.
  *
  * This is used in two different scenarios: a normal join clause, where
  * all the Vars in the clause *must* be replaced by OUTER or INNER references;
@@ -1192,7 +1251,8 @@ search_indexed_tlist_for_non_var(Node *node,
  * not modified.
  */
 static List *
-fix_join_expr(List *clauses,
+fix_join_expr(PlannerGlobal *glob,
+			  List *clauses,
 			  indexed_tlist *outer_itlist,
 			  indexed_tlist *inner_itlist,
 			  Index acceptable_rel,
@@ -1200,6 +1260,7 @@ fix_join_expr(List *clauses,
 {
 	fix_join_expr_context context;
 
+	context.glob = glob;
 	context.outer_itlist = outer_itlist;
 	context.inner_itlist = inner_itlist;
 	context.acceptable_rel = acceptable_rel;
@@ -1276,6 +1337,17 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */
 	else if (IsA(node, ScalarArrayOpExpr))
 		set_sa_opfuncid((ScalarArrayOpExpr *) node);
+	else if (IsA(node, Const))
+	{
+		Const	   *con = (Const *) node;
+
+		/* Check for regclass reference */
+		if (con->consttype == REGCLASSOID && !con->constisnull)
+			context->glob->relationOids =
+				lappend_oid(context->glob->relationOids,
+							DatumGetObjectId(con->constvalue));
+		/* Fall through to let expression_tree_mutator copy it */
+	}
 	return expression_tree_mutator(node,
 								   fix_join_expr_mutator,
 								   (void *) context);
@@ -1284,7 +1356,8 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
 /*
  * fix_upper_expr
  *		Modifies an expression tree so that all Var nodes reference outputs
- *		of a subplan.  Also performs opcode lookup.
+ *		of a subplan.  Also performs opcode lookup, and adds regclass OIDs to
+ *		glob->relationOids.
  *
  * This is used to fix up target and qual expressions of non-join upper-level
  * plan nodes.
@@ -1308,12 +1381,14 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context)
  * The original tree is not modified.
  */
 static Node *
-fix_upper_expr(Node *node,
+fix_upper_expr(PlannerGlobal *glob,
+			   Node *node,
 			   indexed_tlist *subplan_itlist,
 			   int rtoffset)
 {
 	fix_upper_expr_context context;
 
+	context.glob = glob;
 	context.subplan_itlist = subplan_itlist;
 	context.rtoffset = rtoffset;
 	return fix_upper_expr_mutator(node, &context);
@@ -1359,6 +1434,17 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
 		set_opfuncid((OpExpr *) node);	/* rely on struct equivalence */
 	else if (IsA(node, ScalarArrayOpExpr))
 		set_sa_opfuncid((ScalarArrayOpExpr *) node);
+	else if (IsA(node, Const))
+	{
+		Const	   *con = (Const *) node;
+
+		/* Check for regclass reference */
+		if (con->consttype == REGCLASSOID && !con->constisnull)
+			context->glob->relationOids =
+				lappend_oid(context->glob->relationOids,
+							DatumGetObjectId(con->constvalue));
+		/* Fall through to let expression_tree_mutator copy it */
+	}
 	return expression_tree_mutator(node,
 								   fix_upper_expr_mutator,
 								   (void *) context);
@@ -1376,7 +1462,8 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * adjusted RETURNING list, result-table Vars will still have their
  * original varno, but Vars for other rels will have varno OUTER.
  *
- * We also must perform opcode lookup.
+ * We also must perform opcode lookup and add regclass OIDs to
+ * glob->relationOids.
  *
  * 'rlist': the RETURNING targetlist to be fixed
  * 'topplan': the top Plan node for the query (not yet passed through
@@ -1387,7 +1474,8 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context)
  * they are not coming from a subplan.
  */
 List *
-set_returning_clause_references(List *rlist,
+set_returning_clause_references(PlannerGlobal *glob,
+								List *rlist,
 								Plan *topplan,
 								Index resultRelation)
 {
@@ -1402,7 +1490,8 @@ set_returning_clause_references(List *rlist,
 	 */
 	itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation);
 
-	rlist = fix_join_expr(rlist,
+	rlist = fix_join_expr(glob,
+						  rlist,
 						  itlist,
 						  NULL,
 						  resultRelation,
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 43297281f5ffb0504ad185eae0c91357d4f80846..2f52ed7a8cc39bf88fed62fb0c5ff0fad83cd695 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -33,7 +33,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.11 2007/09/20 17:56:31 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.12 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -921,26 +921,17 @@ PlanCacheCallback(Datum arg, Oid relid)
 			foreach(lc2, plan->stmt_list)
 			{
 				PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
-				ListCell   *lc3;
 
 				Assert(!IsA(plannedstmt, Query));
 				if (!IsA(plannedstmt, PlannedStmt))
 					continue;			/* Ignore utility statements */
-				foreach(lc3, plannedstmt->rtable)
+				if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
+					list_member_oid(plannedstmt->relationOids, relid))
 				{
-					RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc3);
-
-					if (rte->rtekind != RTE_RELATION)
-						continue;
-					if (relid == rte->relid || relid == InvalidOid)
-					{
-						/* Invalidate the plan! */
-						plan->dead = true;
-						break;		/* out of rangetable scan */
-					}
-				}
-				if (plan->dead)
+					/* Invalidate the plan! */
+					plan->dead = true;
 					break;			/* out of stmt_list scan */
+				}
 			}
 		}
 		else
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 992b47f58d80fc8bc649ae6419cf349bdb0ab3d7..9b6c637284677daf9c09a93d23cf17329195f3e2 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.95 2007/09/20 17:56:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.96 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,6 +70,8 @@ typedef struct PlannedStmt
 
 	List	   *rowMarks;		/* a list of RowMarkClause's */
 
+	List	   *relationOids;	/* OIDs of relations the plan depends on */
+
 	int			nParamExec;		/* number of PARAM_EXEC Params used */
 } PlannedStmt;
 
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 32c699b6de6fcaddb0ad7816cf2c166107cbb0b0..389035202223be64409f62cc5384ab40f661ebe5 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.146 2007/09/20 17:56:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.147 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,6 +72,8 @@ typedef struct PlannerGlobal
 
 	List	   *finalrtable;	/* "flat" rangetable for executor */
 
+	List	   *relationOids;	/* OIDs of relations the plan depends on */
+
 	bool		transientPlan;	/* redo plan when TransactionXmin changes? */
 } PlannerGlobal;
 
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 4673d53098fbe2af826787a280aa560993260241..43769c71e11e725a801b8f4d43a8432f1082ead2 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.102 2007/10/04 20:44:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.103 2007/10/11 18:05:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,7 +96,8 @@ extern RestrictInfo *build_implied_join_equality(Oid opno,
 extern Plan *set_plan_references(PlannerGlobal *glob,
 								 Plan *plan,
 								 List *rtable);
-extern List *set_returning_clause_references(List *rlist,
+extern List *set_returning_clause_references(PlannerGlobal *glob,
+								List *rlist,
 								Plan *topplan,
 								Index resultRelation);
 extern void fix_opfuncids(Node *node);
diff --git a/src/test/regress/expected/plancache.out b/src/test/regress/expected/plancache.out
index a96ba2a5da017c1626d3717e7dbb9600e52e5ca7..d7d7be92529aee67b0ab7b08e4de39e5157749b2 100644
--- a/src/test/regress/expected/plancache.out
+++ b/src/test/regress/expected/plancache.out
@@ -202,3 +202,20 @@ drop schema s1 cascade;
 NOTICE:  drop cascades to table s1.abc
 drop schema s2 cascade;
 NOTICE:  drop cascades to table abc
+-- Check that invalidation deals with regclass constants
+create temp sequence seq;
+prepare p2 as select nextval('seq');
+execute p2;
+ nextval 
+---------
+       1
+(1 row)
+
+drop sequence seq;
+create temp sequence seq;
+execute p2;
+ nextval 
+---------
+       1
+(1 row)
+
diff --git a/src/test/regress/sql/plancache.sql b/src/test/regress/sql/plancache.sql
index e285c071f6edca537fed03b07834cb9dda909c1c..fc57279d985c702476509b7f2bda227ac2e37dd2 100644
--- a/src/test/regress/sql/plancache.sql
+++ b/src/test/regress/sql/plancache.sql
@@ -123,3 +123,17 @@ execute p1;
 
 drop schema s1 cascade;
 drop schema s2 cascade;
+
+-- Check that invalidation deals with regclass constants
+
+create temp sequence seq;
+
+prepare p2 as select nextval('seq');
+
+execute p2;
+
+drop sequence seq;
+
+create temp sequence seq;
+
+execute p2;