From 21fb95da46bce8de3e149707c680d489b8a5ffb0 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 26 Sep 2011 12:44:17 -0400
Subject: [PATCH] Use a fresh copy of query_list when making a second plan in
 GetCachedPlan.

The code path that tried a generic plan, didn't like it, and then made a
custom plan was mistakenly passing the same copy of the query_list to the
planner both times.  This doesn't work too well for nontrivial queries,
since the planner tends to scribble on its input.  Diagnosis and fix by
Yamamoto Takashi.
---
 src/backend/utils/cache/plancache.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index cfeb8245b8c..56dace0e89c 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -697,7 +697,8 @@ CheckCachedPlan(CachedPlanSource *plansource)
 /*
  * BuildCachedPlan: construct a new CachedPlan from a CachedPlanSource.
  *
- * qlist should be the result value from a previous RevalidateCachedQuery.
+ * qlist should be the result value from a previous RevalidateCachedQuery,
+ * or it can be set to NIL if we need to re-copy the plansource's query_list.
  *
  * To build a generic, parameter-value-independent plan, pass NULL for
  * boundParams.  To build a custom plan, pass the actual parameter values via
@@ -980,6 +981,13 @@ GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams,
 			 * plan.
 			 */
 			customplan = choose_custom_plan(plansource, boundParams);
+
+			/*
+			 * If we choose to plan again, we need to re-copy the query_list,
+			 * since the planner probably scribbled on it.  We can force
+			 * BuildCachedPlan to do that by passing NIL.
+			 */
+			qlist = NIL;
 		}
 	}
 
-- 
GitLab