mirror of
https://github.com/postgres/postgres.git
synced 2025-09-09 13:09:39 +03:00
Fix possible failures when a tuplestore switches from in-memory to on-disk
mode while callers hold pointers to in-memory tuples. I reported this for the case of nodeWindowAgg's primary scan tuple, but inspection of the code shows that all of the calls in nodeWindowAgg and nodeCtescan are at risk. For the moment, fix it with a rather brute-force approach of copying whenever one of the at-risk callers requests a tuple. Later we might think of some sort of reference-count approach to reduce tuple copying.
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.46 2009/01/01 17:23:53 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/sort/tuplestore.c,v 1.47 2009/03/27 18:30:21 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -871,10 +871,17 @@ tuplestore_gettuple(Tuplestorestate *state, bool forward,
|
||||
*
|
||||
* If successful, put tuple in slot and return TRUE; else, clear the slot
|
||||
* and return FALSE.
|
||||
*
|
||||
* If copy is TRUE, the slot receives a copied tuple (allocated in current
|
||||
* memory context) that will stay valid regardless of future manipulations of
|
||||
* the tuplestore's state. If copy is FALSE, the slot may just receive a
|
||||
* pointer to a tuple held within the tuplestore. The latter is more
|
||||
* efficient but the slot contents may be corrupted if additional writes to
|
||||
* the tuplestore occur. (If using tuplestore_trim, see comments therein.)
|
||||
*/
|
||||
bool
|
||||
tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
|
||||
TupleTableSlot *slot)
|
||||
bool copy, TupleTableSlot *slot)
|
||||
{
|
||||
MinimalTuple tuple;
|
||||
bool should_free;
|
||||
@@ -883,6 +890,11 @@ tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
|
||||
|
||||
if (tuple)
|
||||
{
|
||||
if (copy && !should_free)
|
||||
{
|
||||
tuple = heap_copy_minimal_tuple(tuple);
|
||||
should_free = true;
|
||||
}
|
||||
ExecStoreMinimalTuple(tuple, slot, should_free);
|
||||
return true;
|
||||
}
|
||||
@@ -1107,7 +1119,10 @@ tuplestore_trim(Tuplestorestate *state)
|
||||
* since tuplestore_gettuple returns a direct pointer to our
|
||||
* internal copy of the tuple, it's likely that the caller has
|
||||
* still got the tuple just before "current" referenced in a slot.
|
||||
* So we keep one extra tuple before the oldest "current".
|
||||
* So we keep one extra tuple before the oldest "current". (Strictly
|
||||
* speaking, we could require such callers to use the "copy" flag to
|
||||
* tuplestore_gettupleslot, but for efficiency we allow this one case
|
||||
* to not use "copy".)
|
||||
*/
|
||||
nremove = oldest - 1;
|
||||
if (nremove <= 0)
|
||||
|
Reference in New Issue
Block a user