Skip to content

Commit 06d5eac

Browse files
committed
Avoid leaking memory while evaluating arguments for a table function.
ExecMakeTableFunctionResult evaluated the arguments for a function-in-FROM in the query-lifespan memory context. This is insignificant in simple cases where the function relation is scanned only once; but if the function is in a sub-SELECT or is on the inside of a nested loop, any memory consumed during argument evaluation can add up quickly. (The potential for trouble here had been foreseen long ago, per existing comments; but we'd not previously seen a complaint from the field about it.) To fix, create an additional temporary context just for this purpose. Per an example from MauMau. Back-patch to all active branches.
1 parent 94ab763 commit 06d5eac

File tree

4 files changed

+29
-4
lines changed

4 files changed

+29
-4
lines changed

src/backend/executor/execQual.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,6 +1981,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
19811981
Tuplestorestate *
19821982
ExecMakeTableFunctionResult(ExprState *funcexpr,
19831983
ExprContext *econtext,
1984+
MemoryContext argContext,
19841985
TupleDesc expectedDesc,
19851986
bool randomAccess)
19861987
{
@@ -2062,12 +2063,18 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
20622063
/*
20632064
* Evaluate the function's argument list.
20642065
*
2065-
* Note: ideally, we'd do this in the per-tuple context, but then the
2066-
* argument values would disappear when we reset the context in the
2067-
* inner loop. So do it in caller context. Perhaps we should make a
2068-
* separate context just to hold the evaluated arguments?
2066+
* We can't do this in the per-tuple context: the argument values
2067+
* would disappear when we reset that context in the inner loop. And
2068+
* the caller's CurrentMemoryContext is typically a query-lifespan
2069+
* context, so we don't want to leak memory there. We require the
2070+
* caller to pass a separate memory context that can be used for this,
2071+
* and can be reset each time through to avoid bloat.
20692072
*/
2073+
MemoryContextReset(argContext);
2074+
oldcontext = MemoryContextSwitchTo(argContext);
20702075
argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
2076+
MemoryContextSwitchTo(oldcontext);
2077+
20712078
/* We don't allow sets in the arguments of the table function */
20722079
if (argDone != ExprSingleResult)
20732080
ereport(ERROR,

src/backend/executor/nodeFunctionscan.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "funcapi.h"
2727
#include "nodes/nodeFuncs.h"
2828
#include "utils/builtins.h"
29+
#include "utils/memutils.h"
2930

3031

3132
static TupleTableSlot *FunctionNext(FunctionScanState *node);
@@ -65,6 +66,7 @@ FunctionNext(FunctionScanState *node)
6566
node->tuplestorestate = tuplestorestate =
6667
ExecMakeTableFunctionResult(node->funcexpr,
6768
node->ss.ps.ps_ExprContext,
69+
node->argcontext,
6870
node->tupdesc,
6971
node->eflags & EXEC_FLAG_BACKWARD);
7072
}
@@ -228,6 +230,19 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
228230
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
229231
ExecAssignScanProjectionInfo(&scanstate->ss);
230232

233+
/*
234+
* Create a memory context that ExecMakeTableFunctionResult can use to
235+
* evaluate function arguments in. We can't use the per-tuple context for
236+
* this because it gets reset too often; but we don't want to leak
237+
* evaluation results into the query-lifespan context either. We just
238+
* need one context, because we evaluate each function separately.
239+
*/
240+
scanstate->argcontext = AllocSetContextCreate(CurrentMemoryContext,
241+
"Table function arguments",
242+
ALLOCSET_DEFAULT_MINSIZE,
243+
ALLOCSET_DEFAULT_INITSIZE,
244+
ALLOCSET_DEFAULT_MAXSIZE);
245+
231246
return scanstate;
232247
}
233248

src/include/executor/executor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname,
223223
bool *isNull);
224224
extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,
225225
ExprContext *econtext,
226+
MemoryContext argContext,
226227
TupleDesc expectedDesc,
227228
bool randomAccess);
228229
extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,

src/include/nodes/execnodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,6 +1353,7 @@ typedef struct SubqueryScanState
13531353
* tupdesc expected return tuple description
13541354
* tuplestorestate private state of tuplestore.c
13551355
* funcexpr state for function expression being evaluated
1356+
* argcontext memory context to evaluate function arguments in
13561357
* ----------------
13571358
*/
13581359
typedef struct FunctionScanState
@@ -1362,6 +1363,7 @@ typedef struct FunctionScanState
13621363
TupleDesc tupdesc;
13631364
Tuplestorestate *tuplestorestate;
13641365
ExprState *funcexpr;
1366+
MemoryContext argcontext;
13651367
} FunctionScanState;
13661368

13671369
/* ----------------

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy