From f414abd62da7aa3cfd75e9047affd94c029c7c04 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Thu, 28 Feb 2019 12:27:58 -0800 Subject: [PATCH] Allow buffer tuple table slots to materialize after ExecStoreVirtualTuple(). While not common, it can be useful to store a virtual tuple into a buffer tuple table slot, and then materialize that slot. So far we've asserted out, which surprisingly wasn't a problem for anything in core. But that seems fragile, and it also breaks redis_fdw after ff11e7f4b9. Thus, allow materializing a virtual tuple stored in a buffer tuple table slot. Author: Andres Freund Discussion: https://postgr.es/m/20190227181621.xholonj7ff7ohxsg@alap3.anarazel.de https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de --- src/backend/executor/execTuples.c | 48 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 3a14251821..121649f343 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -700,25 +700,36 @@ tts_buffer_heap_materialize(TupleTableSlot *slot) slot->tts_flags |= TTS_FLAG_SHOULDFREE; - /* - * A heap tuple stored in a BufferHeapTupleTableSlot should have a buffer - * associated with it, unless it's materialized (which would've returned - * above). - */ - Assert(bslot->base.tuple); - oldContext = MemoryContextSwitchTo(slot->tts_mcxt); - bslot->base.tuple = heap_copytuple(bslot->base.tuple); - MemoryContextSwitchTo(oldContext); - /* - * A heap tuple stored in a BufferHeapTupleTableSlot should have a buffer - * associated with it, unless it's materialized. - */ - Assert(BufferIsValid(bslot->buffer)); - if (likely(BufferIsValid(bslot->buffer))) - ReleaseBuffer(bslot->buffer); - bslot->buffer = InvalidBuffer; + if (!bslot->base.tuple) + { + /* + * Normally BufferHeapTupleTableSlot should have a tuple + buffer + * associated with it, unless it's materialized (which would've + * returned above). But when it's useful to allow storing virtual + * tuples in a buffer slot, which then also needs to be + * materializable. + */ + bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor, + slot->tts_values, + slot->tts_isnull); + + } + else + { + bslot->base.tuple = heap_copytuple(bslot->base.tuple); + + /* + * A heap tuple stored in a BufferHeapTupleTableSlot should have a + * buffer associated with it, unless it's materialized or virtual. + */ + Assert(BufferIsValid(bslot->buffer)); + if (likely(BufferIsValid(bslot->buffer))) + ReleaseBuffer(bslot->buffer); + bslot->buffer = InvalidBuffer; + } + MemoryContextSwitchTo(oldContext); /* * Have to deform from scratch, otherwise tts_values[] entries could point @@ -752,6 +763,9 @@ tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) } else { + if (!bsrcslot->base.tuple) + tts_buffer_heap_materialize(srcslot); + tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple, bsrcslot->buffer, false); -- 2.40.0