diff --git a/contrib/pgstattuple/README.pgstattuple b/contrib/pgstattuple/README.pgstattuple
index 804c37c6a91a367bc658688027aa15e430f8c669..42a7fc2165dddcb6c81d9c9909d78639cf900333 100644
--- a/contrib/pgstattuple/README.pgstattuple
+++ b/contrib/pgstattuple/README.pgstattuple
@@ -1,4 +1,4 @@
-pgstattuple README			2002/08/22 Tatsuo Ishii
+pgstattuple README			2002/08/29 Tatsuo Ishii
 
 1. What is pgstattuple?
 
@@ -40,15 +40,15 @@ free_percent		-- free space in %
 
 3. Using pgstattuple
 
-   pgstattuple may be called as a SRF (set returning function) and is
+   pgstattuple may be called as a table function and is
    defined as follows:
 
-   CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS SETOF pgstattuple_view
+   CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type
      AS 'MODULE_PATHNAME', 'pgstattuple'
      LANGUAGE 'c' WITH (isstrict);
 
-   The argument is the table name.  Note that pgstattuple never
-   returns more than 1 tuple.
+   The argument is the table name.  Note that pgstattuple only returns
+   one row.
 
 4. Notes
 
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index a357f6f412ad26f598a52b88232fb87b14471a7b..4fbc60bcf2aa4a0bc1a03e89ac63b56150a9efc6 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -1,5 +1,5 @@
 /*
- * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.7 2002/08/23 08:19:49 ishii Exp $
+ * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.8 2002/08/29 17:14:31 tgl Exp $
  *
  * Copyright (c) 2001,2002  Tatsuo Ishii
  *
@@ -25,10 +25,10 @@
 #include "postgres.h"
 
 #include "fmgr.h"
+#include "funcapi.h"
 #include "access/heapam.h"
 #include "access/transam.h"
 #include "catalog/namespace.h"
-#include "funcapi.h"
 #include "utils/builtins.h"
 
 
@@ -41,19 +41,19 @@ extern Datum pgstattuple(PG_FUNCTION_ARGS);
  * returns live/dead tuples info
  *
  * C FUNCTION definition
- * pgstattuple(TEXT) returns setof pgstattuple_view
- * see pgstattuple.sql for pgstattuple_view
+ * pgstattuple(text) returns pgstattuple_type
+ * see pgstattuple.sql for pgstattuple_type
  * ----------
  */
 
-#define DUMMY_TUPLE "pgstattuple_view"
+#define DUMMY_TUPLE "pgstattuple_type"
 #define NCOLUMNS 9
 #define NCHARS 32
 
 Datum
 pgstattuple(PG_FUNCTION_ARGS)
 {
-	text	   *relname;
+	text	   *relname = PG_GETARG_TEXT_P(0);
 	RangeVar   *relrv;
 	Relation	rel;
 	HeapScanDesc scan;
@@ -71,62 +71,30 @@ pgstattuple(PG_FUNCTION_ARGS)
 	double		dead_tuple_percent;
 	uint64		free_space = 0; /* free/reusable space in bytes */
 	double		free_percent;	/* free/reusable space in % */
-
-	FuncCallContext	   *funcctx;
-	int					call_cntr;
-	int					max_calls;
 	TupleDesc			tupdesc;
 	TupleTableSlot	   *slot;
 	AttInMetadata	   *attinmeta;
+	char			  **values;
+	int					i;
+	Datum				result;
 
-	char **values;
-	int i;
-	Datum		result;
-
-	/* stuff done only on the first call of the function */
-	if(SRF_IS_FIRSTCALL())
-	{
-		/* create a function context for cross-call persistence */
-		funcctx = SRF_FIRSTCALL_INIT();
-    
-		/* total number of tuples to be returned */
-		funcctx->max_calls = 1;
-    
-		/*
-		 * Build a tuple description for a pgstattupe_view tuple
-		 */
-		tupdesc = RelationNameGetTupleDesc(DUMMY_TUPLE);
-    
-		/* allocate a slot for a tuple with this tupdesc */
-		slot = TupleDescGetSlot(tupdesc);
-    
-		/* assign slot to function context */
-		funcctx->slot = slot;
-    
-		/*
-		 * Generate attribute metadata needed later to produce tuples from raw
-		 * C strings
-		 */
-		attinmeta = TupleDescGetAttInMetadata(tupdesc);
-		funcctx->attinmeta = attinmeta;
-	}
+	/*
+	 * Build a tuple description for a pgstattupe_type tuple
+	 */
+	tupdesc = RelationNameGetTupleDesc(DUMMY_TUPLE);
 
-	/* stuff done on every call of the function */
-	funcctx = SRF_PERCALL_SETUP();
-	call_cntr = funcctx->call_cntr;
-	max_calls = funcctx->max_calls;
-	slot = funcctx->slot;
-	attinmeta = funcctx->attinmeta;
+	/* allocate a slot for a tuple with this tupdesc */
+	slot = TupleDescGetSlot(tupdesc);
 
-	/* Are we done? */
-	if (call_cntr >= max_calls)
-	{
-		SRF_RETURN_DONE(funcctx);
-	}
+	/*
+	 * Generate attribute metadata needed later to produce tuples from raw
+	 * C strings
+	 */
+	attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
 	/* open relation */
-	relname = PG_GETARG_TEXT_P(0);
-	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,"pgstattuple"));
+	relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
+															 "pgstattuple"));
 	rel = heap_openrv(relrv, AccessShareLock);
 
 	nblocks = RelationGetNumberOfBlocks(rel);
