aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeProjectSet.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-10-28 14:04:43 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-10-28 14:04:43 -0400
commitd8d7f282fd1dc883e8062447b541aa230f6f29a3 (patch)
treedfbd529eecd3308ea3397b912a4b6bf3627af279 /src/backend/executor/nodeProjectSet.c
parent7180bb827bf5f2638c2868c92ea942eb29d5b723 (diff)
downloadpostgresql-d8d7f282fd1dc883e8062447b541aa230f6f29a3.tar.gz
postgresql-d8d7f282fd1dc883e8062447b541aa230f6f29a3.zip
Fix intra-query memory leak when a SRF returns zero rows.
When looping around after finding that the set-returning function returned zero rows for the current input tuple, ExecProjectSet neglected to reset either of the two memory contexts it's responsible for cleaning out. Typically this wouldn't cause much problem, because once the SRF does return at least one row, the contexts would get reset on the next call. However, if the SRF returns no rows for many input tuples in succession, quite a lot of memory could be transiently consumed. To fix, make sure we reset both contexts while looping around. Per bug #18172 from Sergei Kornilov. Back-patch to all supported branches. Discussion: https://postgr.es/m/18172-9b8c5fc1d676ded3@postgresql.org
Diffstat (limited to 'src/backend/executor/nodeProjectSet.c')
-rw-r--r--src/backend/executor/nodeProjectSet.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 277d2783711..9fbba095bfc 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -73,20 +73,22 @@ ExecProjectSet(PlanState *pstate)
}
/*
- * Reset argument context to free any expression evaluation storage
- * allocated in the previous tuple cycle. Note this can't happen until
- * we're done projecting out tuples from a scan tuple, as ValuePerCall
- * functions are allowed to reference the arguments for each returned
- * tuple.
- */
- MemoryContextReset(node->argcontext);
-
- /*
* Get another input tuple and project SRFs from it.
*/
for (;;)
{
/*
+ * Reset argument context to free any expression evaluation storage
+ * allocated in the previous tuple cycle. Note this can't happen
+ * until we're done projecting out tuples from a scan tuple, as
+ * ValuePerCall functions are allowed to reference the arguments for
+ * each returned tuple. However, if we loop around after finding that
+ * no rows are produced from a scan tuple, we should reset, to avoid
+ * leaking memory when many successive scan tuples produce no rows.
+ */
+ MemoryContextReset(node->argcontext);
+
+ /*
* Retrieve tuples from the outer plan until there are no more.
*/
outerPlan = outerPlanState(node);
@@ -111,6 +113,12 @@ ExecProjectSet(PlanState *pstate)
*/
if (resultSlot)
return resultSlot;
+
+ /*
+ * When we do loop back, we'd better reset the econtext again, just in
+ * case the SRF leaked some memory there.
+ */
+ ResetExprContext(econtext);
}
return NULL;