aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 b4bbdc89b19..aee26d38133 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;