From 669ac03af62328e4eb572dacb8ba319414ef1211 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 15 Jun 2011 14:05:22 -0400 Subject: [PATCH] Fix failure to account for memory used by tuplestore_putvalues(). This oversight could result in a tuplestore using much more than the intended amount of memory. It would only happen in a code path that loaded a tuplestore via tuplestore_putvalues(), and many of those won't emit huge amounts of data; but cases such as holdable cursors and plpgsql's RETURN NEXT command could have the problem. The fix ensures that the tuplestore will switch to write-to-disk mode when it overruns work_mem. The potential overrun was finite, because we would still count the space used by the tuple pointer array, so the tuplestore code would eventually flip into write-to-disk mode anyway. When storing wide tuples we would go far past the expected work_mem usage before that happened; but this may account for the lack of prior reports. Back-patch to 8.4, where tuplestore_putvalues was introduced. Per bug #6061 from Yann Delorme. --- src/backend/utils/sort/tuplestore.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index b67d78c8e7..31c0a7b9f0 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -570,7 +570,8 @@ tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple) MemoryContext oldcxt = MemoryContextSwitchTo(state->context); /* - * Copy the tuple. (Must do this even in WRITEFILE case.) + * Copy the tuple. (Must do this even in WRITEFILE case. Note that + * COPYTUP includes USEMEM, so we needn't do that here.) */ tuple = COPYTUP(state, tuple); @@ -580,9 +581,8 @@ tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple) } /* - * Similar to tuplestore_puttuple(), but start from the values + nulls - * array. This avoids requiring that the caller construct a HeapTuple, - * saving a copy. + * Similar to tuplestore_puttuple(), but work from values + nulls arrays. + * This avoids an extra tuple-construction operation. */ void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, @@ -592,6 +592,7 @@ tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, MemoryContext oldcxt = MemoryContextSwitchTo(state->context); tuple = heap_form_minimal_tuple(tdesc, values, isnull); + USEMEM(state, GetMemoryChunkSpace(tuple)); tuplestore_puttuple_common(state, (void *) tuple);