@@ -74,7 +74,11 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
7474static pg_attribute_always_inline void
7575slot_deform_heap_tuple (TupleTableSlot * slot , HeapTuple tuple , uint32 * offp ,
7676 int natts );
77- static void tts_buffer_heap_store_tuple (TupleTableSlot * slot , HeapTuple tuple , Buffer buffer );
77+ static inline void tts_buffer_heap_store_tuple (TupleTableSlot * slot ,
78+ HeapTuple tuple ,
79+ Buffer buffer ,
80+ bool transfer_pin );
81+ static void tts_heap_store_tuple (TupleTableSlot * slot , HeapTuple tuple , bool shouldFree );
7882
7983
8084const TupleTableSlotOps TTSOpsVirtual ;
@@ -743,7 +747,9 @@ tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
743747 }
744748 else
745749 {
746- tts_buffer_heap_store_tuple (dstslot , bsrcslot -> base .tuple , bsrcslot -> buffer );
750+ tts_buffer_heap_store_tuple (dstslot , bsrcslot -> base .tuple ,
751+ bsrcslot -> buffer , false);
752+
747753 /*
748754 * Need to materialize because the HeapTupleData portion of the tuple
749755 * might be in a foreign memory context. That's annoying, but until
@@ -792,8 +798,9 @@ tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
792798 return minimal_tuple_from_heap_tuple (bslot -> base .tuple );
793799}
794800
795- static void
796- tts_buffer_heap_store_tuple (TupleTableSlot * slot , HeapTuple tuple , Buffer buffer )
801+ static inline void
802+ tts_buffer_heap_store_tuple (TupleTableSlot * slot , HeapTuple tuple ,
803+ Buffer buffer , bool transfer_pin )
797804{
798805 BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * ) slot ;
799806
@@ -813,7 +820,9 @@ tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer
813820
814821 /*
815822 * If tuple is on a disk page, keep the page pinned as long as we hold a
816- * pointer into it. We assume the caller already has such a pin.
823+ * pointer into it. We assume the caller already has such a pin. If
824+ * transfer_pin is true, we'll transfer that pin to this slot, if not
825+ * we'll pin it again ourselves.
817826 *
818827 * This is coded to optimize the case where the slot previously held a
819828 * tuple on the same disk page: in that case releasing and re-acquiring
@@ -824,8 +833,19 @@ tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, Buffer buffer
824833 {
825834 if (BufferIsValid (bslot -> buffer ))
826835 ReleaseBuffer (bslot -> buffer );
836+
827837 bslot -> buffer = buffer ;
828- IncrBufferRefCount (buffer );
838+
839+ if (!transfer_pin && BufferIsValid (buffer ))
840+ IncrBufferRefCount (buffer );
841+ }
842+ else if (transfer_pin && BufferIsValid (buffer ))
843+ {
844+ /*
845+ * In transfer_pin mode the caller won't know about the same-page
846+ * optimization, so we gotta release its pin.
847+ */
848+ ReleaseBuffer (buffer );
829849 }
830850}
831851
@@ -1321,7 +1341,32 @@ ExecStoreBufferHeapTuple(HeapTuple tuple,
13211341
13221342 if (unlikely (!TTS_IS_BUFFERTUPLE (slot )))
13231343 elog (ERROR , "trying to store an on-disk heap tuple into wrong type of slot" );
1324- tts_buffer_heap_store_tuple (slot , tuple , buffer );
1344+ tts_buffer_heap_store_tuple (slot , tuple , buffer , false);
1345+
1346+
1347+ return slot ;
1348+ }
1349+
1350+ /*
1351+ * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1352+ * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1353+ */
1354+ TupleTableSlot *
1355+ ExecStorePinnedBufferHeapTuple (HeapTuple tuple ,
1356+ TupleTableSlot * slot ,
1357+ Buffer buffer )
1358+ {
1359+ /*
1360+ * sanity checks
1361+ */
1362+ Assert (tuple != NULL );
1363+ Assert (slot != NULL );
1364+ Assert (slot -> tts_tupleDescriptor != NULL );
1365+ Assert (BufferIsValid (buffer ));
1366+
1367+ if (unlikely (!TTS_IS_BUFFERTUPLE (slot )))
1368+ elog (ERROR , "trying to store an on-disk heap tuple into wrong type of slot" );
1369+ tts_buffer_heap_store_tuple (slot , tuple , buffer , true);
13251370
13261371 return slot ;
13271372}
0 commit comments