60
60
#include "access/heaptoast.h"
61
61
#include "access/htup_details.h"
62
62
#include "access/tupdesc_details.h"
63
+ #include "access/xact.h"
63
64
#include "catalog/pg_type.h"
64
65
#include "funcapi.h"
65
66
#include "nodes/nodeFuncs.h"
@@ -148,6 +149,22 @@ tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
148
149
return 0 ; /* silence compiler warnings */
149
150
}
150
151
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
+
151
168
/*
152
169
* To materialize a virtual slot all the datums that aren't passed by value
153
170
* 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)
354
371
slot -> tts_tupleDescriptor , isnull );
355
372
}
356
373
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
+
357
397
static void
358
398
tts_heap_materialize (TupleTableSlot * slot )
359
399
{
@@ -521,6 +561,18 @@ tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
521
561
return 0 ; /* silence compiler warnings */
522
562
}
523
563
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
+
524
576
static void
525
577
tts_minimal_materialize (TupleTableSlot * slot )
526
578
{
@@ -714,6 +766,29 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
714
766
slot -> tts_tupleDescriptor , isnull );
715
767
}
716
768
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
+
717
792
static void
718
793
tts_buffer_heap_materialize (TupleTableSlot * slot )
719
794
{
@@ -1029,6 +1104,7 @@ const TupleTableSlotOps TTSOpsVirtual = {
1029
1104
.getsomeattrs = tts_virtual_getsomeattrs ,
1030
1105
.getsysattr = tts_virtual_getsysattr ,
1031
1106
.materialize = tts_virtual_materialize ,
1107
+ .is_current_xact_tuple = tts_virtual_is_current_xact_tuple ,
1032
1108
.copyslot = tts_virtual_copyslot ,
1033
1109
1034
1110
/*
@@ -1048,6 +1124,7 @@ const TupleTableSlotOps TTSOpsHeapTuple = {
1048
1124
.clear = tts_heap_clear ,
1049
1125
.getsomeattrs = tts_heap_getsomeattrs ,
1050
1126
.getsysattr = tts_heap_getsysattr ,
1127
+ .is_current_xact_tuple = tts_heap_is_current_xact_tuple ,
1051
1128
.materialize = tts_heap_materialize ,
1052
1129
.copyslot = tts_heap_copyslot ,
1053
1130
.get_heap_tuple = tts_heap_get_heap_tuple ,
@@ -1065,6 +1142,7 @@ const TupleTableSlotOps TTSOpsMinimalTuple = {
1065
1142
.clear = tts_minimal_clear ,
1066
1143
.getsomeattrs = tts_minimal_getsomeattrs ,
1067
1144
.getsysattr = tts_minimal_getsysattr ,
1145
+ .is_current_xact_tuple = tts_minimal_is_current_xact_tuple ,
1068
1146
.materialize = tts_minimal_materialize ,
1069
1147
.copyslot = tts_minimal_copyslot ,
1070
1148
@@ -1082,6 +1160,7 @@ const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1082
1160
.clear = tts_buffer_heap_clear ,
1083
1161
.getsomeattrs = tts_buffer_heap_getsomeattrs ,
1084
1162
.getsysattr = tts_buffer_heap_getsysattr ,
1163
+ .is_current_xact_tuple = tts_buffer_is_current_xact_tuple ,
1085
1164
.materialize = tts_buffer_heap_materialize ,
1086
1165
.copyslot = tts_buffer_heap_copyslot ,
1087
1166
.get_heap_tuple = tts_buffer_heap_get_heap_tuple ,
0 commit comments