@@ -223,5 +191,5 @@ pgstattuple(PG_FUNCTION_ARGS)
 	}
 	pfree(values);
     
-	SRF_RETURN_NEXT(funcctx, result);
+	PG_RETURN_DATUM(result);
 }
diff --git a/contrib/pgstattuple/pgstattuple.sql.in b/contrib/pgstattuple/pgstattuple.sql.in
index 7c661a8ee3c21d5b3bfef624a137d477f9f21e46..d3370fb830cda48588ef3ef7d97004e92a91bb2c 100644
--- a/contrib/pgstattuple/pgstattuple.sql.in
+++ b/contrib/pgstattuple/pgstattuple.sql.in
@@ -1,16 +1,16 @@
-DROP VIEW pgstattuple_view CASCADE;
-CREATE VIEW pgstattuple_view AS
-  SELECT
-    0::BIGINT AS table_len,		-- physical table length in bytes
-    0::BIGINT AS tuple_count,		-- number of live tuples
-    0::BIGINT AS tuple_len,		-- total tuples length in bytes
-    0.0::FLOAT AS tuple_percent,	-- live tuples in %
-    0::BIGINT AS dead_tuple_count,	-- number of dead tuples
-    0::BIGINT AS dead_tuple_len,	-- total dead tuples length in bytes
-    0.0::FLOAT AS dead_tuple_percent,	-- dead tuples in %
-    0::BIGINT AS free_space,		-- free space in bytes
-    0.0::FLOAT AS free_percent;		-- free space in %
+DROP TYPE pgstattuple_type CASCADE;
+CREATE TYPE pgstattuple_type AS (
+    table_len BIGINT,		-- physical table length in bytes
+    tuple_count BIGINT,		-- number of live tuples
+    tuple_len BIGINT,		-- total tuples length in bytes
+    tuple_percent FLOAT,	-- live tuples in %
+    dead_tuple_count BIGINT,	-- number of dead tuples
+    dead_tuple_len BIGINT,	-- total dead tuples length in bytes
+    dead_tuple_percent FLOAT,	-- dead tuples in %
+    free_space BIGINT,		-- free space in bytes
+    free_percent FLOAT		-- free space in %
+);
 
-CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS SETOF pgstattuple_view
+CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type
   AS 'MODULE_PATHNAME', 'pgstattuple'
   LANGUAGE 'c' WITH (isstrict);
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index d05fc1a76b66c04444218e3fb8689b6b9ccb038c..37a6e723a65862228717d1b62e3acfde5664d665 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -87,6 +87,7 @@ normal_rand(PG_FUNCTION_ARGS)
 	float8				stddev;
 	float8				carry_val;
 	bool				use_carry;
+	MemoryContext		oldcontext;
 
 	/* stuff done only on the first call of the function */
  	if(SRF_IS_FIRSTCALL())
