diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 81b9c69e9a2b8774cb2077ec1f7a66b984ff71e5..6bbb5b139b631a23f60c4c5f580412ded436b016 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.45 2008/01/01 19:45:49 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.46 2008/02/29 02:49:39 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,7 +77,17 @@ FunctionNext(FunctionScanState *node)
 		 * do it always.
 		 */
 		if (funcTupdesc)
+		{
 			tupledesc_match(node->tupdesc, funcTupdesc);
+
+			/*
+			 * If it is a dynamically-allocated TupleDesc, free it: it is
+			 * typically allocated in the EState's per-query context, so we
+			 * must avoid leaking it on rescan.
+			 */
+			if (funcTupdesc->tdrefcount == -1)
+				FreeTupleDesc(funcTupdesc);
+		}
 	}
 
 	/*
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 8c6609de62c29ec7b3b401e45570eba42575b3fa..4bb230a3f364892af44fb4056190a48edcc30caf 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -7,7 +7,7 @@
  * Copyright (c) 2002-2008, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.37 2008/01/01 19:45:53 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.38 2008/02/29 02:49:39 neilc Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
+#include "utils/memutils.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -63,13 +64,23 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
 		/*
 		 * First call
 		 */
-		ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+		ReturnSetInfo  *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
+		MemoryContext	multi_call_ctx;
+
+		/*
+		 * Create a suitably long-lived context to hold cross-call data
+		 */
+		multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
+											   "SRF multi-call context",
+											   ALLOCSET_SMALL_MINSIZE,
+											   ALLOCSET_SMALL_INITSIZE,
+											   ALLOCSET_SMALL_MAXSIZE);
 
 		/*
 		 * Allocate suitably long-lived space and zero it
 		 */
 		retval = (FuncCallContext *)
-			MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
+			MemoryContextAllocZero(multi_call_ctx,
 								   sizeof(FuncCallContext));
 
 		/*
@@ -81,7 +92,7 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
 		retval->user_fctx = NULL;
 		retval->attinmeta = NULL;
 		retval->tuple_desc = NULL;
-		retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
+		retval->multi_call_memory_ctx = multi_call_ctx;
 
 		/*
 		 * save the pointer for cross-call use
@@ -168,13 +179,11 @@ shutdown_MultiFuncCall(Datum arg)
 	flinfo->fn_extra = NULL;
 
 	/*
-	 * Caller is responsible to free up memory for individual struct elements
-	 * other than att_in_funcinfo and elements.
+	 * Delete context that holds all multi-call data, including the
+	 * FuncCallContext itself
 	 */
-	if (funcctx->attinmeta != NULL)
-		pfree(funcctx->attinmeta);
-
-	pfree(funcctx);
+	MemoryContextSwitchTo(flinfo->fn_mcxt);
+	MemoryContextDelete(funcctx->multi_call_memory_ctx);
 }