mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Adjust nodeFunctionscan.c to reset transient memory context between calls
to the table function, thus preventing memory leakage accumulation across calls. This means that SRFs need to be careful to distinguish permanent and local storage; adjust code and documentation accordingly. Patch by Joe Conway, very minor tweaks by Tom Lane.
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user