aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/pgstattuple/README.pgstattuple10
-rw-r--r--contrib/pgstattuple/pgstattuple.c78
-rw-r--r--contrib/pgstattuple/pgstattuple.sql.in26
-rw-r--r--contrib/tablefunc/tablefunc.c28
-rw-r--r--doc/src/sgml/xfunc.sgml46
-rw-r--r--src/backend/executor/nodeFunctionscan.c8
-rw-r--r--src/backend/utils/adt/lockfuncs.c41
-rw-r--r--src/backend/utils/fmgr/funcapi.c21
-rw-r--r--src/backend/utils/misc/guc.c8
-rw-r--r--src/include/funcapi.h22
10 files changed, 154 insertions, 134 deletions
diff --git a/contrib/pgstattuple/README.pgstattuple b/contrib/pgstattuple/README.pgstattuple
index 804c37c6a91..42a7fc2165d 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 a357f6f412a..4fbc60bcf2a 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 7c661a8ee3c..d3370fb830c 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 d05fc1a76b6..37a6e723a65 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 b3f653a28a1..fad7ad888d8 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>
@@ -1715,26 +1716,42 @@ SRF_RETURN_DONE(funcctx)
</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 381b6047bf0..d58d312238e 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 $
*
*-------------------------------------------------------------------------
*/
@@ -429,6 +429,12 @@ function_getonetuple(FunctionScanState *scanstate,
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
*/
retDatum = ExecEvalExprSwitchContext(expr, econtext, isNull, isDone);
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 83d0d1051df..199efbacd26 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 28311c26b7b..35ba972fe12 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 660cd124ba9..5114fcc38f2 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 27dbdf20e62..fcfb6acb694 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();