*
* At ExecutorStart()
* ----------------
-
+ *
* - ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a
* TupleTableSlots for the tuples returned by the access method, and
* ExecInitResultTypeTL() to define the node's return
return heap_form_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
slot->tts_isnull);
-
}
static MinimalTuple
{
HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+ Assert(!TTS_EMPTY(slot));
+
return heap_getsysattr(hslot->tuple, attnum,
slot->tts_tupleDescriptor, isnull);
}
Assert(!TTS_EMPTY(slot));
- /* This slot has it's tuple already materialized. Nothing to do. */
+ /* If slot has its tuple already materialized, nothing to do. */
if (TTS_SHOULDFREE(slot))
return;
- slot->tts_flags |= TTS_FLAG_SHOULDFREE;
-
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+ /*
+ * Have to deform from scratch, otherwise tts_values[] entries could point
+ * into the non-materialized tuple (which might be gone when accessed).
+ */
+ slot->tts_nvalid = 0;
+ hslot->off = 0;
+
if (!hslot->tuple)
hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
hslot->tuple = heap_copytuple(hslot->tuple);
}
- /*
- * Have to deform from scratch, otherwise tts_values[] entries could point
- * into the non-materialized tuple (which might be gone when accessed).
- */
- slot->tts_nvalid = 0;
- hslot->off = 0;
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
MemoryContextSwitchTo(oldContext);
}
slot->tts_nvalid = 0;
hslot->tuple = tuple;
hslot->off = 0;
- slot->tts_flags &= ~TTS_FLAG_EMPTY;
+ slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
slot->tts_tid = tuple->t_self;
if (shouldFree)
Assert(!TTS_EMPTY(slot));
- /* This slot has it's tuple already materialized. Nothing to do. */
+ /* If slot has its tuple already materialized, nothing to do. */
if (TTS_SHOULDFREE(slot))
return;
- slot->tts_flags |= TTS_FLAG_SHOULDFREE;
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+ /*
+ * Have to deform from scratch, otherwise tts_values[] entries could point
+ * into the non-materialized tuple (which might be gone when accessed).
+ */
+ slot->tts_nvalid = 0;
+ mslot->off = 0;
+
if (!mslot->mintuple)
{
mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
}
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+
Assert(mslot->tuple == &mslot->minhdr);
mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
MemoryContextSwitchTo(oldContext);
-
- /*
- * Have to deform from scratch, otherwise tts_values[] entries could point
- * into the non-materialized tuple (which might be gone when accessed).
- */
- slot->tts_nvalid = 0;
- mslot->off = 0;
}
static void
if (shouldFree)
slot->tts_flags |= TTS_FLAG_SHOULDFREE;
- else
- Assert(!TTS_SHOULDFREE(slot));
}
heap_freetuple(bslot->base.tuple);
slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
-
- Assert(!BufferIsValid(bslot->buffer));
}
if (BufferIsValid(bslot->buffer))
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+ Assert(!TTS_EMPTY(slot));
+
return heap_getsysattr(bslot->base.tuple, attnum,
slot->tts_tupleDescriptor, isnull);
}
Assert(!TTS_EMPTY(slot));
- /* If already materialized nothing to do. */
+ /* If slot has its tuple already materialized, nothing to do. */
if (TTS_SHOULDFREE(slot))
return;
- slot->tts_flags |= TTS_FLAG_SHOULDFREE;
-
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
+ /*
+ * Have to deform from scratch, otherwise tts_values[] entries could point
+ * into the non-materialized tuple (which might be gone when accessed).
+ */
+ bslot->base.off = 0;
+ slot->tts_nvalid = 0;
+
if (!bslot->base.tuple)
{
/*
bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
slot->tts_isnull);
-
}
else
{
* 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
- * into the non-materialized tuple (which might be gone when accessed).
+ * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
+ * any. This avoids having a transient state that would fall foul of our
+ * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
+ * In the unlikely event that ReleaseBuffer() above errors out, we'd
+ * effectively leak the copied tuple, but that seems fairly harmless.
*/
- bslot->base.off = 0;
- slot->tts_nvalid = 0;
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
+
+ MemoryContextSwitchTo(oldContext);
}
static void
MemoryContext oldContext;
ExecClearTuple(dstslot);
- dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
+ dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
MemoryContextSwitchTo(oldContext);
}
else
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
ExecClearTuple(slot);
- slot->tts_flags |= TTS_FLAG_SHOULDFREE;
slot->tts_flags &= ~TTS_FLAG_EMPTY;
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
bslot->base.tuple = heap_copytuple(tuple);
+ slot->tts_flags |= TTS_FLAG_SHOULDFREE;
MemoryContextSwitchTo(oldContext);
if (shouldFree)
slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
}
-
}
}