@@ -94,6 +95,9 @@ normal_rand(PG_FUNCTION_ARGS)
 		/* create a function context for cross-call persistence */
  		funcctx = SRF_FIRSTCALL_INIT();
 
+		/* switch to memory context appropriate for multiple function calls */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
 		/* total number of tuples to be returned */
 		funcctx->max_calls = PG_GETARG_UINT32(0);
 
@@ -119,6 +123,8 @@ normal_rand(PG_FUNCTION_ARGS)
 		 * purpose it doesn't matter, just cast it as an unsigned value
 		 */
 		srandom(PG_GETARG_UINT32(3));
+
+		MemoryContextSwitchTo(oldcontext);
     }
 
 	/* stuff done on every call of the function */
@@ -260,10 +266,11 @@ crosstab(PG_FUNCTION_ARGS)
 	AttInMetadata	   *attinmeta;
 	SPITupleTable	   *spi_tuptable = NULL;
 	TupleDesc			spi_tupdesc;
-	char			   *lastrowid;
+	char			   *lastrowid = NULL;
 	crosstab_fctx	   *fctx;
 	int					i;
 	int					num_categories;
+	MemoryContext		oldcontext;
 
 	/* stuff done only on the first call of the function */
  	if(SRF_IS_FIRSTCALL())
@@ -275,13 +282,12 @@ crosstab(PG_FUNCTION_ARGS)
 		TupleDesc		tupdesc = NULL;
 		int				ret;
 		int				proc;
-		MemoryContext	oldcontext;
 
 		/* create a function context for cross-call persistence */
  		funcctx = SRF_FIRSTCALL_INIT();
 
-		/* SPI switches context on us, so save it first */
-		oldcontext = CurrentMemoryContext;
+		/* switch to memory context appropriate for multiple function calls */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
 		/* Connect to SPI manager */
 		if ((ret = SPI_connect()) < 0)
@@ -317,8 +323,8 @@ crosstab(PG_FUNCTION_ARGS)
 	 		SRF_RETURN_DONE(funcctx);
 		}
 
-		/* back to the original memory context */
-		MemoryContextSwitchTo(oldcontext);
+		/* SPI switches context on us, so reset it */
+		MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
 		/* get the typeid that represents our return type */
 		functypeid = get_func_rettype(funcid);
@@ -381,6 +387,8 @@ crosstab(PG_FUNCTION_ARGS)
 
 		/* total number of tuples to be returned */
 		funcctx->max_calls = proc;
+
+		MemoryContextSwitchTo(oldcontext);
     }
 
 	/* stuff done on every call of the function */
