postgres.git / summary / log / commit / refs

commit    d8bd584bf4cc6c74178a73ae8924b86ab2bebb44
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Thu Jun 21 21:26:24 2012 +0000
First released in: 9.3.0, 8.3.20, 8.4.13, 9.0.9, 9.1.5, 9.2.0

    Fix memory leak in ARRAY(SELECT ...) subqueries.
    
    Repeated execution of an uncorrelated ARRAY_SUBLINK sub-select (which
    I think can only happen if the sub-select is embedded in a larger,
    correlated subquery) would leak memory for the duration of the query,
    due to not reclaiming the array generated in the previous execution.
    Per bug #6698 from Armando Miraglia.  Diagnosis and fix idea by Heikki,
    patch itself by me.
    
    This has been like this all along, so back-patch to all supported versions.


src/backend/executor/nodeSubplan.c | 18 +++++++++++++----- src/include/nodes/execnodes.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index d397b136fd3..4ac4541f58e 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -668,6 +668,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) * initialize my state */ sstate->curTuple = NULL; + sstate->curArray = PointerGetDatum(NULL); sstate->projLeft = NULL; sstate->projRight = NULL; sstate->hashtable = NULL; @@ -994,16 +995,23 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) int paramid = linitial_int(subplan->setParam); ParamExecData *prm = &(econtext->ecxt_param_exec_vals[paramid]); - prm->execPlan = NULL; - /* We build the result in query context so it won't disappear */ + /* + * We build the result array in query context so it won't disappear; + * to avoid leaking memory across repeated calls, we have to remember + * the latest value, much as for curTuple above. + */ + if (node->curArray != PointerGetDatum(NULL)) + pfree(DatumGetPointer(node->curArray)); if (astate != NULL) - prm->value = makeArrayResult(astate, - econtext->ecxt_per_query_memory); + node->curArray = makeArrayResult(astate, + econtext->ecxt_per_query_memory); else { MemoryContextSwitchTo(econtext->ecxt_per_query_memory); - prm->value = PointerGetDatum(construct_empty_array(subplan->firstColType)); + node->curArray = PointerGetDatum(construct_empty_array(subplan->firstColType)); } + prm->execPlan = NULL; + prm->value = node->curArray; prm->isnull = false; } else if (!found) diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index f7a6787b55a..fa8465d6023 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -714,6 +714,7 @@ typedef struct SubPlanState ExprState *testexpr; /* state of combining expression */ List *args; /* states of argument expression(s) */ HeapTuple curTuple; /* copy of most recent tuple from subplan */ + Datum curArray; /* most recent array from ARRAY() subplan */ /* these are used when hashing the subselect's output: */ ProjectionInfo *projLeft; /* for projecting lefthand exprs */ ProjectionInfo *projRight; /* for projecting subselect output */ [parent: 9166ae25bc90]