diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 88a5c28d19b4e413caacc760a621bf597125d085..ffa117b66cd2cf2a9fb787392711ef1b3700e010 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -35,7 +35,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.32 2010/01/02 16:57:55 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.33 2010/01/13 16:56:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1068,14 +1068,57 @@ PlanCacheSysCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
 void
 ResetPlanCache(void)
 {
-	ListCell   *lc;
+	ListCell   *lc1;
 
-	foreach(lc, cached_plans_list)
+	foreach(lc1, cached_plans_list)
 	{
-		CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
+		CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
 		CachedPlan *plan = plansource->plan;
+		ListCell   *lc2;
 
-		if (plan)
-			plan->dead = true;
+		/* No work if it's already invalidated */
+		if (!plan || plan->dead)
+			continue;
+
+		/*
+		 * We *must not* mark transaction control statements as dead,
+		 * particularly not ROLLBACK, because they may need to be executed in
+		 * aborted transactions when we can't revalidate them (cf bug #5269).
+		 * In general there is no point in invalidating utility statements
+		 * since they have no plans anyway.  So mark it dead only if it
+		 * contains at least one non-utility statement.
+		 */
+		if (plan->fully_planned)
+		{
+			/* Search statement list for non-utility statements */
+			foreach(lc2, plan->stmt_list)
+			{
+				PlannedStmt *plannedstmt = (PlannedStmt *) lfirst(lc2);
+
+				Assert(!IsA(plannedstmt, Query));
+				if (IsA(plannedstmt, PlannedStmt))
+				{
+					/* non-utility statement, so invalidate */
+					plan->dead = true;
+					break;		/* out of stmt_list scan */
+				}
+			}
+		}
+		else
+		{
+			/* Search Query list for non-utility statements */
+			foreach(lc2, plan->stmt_list)
+			{
+				Query	   *query = (Query *) lfirst(lc2);
+
+				Assert(IsA(query, Query));
+				if (query->commandType != CMD_UTILITY)
+				{
+					/* non-utility statement, so invalidate */
+					plan->dead = true;
+					break;		/* out of stmt_list scan */
+				}
+			}
+		}
 	}
 }