@@ -432,7 +440,7 @@ crosstab(PG_FUNCTION_ARGS)
 			for (i = 0; i < num_categories; i++)
 			{
 				HeapTuple	spi_tuple;
-				char	   *rowid;
+				char	   *rowid = NULL;
 
 				/* see if we've gone too far already */
 				if (call_cntr >= max_calls)
@@ -496,7 +504,13 @@ crosstab(PG_FUNCTION_ARGS)
 			xpfree(fctx->lastrowid);
 
 			if (values[0] != NULL)
+			{
+				/* switch to memory context appropriate for multiple function calls */
+				oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
 				lastrowid = fctx->lastrowid = pstrdup(values[0]);
+				MemoryContextSwitchTo(oldcontext);
+			}
 
 			if (!allnulls)
 			{
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index b3f653a28a12fc59a1770e23875188a95068c514..fad7ad888d8931c2e440cf3cb2ac7bfc565783e1 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.57 2002/08/29 00:17:02 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.58 2002/08/29 17:14:32 tgl Exp $
 -->
 
  <chapter id="xfunc">
@@ -1670,13 +1670,14 @@ typedef struct
 	AttInMetadata	   *attinmeta;
 
 	/*
-	 * memory context used to initialize structure
+	 * memory context used for structures which must live for multiple calls
 	 *
-	 * fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
-	 * SRF_RETURN_DONE() for cleanup. It is primarily for internal use
-	 * by the API.
+	 * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
+	 * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
+	 * context for any memory that is to be re-used across multiple calls
+	 * of the SRF.
 	 */
-	MemoryContext	fmctx;
+	MemoryContext	multi_call_memory_ctx;
 
 }	FuncCallContext;
 </programlisting>
@@ -1714,27 +1715,43 @@ SRF_RETURN_DONE(funcctx)
      to clean up and end the SRF.
     </para>
 
+    <para>
+     The palloc memory context that is current when the SRF is called is
+     a transient context that will be cleared between calls.  This means
+     that you do not need to be careful about pfree'ing everything
+     you palloc; it will go away anyway.  However, if you want to allocate
+     any data structures to live across calls, you need to put them somewhere
+     else.  The memory context referenced by
+     <structfield>multi_call_memory_ctx</> is a suitable location for any
+     data that needs to survive until the SRF is finished running.  In most
+     cases, this means that you should switch into
+     <structfield>multi_call_memory_ctx</> while doing the first-call setup.
+    </para>
+
     <para>
      A complete pseudo-code example looks like the following:
 <programlisting>
 Datum
 my_Set_Returning_Function(PG_FUNCTION_ARGS)
 {
-    FuncCallContext     *funcctx;
-    Datum                result;
+    FuncCallContext  *funcctx;
+    Datum             result;
+    MemoryContext     oldcontext;
     [user defined declarations]
 
     if (SRF_IS_FIRSTCALL())
     {
+        funcctx = SRF_FIRSTCALL_INIT();
+        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
         /* one-time setup code appears here: */
         [user defined code]
-        funcctx = SRF_FIRSTCALL_INIT();
         [if returning composite]
             [build TupleDesc, and perhaps AttInMetadata]
             [obtain slot]
             funcctx-&gt;slot = slot;
         [endif returning composite]
         [user defined code]
+        MemoryContextSwitchTo(oldcontext);
     }
 
     /* each-time setup code appears here: */
@@ -1777,8 +1794,13 @@ testpassbyval(PG_FUNCTION_ARGS)
      /* stuff done only on the first call of the function */
      if (SRF_IS_FIRSTCALL())
      {
+        MemoryContext	oldcontext;
+
         /* create a function context for cross-call persistence */
-         funcctx = SRF_FIRSTCALL_INIT();
+        funcctx = SRF_FIRSTCALL_INIT();
+
+        /* switch to memory context appropriate for multiple function calls */
+        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 
         /* total number of tuples to be returned */
         funcctx-&gt;max_calls = PG_GETARG_UINT32(0);
@@ -1800,6 +1822,8 @@ testpassbyval(PG_FUNCTION_ARGS)
          */
         attinmeta = TupleDescGetAttInMetadata(tupdesc);
         funcctx-&gt;attinmeta = attinmeta;
+
+        MemoryContextSwitchTo(oldcontext);
     }
 
     /* stuff done on every call of the function */
@@ -1836,7 +1860,7 @@ testpassbyval(PG_FUNCTION_ARGS)
         /* make the tuple into a datum */
         result = TupleGetDatum(slot, tuple);
 
-        /* Clean up */
+        /* Clean up (this is not actually necessary) */
         pfree(values[0]);
         pfree(values[1]);
         pfree(values[2]);
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 381b6047bf0729b022cd583d385544b50abac2df..d58d312238e66d4fd8c99a45cf9d5630ebfd54e8 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.6 2002/08/29 00:17:04 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeFunctionscan.c,v 1.7 2002/08/29 17:14:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -428,6 +428,12 @@ function_getonetuple(FunctionScanState *scanstate,
 	ExprContext	   *econtext = scanstate->csstate.cstate.cs_ExprContext;
 	TupleTableSlot *slot = scanstate->csstate.css_ScanTupleSlot;
 
+	/*
+	 * reset per-tuple memory context before each call of the function.
+	 * This cleans up any local memory the function may leak when called.
+	 */
+	ResetExprContext(econtext);
+
 	/*
 	 * get the next Datum from the function
 	 */
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 83d0d1051df974056d7122a049f1c79762f0ebb8..199efbacd26bdfdd20d88480f287db8eb5b51396 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -5,7 +5,7 @@
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *		$Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.3 2002/08/29 00:17:05 tgl Exp $
+ *		$Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.4 2002/08/29 17:14:33 tgl Exp $
  */
 #include "postgres.h"
 
@@ -24,15 +24,20 @@ static int next_lock(int locks[]);
 Datum
 pg_lock_status(PG_FUNCTION_ARGS)
 {
-	FuncCallContext		*funccxt;
-	LockData			*lockData;
+	FuncCallContext	   *funcctx;
+	LockData		   *lockData;
+	MemoryContext		oldcontext;
 
 	if (SRF_IS_FIRSTCALL())
 	{
-		MemoryContext	oldcxt;
 		TupleDesc		tupdesc;
 
-		funccxt = SRF_FIRSTCALL_INIT();
+		/* create a function context for cross-call persistence */
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		/* switch to memory context appropriate for multiple function calls */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
 		tupdesc = CreateTemplateTupleDesc(5, WITHOUTOID);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
 						   OIDOID, -1, 0, false);
@@ -45,10 +50,8 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isgranted",
 						   BOOLOID, -1, 0, false);
 
-		funccxt->slot = TupleDescGetSlot(tupdesc);
-		funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
-
-		oldcxt = MemoryContextSwitchTo(funccxt->fmctx);
+		funcctx->slot = TupleDescGetSlot(tupdesc);
+		funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
 
 		/*
 		 * Preload all the locking information that we will eventually format
@@ -56,15 +59,15 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		 * MemoryContext is reset when the SRF finishes, we don't need to
 		 * free it ourselves.
 		 */
-		funccxt->user_fctx = (LockData *) palloc(sizeof(LockData));
+		funcctx->user_fctx = (LockData *) palloc(sizeof(LockData));
 
-		GetLockStatusData(funccxt->user_fctx);
+		GetLockStatusData(funcctx->user_fctx);
 
-		MemoryContextSwitchTo(oldcxt);
+		MemoryContextSwitchTo(oldcontext);
 	}
 
-	funccxt	= SRF_PERCALL_SETUP();
-	lockData = (LockData *) funccxt->user_fctx;
+	funcctx	= SRF_PERCALL_SETUP();
+	lockData = (LockData *) funcctx->user_fctx;
 
 	while (lockData->currIdx < lockData->nelements)
 	{
@@ -82,7 +85,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		holder		= &(lockData->holders[currIdx]);
 		lock		= &(lockData->locks[currIdx]);
 		proc		= &(lockData->procs[currIdx]);
-		num_attrs	= funccxt->attinmeta->tupdesc->natts;
+		num_attrs	= funcctx->attinmeta->tupdesc->natts;
 
 		values = (char **) palloc(sizeof(*values) * num_attrs);
 
@@ -133,12 +136,12 @@ pg_lock_status(PG_FUNCTION_ARGS)
 
 		strncpy(values[3], GetLockmodeName(mode), 32);
 
-		tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
-		result = TupleGetDatum(funccxt->slot, tuple);
-		SRF_RETURN_NEXT(funccxt, result);
+		tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+		result = TupleGetDatum(funcctx->slot, tuple);
+		SRF_RETURN_NEXT(funcctx, result);
 	}
 
-	SRF_RETURN_DONE(funccxt);
+	SRF_RETURN_DONE(funcctx);
 }
 
 static LOCKMODE
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 28311c26b7b2ec3db8901244afb10d4d8beb7bc0..35ba972fe12051d536fc2dc1a384c06ff2a5300c 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -7,7 +7,7 @@
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/funcapi.c,v 1.3 2002/08/29 00:17:05 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/funcapi.c,v 1.4 2002/08/29 17:14:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,16 +39,12 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
 	{
 		/*
 		 * First call
+		 *
+		 * Allocate suitably long-lived space and zero it
 		 */
-		MemoryContext oldcontext;
-
-		/* switch to the appropriate memory context */
-		oldcontext = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt);
-
-		/*
-		 * allocate space and zero it
-		 */
-		retval = (FuncCallContext *) palloc(sizeof(FuncCallContext));
+		retval = (FuncCallContext *)
+			MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+							   sizeof(FuncCallContext));
 		MemSet(retval, 0, sizeof(FuncCallContext));
 
 		/*
@@ -59,15 +55,12 @@ init_MultiFuncCall(PG_FUNCTION_ARGS)
 		retval->slot = NULL;
 		retval->user_fctx = NULL;
 		retval->attinmeta = NULL;
-		retval->fmctx = fcinfo->flinfo->fn_mcxt;
+		retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
 
 		/*
 		 * save the pointer for cross-call use
 		 */
 		fcinfo->flinfo->fn_extra = retval;
