Fix memory leak in ARRAY(SELECT ...) subqueries.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jun 2012 21:26:07 +0000 (17:26 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jun 2012 21:27:19 +0000 (17:27 -0400)
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
src/include/nodes/execnodes.h

index da31820e2d941f899d82bed33fe236d764bb9f77..4b8746f4f2611d84f80a97178c677002f5710f63 100644 (file)
@@ -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)
index 6fe8c2303a21850e9cbf2aa7247a2e82cc7d7911..aa3916998718e88d6e0a4472c96f8a13f19864b3 100644 (file)
@@ -708,6 +708,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 */