1919 *
2020 *At ExecutorStart()
2121 *----------------
22-
22+ *
2323 *- ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a
2424 * TupleTableSlots for the tuples returned by the access method, and
2525 * ExecInitResultTypeTL() to define the node's return
@@ -273,7 +273,6 @@ tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
273273return heap_form_tuple (slot -> tts_tupleDescriptor ,
274274slot -> tts_values ,
275275slot -> tts_isnull );
276-
277276}
278277
279278static MinimalTuple
@@ -335,6 +334,8 @@ tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
335334{
336335HeapTupleTableSlot * hslot = (HeapTupleTableSlot * )slot ;
337336
337+ Assert (!TTS_EMPTY (slot ));
338+
338339return heap_getsysattr (hslot -> tuple ,attnum ,
339340slot -> tts_tupleDescriptor ,isnull );
340341}
@@ -347,14 +348,19 @@ tts_heap_materialize(TupleTableSlot *slot)
347348
348349Assert (!TTS_EMPTY (slot ));
349350
350- /*This slot hasit's tuple already materialized. Nothing to do. */
351+ /*If slot hasits tuple already materialized, nothing to do. */
351352if (TTS_SHOULDFREE (slot ))
352353return ;
353354
354- slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
355-
356355oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
357356
357+ /*
358+ * Have to deform from scratch, otherwise tts_values[] entries could point
359+ * into the non-materialized tuple (which might be gone when accessed).
360+ */
361+ slot -> tts_nvalid = 0 ;
362+ hslot -> off = 0 ;
363+
358364if (!hslot -> tuple )
359365hslot -> tuple = heap_form_tuple (slot -> tts_tupleDescriptor ,
360366slot -> tts_values ,
@@ -369,12 +375,7 @@ tts_heap_materialize(TupleTableSlot *slot)
369375hslot -> tuple = heap_copytuple (hslot -> tuple );
370376}
371377
372- /*
373- * Have to deform from scratch, otherwise tts_values[] entries could point
374- * into the non-materialized tuple (which might be gone when accessed).
375- */
376- slot -> tts_nvalid = 0 ;
377- hslot -> off = 0 ;
378+ slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
378379
379380MemoryContextSwitchTo (oldContext );
380381}
@@ -437,7 +438,7 @@ tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
437438slot -> tts_nvalid = 0 ;
438439hslot -> tuple = tuple ;
439440hslot -> off = 0 ;
440- slot -> tts_flags &= ~TTS_FLAG_EMPTY ;
441+ slot -> tts_flags &= ~( TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE ) ;
441442slot -> tts_tid = tuple -> t_self ;
442443
443444if (shouldFree )
@@ -510,13 +511,19 @@ tts_minimal_materialize(TupleTableSlot *slot)
510511
511512Assert (!TTS_EMPTY (slot ));
512513
513- /*This slot hasit's tuple already materialized. Nothing to do. */
514+ /*If slot hasits tuple already materialized, nothing to do. */
514515if (TTS_SHOULDFREE (slot ))
515516return ;
516517
517- slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
518518oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
519519
520+ /*
521+ * Have to deform from scratch, otherwise tts_values[] entries could point
522+ * into the non-materialized tuple (which might be gone when accessed).
523+ */
524+ slot -> tts_nvalid = 0 ;
525+ mslot -> off = 0 ;
526+
520527if (!mslot -> mintuple )
521528{
522529mslot -> mintuple = heap_form_minimal_tuple (slot -> tts_tupleDescriptor ,
@@ -533,19 +540,14 @@ tts_minimal_materialize(TupleTableSlot *slot)
533540mslot -> mintuple = heap_copy_minimal_tuple (mslot -> mintuple );
534541}
535542
543+ slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
544+
536545Assert (mslot -> tuple == & mslot -> minhdr );
537546
538547mslot -> minhdr .t_len = mslot -> mintuple -> t_len + MINIMAL_TUPLE_OFFSET ;
539548mslot -> minhdr .t_data = (HeapTupleHeader ) ((char * )mslot -> mintuple - MINIMAL_TUPLE_OFFSET );
540549
541550MemoryContextSwitchTo (oldContext );
542-
543- /*
544- * Have to deform from scratch, otherwise tts_values[] entries could point
545- * into the non-materialized tuple (which might be gone when accessed).
546- */
547- slot -> tts_nvalid = 0 ;
548- mslot -> off = 0 ;
549551}
550552
551553static void
@@ -616,8 +618,6 @@ tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree
616618
617619if (shouldFree )
618620slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
619- else
620- Assert (!TTS_SHOULDFREE (slot ));
621621}
622622
623623
@@ -652,8 +652,6 @@ tts_buffer_heap_clear(TupleTableSlot *slot)
652652
653653heap_freetuple (bslot -> base .tuple );
654654slot -> tts_flags &= ~TTS_FLAG_SHOULDFREE ;
655-
656- Assert (!BufferIsValid (bslot -> buffer ));
657655}
658656
659657if (BufferIsValid (bslot -> buffer ))
@@ -682,6 +680,8 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
682680{
683681BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * )slot ;
684682
683+ Assert (!TTS_EMPTY (slot ));
684+
685685return heap_getsysattr (bslot -> base .tuple ,attnum ,
686686slot -> tts_tupleDescriptor ,isnull );
687687}
@@ -694,14 +694,19 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
694694
695695Assert (!TTS_EMPTY (slot ));
696696
697- /* If already materialized nothing to do. */
697+ /* Ifslot has its tuple already materialized, nothing to do. */
698698if (TTS_SHOULDFREE (slot ))
699699return ;
700700
701- slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
702-
703701oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
704702
703+ /*
704+ * Have to deform from scratch, otherwise tts_values[] entries could point
705+ * into the non-materialized tuple (which might be gone when accessed).
706+ */
707+ bslot -> base .off = 0 ;
708+ slot -> tts_nvalid = 0 ;
709+
705710if (!bslot -> base .tuple )
706711{
707712/*
@@ -714,7 +719,6 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
714719bslot -> base .tuple = heap_form_tuple (slot -> tts_tupleDescriptor ,
715720slot -> tts_values ,
716721slot -> tts_isnull );
717-
718722}
719723else
720724{
@@ -724,19 +728,21 @@ tts_buffer_heap_materialize(TupleTableSlot *slot)
724728 * A heap tuple stored in a BufferHeapTupleTableSlot should have a
725729 * buffer associated with it, unless it's materialized or virtual.
726730 */
727- Assert (BufferIsValid (bslot -> buffer ));
728731if (likely (BufferIsValid (bslot -> buffer )))
729732ReleaseBuffer (bslot -> buffer );
730733bslot -> buffer = InvalidBuffer ;
731734}
732- MemoryContextSwitchTo (oldContext );
733735
734736/*
735- * Have to deform from scratch, otherwise tts_values[] entries could point
736- * into the non-materialized tuple (which might be gone when accessed).
737+ * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
738+ * any. This avoids having a transient state that would fall foul of our
739+ * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
740+ * In the unlikely event that ReleaseBuffer() above errors out, we'd
741+ * effectively leak the copied tuple, but that seems fairly harmless.
737742 */
738- bslot -> base .off = 0 ;
739- slot -> tts_nvalid = 0 ;
743+ slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
744+
745+ MemoryContextSwitchTo (oldContext );
740746}
741747
742748static void
@@ -757,10 +763,10 @@ tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
757763MemoryContext oldContext ;
758764
759765ExecClearTuple (dstslot );
760- dstslot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
761766dstslot -> tts_flags &= ~TTS_FLAG_EMPTY ;
762767oldContext = MemoryContextSwitchTo (dstslot -> tts_mcxt );
763768bdstslot -> base .tuple = ExecCopySlotHeapTuple (srcslot );
769+ dstslot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
764770MemoryContextSwitchTo (oldContext );
765771}
766772else
@@ -1445,10 +1451,10 @@ ExecForceStoreHeapTuple(HeapTuple tuple,
14451451BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * )slot ;
14461452
14471453ExecClearTuple (slot );
1448- slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
14491454slot -> tts_flags &= ~TTS_FLAG_EMPTY ;
14501455oldContext = MemoryContextSwitchTo (slot -> tts_mcxt );
14511456bslot -> base .tuple = heap_copytuple (tuple );
1457+ slot -> tts_flags |=TTS_FLAG_SHOULDFREE ;
14521458MemoryContextSwitchTo (oldContext );
14531459
14541460if (shouldFree )
@@ -1857,7 +1863,6 @@ slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
18571863slot -> tts_values [missattnum ]= attrmiss [missattnum ].am_value ;
18581864slot -> tts_isnull [missattnum ]= !attrmiss [missattnum ].am_present ;
18591865}
1860-
18611866}
18621867}
18631868