-
-		/* back to the original memory context */
-		MemoryContextSwitchTo(oldcontext);
 	}
 	else	/* second and subsequent calls */
 	{
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 660cd124ba90c6afec74c5bb34a5d760109af516..5114fcc38f29d5745e0a7067b169eb1f7fac1127 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -5,7 +5,7 @@
  * command, configuration file, and command line options.
  * See src/backend/utils/misc/README for more information.
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.85 2002/08/29 00:17:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.86 2002/08/29 17:14:33 tgl Exp $
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  * Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -2421,6 +2421,7 @@ show_all_settings(PG_FUNCTION_ARGS)
 	int					max_calls;
 	TupleTableSlot	   *slot;
 	AttInMetadata	   *attinmeta;
+	MemoryContext		oldcontext;
 
 	/* stuff done only on the first call of the function */
  	if(SRF_IS_FIRSTCALL())
@@ -2428,6 +2429,9 @@ show_all_settings(PG_FUNCTION_ARGS)
 		/* create a function context for cross-call persistence */
  		funcctx = SRF_FIRSTCALL_INIT();
 
+		/* switch to memory context appropriate for multiple function calls */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
 		/* need a tuple descriptor representing two TEXT columns */
 		tupdesc = CreateTemplateTupleDesc(2, WITHOUTOID);
 		TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
@@ -2450,6 +2454,8 @@ show_all_settings(PG_FUNCTION_ARGS)
 
 		/* total number of tuples to be returned */
 		funcctx->max_calls = GetNumConfigOptions();
+
+		MemoryContextSwitchTo(oldcontext);
     }
 
 	/* stuff done on every call of the function */
