Skip to content

Commit 0997e0a

Browse files
committed
Add TupleTableSlotOps.is_current_xact_tuple() method
This allows us to abstract how/whether table AM uses transaction identifiers. A custom table AM can use a custom slot, which may not store xmin directly, but determine the tuple belonging to the current transaction in the other way. Discussion: https://postgr.es/m/CAPpHfdurb9ycV8udYqM%3Do0sPS66PJ4RCBM1g-bBpvzUfogY0EA%40mail.gmail.com Reviewed-by: Matthias van de Meent, Mark Dilger, Pavel Borisov Reviewed-by: Nikita Malakhov, Japin Li
1 parent c35a3fb commit 0997e0a

File tree

3 files changed

+101
-7
lines changed

3 files changed

+101
-7
lines changed

src/backend/executor/execTuples.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
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+
357397
static void
358398
tts_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+
524576
static void
525577
tts_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+
717792
static void
718793
tts_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,

src/backend/utils/adt/ri_triggers.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,9 +1260,6 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
12601260
{
12611261
const RI_ConstraintInfo *riinfo;
12621262
int ri_nullcheck;
1263-
Datum xminDatum;
1264-
TransactionId xmin;
1265-
bool isnull;
12661263

12671264
/*
12681265
* AfterTriggerSaveEvent() handles things such that this function is never
@@ -1330,10 +1327,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
13301327
* this if we knew the INSERT trigger already fired, but there is no easy
13311328
* way to know that.)
13321329
*/
1333-
xminDatum = slot_getsysattr(oldslot, MinTransactionIdAttributeNumber, &isnull);
1334-
Assert(!isnull);
1335-
xmin = DatumGetTransactionId(xminDatum);
1336-
if (TransactionIdIsCurrentTransactionId(xmin))
1330+
if (slot_is_current_xact_tuple(oldslot))
13371331
return true;
13381332

13391333
/* If all old and new key values are equal, no check is needed */

src/include/executor/tuptable.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ struct TupleTableSlotOps
166166
*/
167167
Datum (*getsysattr) (TupleTableSlot *slot, int attnum, bool *isnull);
168168

169+
/*
170+
* Check if the tuple is created by the current transaction. Throws an
171+
* error if the slot doesn't contain the storage tuple.
172+
*/
173+
bool (*is_current_xact_tuple) (TupleTableSlot *slot);
174+
169175
/*
170176
* Make the contents of the slot solely depend on the slot, and not on
171177
* underlying resources (like another memory context, buffers, etc).
@@ -426,6 +432,21 @@ slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
426432
return slot->tts_ops->getsysattr(slot, attnum, isnull);
427433
}
428434

435+
/*
436+
* slot_is_current_xact_tuple - check if the slot's current tuple is created
437+
* by the current transaction.
438+
*
439+
* If the slot does not contain a storage tuple, this will throw an error.
440+
* Hence before calling this function, callers should make sure that the
441+
* slot type supports storage tuples and that there is currently one inside
442+
* the slot.
443+
*/
444+
static inline bool
445+
slot_is_current_xact_tuple(TupleTableSlot *slot)
446+
{
447+
return slot->tts_ops->is_current_xact_tuple(slot);
448+
}
449+
429450
/*
430451
* ExecClearTuple - clear the slot's contents
431452
*/

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy