]> 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:31 +0000 (17:26 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 21 Jun 2012 21:26:31 +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 d03416a56b4c1754d6d047d32f096875a11faf5e..e69eb5c6edfc2d8542e26d953394b9b322edc98d 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;
@@ -1004,16 +1005,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 23a86e908484cf9c52c54820d9d5a6c35863669d..5348fa892d0afc4671e157f4a72e7077078385ef 100644 (file)
@@ -663,6 +663,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 */