diff --git a/src/include/funcapi.h b/src/include/funcapi.h
index 27dbdf20e62061a9207d0bee6ca64ad464807733..fcfb6acb69448a7f9a25698447ee8326ede4fdba 100644
--- a/src/include/funcapi.h
+++ b/src/include/funcapi.h
@@ -9,7 +9,7 @@
  *
  * Copyright (c) 2002, PostgreSQL Global Development Group
  *
- * $Id: funcapi.h,v 1.5 2002/08/29 00:17:06 tgl Exp $
+ * $Id: funcapi.h,v 1.6 2002/08/29 17:14:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -101,13 +101,14 @@ typedef struct FuncCallContext
 	AttInMetadata	   *attinmeta;
 
 	/*
-	 * memory context used to initialize structure
+	 * memory context used for structures which must live for multiple calls
 	 *
-	 * fmctx is set by SRF_FIRSTCALL_INIT() for you, and used by
-	 * SRF_RETURN_DONE() for cleanup. It is primarily for internal use
-	 * by the API.
+	 * multi_call_memory_ctx is set by SRF_FIRSTCALL_INIT() for you, and used
+	 * by SRF_RETURN_DONE() for cleanup. It is the most appropriate memory
+	 * context for any memory that is to be re-used across multiple calls
+	 * of the SRF.
 	 */
-	MemoryContext	fmctx;
+	MemoryContext	multi_call_memory_ctx;
 
 }	FuncCallContext;
 
@@ -160,17 +161,22 @@ extern HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
  * {
  * 	FuncCallContext	   *funcctx;
  * 	Datum				result;
+ *  MemoryContext		oldcontext;
  * 	<user defined declarations>
  * 
- * 	if(SRF_IS_FIRSTCALL())
+ * 	if (SRF_IS_FIRSTCALL())
  * 	{
- * 		<user defined code>
  * 		funcctx = SRF_FIRSTCALL_INIT();
+ *		// switch context when allocating stuff to be used in later calls
+ *		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+ * 		<user defined code>
  * 		<if returning composite>
  * 			<obtain slot>
  * 			funcctx->slot = slot;
  * 		<endif returning composite>
  * 		<user defined code>
+ *		// return to original context when allocating transient memory
+ *		MemoryContextSwitchTo(oldcontext);
  *  }
  * 	<user defined code>
  * 	funcctx = SRF_PERCALL_SETUP();