/*
     * Save the final parameter types (or other parameter specification data)
-    * into the source_context, as well as our other parameters.  Also save
-    * the result tuple descriptor.
+    * into the source_context, as well as our other parameters.
     */
    MemoryContextSwitchTo(source_context);
 
    plansource->parserSetupArg = parserSetupArg;
    plansource->cursor_options = cursor_options;
    plansource->fixed_result = fixed_result;
-   plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
 
+   /*
+    * Also save the result tuple descriptor.  PlanCacheComputeResultDesc may
+    * leak some cruft; normally we just accept that to save a copy step, but
+    * in USE_VALGRIND mode be tidy by running it in the caller's context.
+    */
+#ifdef USE_VALGRIND
+   MemoryContextSwitchTo(oldcxt);
+   plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
+   if (plansource->resultDesc)
+   {
+       MemoryContextSwitchTo(source_context);
+       plansource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
+       MemoryContextSwitchTo(oldcxt);
+   }
+#else
+   plansource->resultDesc = PlanCacheComputeResultDesc(querytree_list);
    MemoryContextSwitchTo(oldcxt);
+#endif
 
    plansource->is_complete = true;
    plansource->is_valid = true;