]> granicus.if.org Git - postgresql/commitdiff
Fix memory leak in ARRAY(SELECT ...) subqueries.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jun 2012 21:26:13 +0000 (17:26 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jun 2012 21:26:13 +0000 (17:26 -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 */