6060#include "access/heaptoast.h"
6161#include "access/htup_details.h"
6262#include "access/tupdesc_details.h"
63+ #include "access/xact.h"
6364#include "catalog/pg_type.h"
6465#include "funcapi.h"
6566#include "nodes/nodeFuncs.h"
@@ -148,6 +149,22 @@ tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
148149 return 0 ; /* silence compiler warnings */
149150}
150151
152+ /*
153+ * VirtualTupleTableSlots never have storage tuples. We generally
154+ * shouldn't get here, but provide a user-friendly message if we do.
155+ */
156+ static bool
157+ tts_virtual_is_current_xact_tuple (TupleTableSlot * slot )
158+ {
159+ Assert (!TTS_EMPTY (slot ));
160+
161+ ereport (ERROR ,
162+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
163+ errmsg ("don't have a storage tuple in this context" )));
164+
165+ return false; /* silence compiler warnings */
166+ }
167+
151168/*
152169 * To materialize a virtual slot all the datums that aren't passed by value
153170 * have to be copied into the slot's memory context. To do so, compute the
@@ -354,6 +371,29 @@ tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
354371 slot -> tts_tupleDescriptor , isnull );
355372}
356373
374+ static bool
375+ tts_heap_is_current_xact_tuple (TupleTableSlot * slot )
376+ {
377+ HeapTupleTableSlot * hslot = (HeapTupleTableSlot * ) slot ;
378+ TransactionId xmin ;
379+
380+ Assert (!TTS_EMPTY (slot ));
381+
382+ /*
383+ * In some code paths it's possible to get here with a non-materialized
384+ * slot, in which case we can't check if tuple is created by the current
385+ * transaction.
386+ */
387+ if (!hslot -> tuple )
388+ ereport (ERROR ,
389+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
390+ errmsg ("don't have a storage tuple in this context" )));
391+
392+ xmin = HeapTupleHeaderGetRawXmin (hslot -> tuple -> t_data );
393+
394+ return TransactionIdIsCurrentTransactionId (xmin );
395+ }
396+
357397static void
358398tts_heap_materialize (TupleTableSlot * slot )
359399{
@@ -521,6 +561,18 @@ tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
521561 return 0 ; /* silence compiler warnings */
522562}
523563
564+ static bool
565+ tts_minimal_is_current_xact_tuple (TupleTableSlot * slot )
566+ {
567+ Assert (!TTS_EMPTY (slot ));
568+
569+ ereport (ERROR ,
570+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
571+ errmsg ("don't have a storage tuple in this context" )));
572+
573+ return false; /* silence compiler warnings */
574+ }
575+
524576static void
525577tts_minimal_materialize (TupleTableSlot * slot )
526578{
@@ -714,6 +766,29 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
714766 slot -> tts_tupleDescriptor , isnull );
715767}
716768
769+ static bool
770+ tts_buffer_is_current_xact_tuple (TupleTableSlot * slot )
771+ {
772+ BufferHeapTupleTableSlot * bslot = (BufferHeapTupleTableSlot * ) slot ;
773+ TransactionId xmin ;
774+
775+ Assert (!TTS_EMPTY (slot ));
776+
777+ /*
778+ * In some code paths it's possible to get here with a non-materialized
779+ * slot, in which case we can't check if tuple is created by the current
780+ * transaction.
781+ */
782+ if (!bslot -> base .tuple )
783+ ereport (ERROR ,
784+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
785+ errmsg ("don't have a storage tuple in this context" )));
786+
787+ xmin = HeapTupleHeaderGetRawXmin (bslot -> base .tuple -> t_data );
788+
789+ return TransactionIdIsCurrentTransactionId (xmin );
790+ }
791+
717792static void
718793tts_buffer_heap_materialize (TupleTableSlot * slot )
719794{
@@ -1029,6 +1104,7 @@ const TupleTableSlotOps TTSOpsVirtual = {
10291104 .getsomeattrs = tts_virtual_getsomeattrs ,
10301105 .getsysattr = tts_virtual_getsysattr ,
10311106 .materialize = tts_virtual_materialize ,
1107+ .is_current_xact_tuple = tts_virtual_is_current_xact_tuple ,
10321108 .copyslot = tts_virtual_copyslot ,
10331109
10341110 /*
@@ -1048,6 +1124,7 @@ const TupleTableSlotOps TTSOpsHeapTuple = {
10481124 .clear = tts_heap_clear ,
10491125 .getsomeattrs = tts_heap_getsomeattrs ,
10501126 .getsysattr = tts_heap_getsysattr ,
1127+ .is_current_xact_tuple = tts_heap_is_current_xact_tuple ,
10511128 .materialize = tts_heap_materialize ,
10521129 .copyslot = tts_heap_copyslot ,
10531130 .get_heap_tuple = tts_heap_get_heap_tuple ,
@@ -1065,6 +1142,7 @@ const TupleTableSlotOps TTSOpsMinimalTuple = {
10651142 .clear = tts_minimal_clear ,
10661143 .getsomeattrs = tts_minimal_getsomeattrs ,
10671144 .getsysattr = tts_minimal_getsysattr ,
1145+ .is_current_xact_tuple = tts_minimal_is_current_xact_tuple ,
10681146 .materialize = tts_minimal_materialize ,
10691147 .copyslot = tts_minimal_copyslot ,
10701148
@@ -1082,6 +1160,7 @@ const TupleTableSlotOps TTSOpsBufferHeapTuple = {
10821160 .clear = tts_buffer_heap_clear ,
10831161 .getsomeattrs = tts_buffer_heap_getsomeattrs ,
10841162 .getsysattr = tts_buffer_heap_getsysattr ,
1163+ .is_current_xact_tuple = tts_buffer_is_current_xact_tuple ,
10851164 .materialize = tts_buffer_heap_materialize ,
10861165 .copyslot = tts_buffer_heap_copyslot ,
10871166 .get_heap_tuple = tts_buffer_heap_get_heap_tuple ,
0 commit comments