0005-Add-table-AM-tuple_is_current-method-v2.patch
application/octet-stream
Filename: 0005-Add-table-AM-tuple_is_current-method-v2.patch
Type: application/octet-stream
Part: 6
Message:
Re: Table AM Interface Enhancements
Patch
Format: format-patch
Series: patch v2-0005
Subject: Add table AM tuple_is_current method
| File | + | − |
|---|---|---|
| src/backend/executor/execTuples.c | 79 | 0 |
| src/backend/utils/adt/ri_triggers.c | 1 | 7 |
| src/include/executor/tuptable.h | 21 | 0 |
From 5840c7d640a0e55ae14d7da36dfd343082b2c5ee Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Wed, 7 Jun 2023 13:47:53 +0300
Subject: [PATCH 05/13] Add table AM tuple_is_current method
This allows to abstract how/whether table AM uses transaction identifiers.
---
src/backend/executor/execTuples.c | 79 +++++++++++++++++++++++++++++
src/backend/utils/adt/ri_triggers.c | 8 +--
src/include/executor/tuptable.h | 21 ++++++++
3 files changed, 101 insertions(+), 7 deletions(-)
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index a7aa2ee02b1..2e6e441f7f8 100644
--- a/src/backend/executor/execTuples.c
+++ b/src/backend/executor/execTuples.c
@@ -60,6 +60,7 @@
#include "access/heaptoast.h"
#include "access/htup_details.h"
#include "access/tupdesc_details.h"
+#include "access/xact.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "nodes/nodeFuncs.h"
@@ -148,6 +149,22 @@ tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
return 0; /* silence compiler warnings */
}
+/*
+ * VirtualTupleTableSlots never have a storage tuples. We generally
+ * shouldn't get here, but provide a user-friendly message if we do.
+ */
+static bool
+tts_virtual_is_current_xact_tuple(TupleTableSlot *slot)
+{
+ Assert(!TTS_EMPTY(slot));
+
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("don't have a storage tuple in this context")));
+
+ return false; /* silence compiler warnings */
+}
+
/*
* To materialize a virtual slot all the datums that aren't passed by value
* 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)
slot->tts_tupleDescriptor, isnull);
}
+static bool
+tts_heap_is_current_xact_tuple(TupleTableSlot *slot)
+{
+ HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
+ TransactionId xmin;
+
+ Assert(!TTS_EMPTY(slot));
+
+ /*
+ * In some code paths it's possible to get here with a non-materialized
+ * slot, in which case we can't check if tuple is created by the current
+ * transaction.
+ */
+ if (!hslot->tuple)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("don't have a storage tuple in this context")));
+
+ xmin = HeapTupleHeaderGetRawXmin(hslot->tuple->t_data);
+
+ return TransactionIdIsCurrentTransactionId(xmin);
+}
+
static void
tts_heap_materialize(TupleTableSlot *slot)
{
@@ -521,6 +561,18 @@ tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
return 0; /* silence compiler warnings */
}
+static bool
+tts_minimal_is_current_xact_tuple(TupleTableSlot *slot)
+{
+ Assert(!TTS_EMPTY(slot));
+
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("don't have a storage tuple in this context")));
+
+ return false; /* silence compiler warnings */
+}
+
static void
tts_minimal_materialize(TupleTableSlot *slot)
{
@@ -714,6 +766,29 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
slot->tts_tupleDescriptor, isnull);
}
+static bool
+tts_buffer_is_current_xact_tuple(TupleTableSlot *slot)
+{
+ BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
+ TransactionId xmin;
+
+ Assert(!TTS_EMPTY(slot));
+
+ /*
+ * In some code paths it's possible to get here with a non-materialized
+ * slot, in which case we can't check if tuple is created by the current
+ * transaction.
+ */
+ if (!bslot->base.tuple)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("don't have a storage tuple in this context")));
+
+ xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
+
+ return TransactionIdIsCurrentTransactionId(xmin);
+}
+
static void
tts_buffer_heap_materialize(TupleTableSlot *slot)
{
@@ -1029,6 +1104,7 @@ const TupleTableSlotOps TTSOpsVirtual = {
.getsomeattrs = tts_virtual_getsomeattrs,
.getsysattr = tts_virtual_getsysattr,
.materialize = tts_virtual_materialize,
+ .is_current_xact_tuple = tts_virtual_is_current_xact_tuple,
.copyslot = tts_virtual_copyslot,
/*
@@ -1048,6 +1124,7 @@ const TupleTableSlotOps TTSOpsHeapTuple = {
.clear = tts_heap_clear,
.getsomeattrs = tts_heap_getsomeattrs,
.getsysattr = tts_heap_getsysattr,
+ .is_current_xact_tuple = tts_heap_is_current_xact_tuple,
.materialize = tts_heap_materialize,
.copyslot = tts_heap_copyslot,
.get_heap_tuple = tts_heap_get_heap_tuple,
@@ -1065,6 +1142,7 @@ const TupleTableSlotOps TTSOpsMinimalTuple = {
.clear = tts_minimal_clear,
.getsomeattrs = tts_minimal_getsomeattrs,
.getsysattr = tts_minimal_getsysattr,
+ .is_current_xact_tuple = tts_minimal_is_current_xact_tuple,
.materialize = tts_minimal_materialize,
.copyslot = tts_minimal_copyslot,
@@ -1082,6 +1160,7 @@ const TupleTableSlotOps TTSOpsBufferHeapTuple = {
.clear = tts_buffer_heap_clear,
.getsomeattrs = tts_buffer_heap_getsomeattrs,
.getsysattr = tts_buffer_heap_getsysattr,
+ .is_current_xact_tuple = tts_buffer_is_current_xact_tuple,
.materialize = tts_buffer_heap_materialize,
.copyslot = tts_buffer_heap_copyslot,
.get_heap_tuple = tts_buffer_heap_get_heap_tuple,
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 2fe93775003..62601a6d80c 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -1260,9 +1260,6 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
{
const RI_ConstraintInfo *riinfo;
int ri_nullcheck;
- Datum xminDatum;
- TransactionId xmin;
- bool isnull;
/*
* AfterTriggerSaveEvent() handles things such that this function is never
@@ -1330,10 +1327,7 @@ RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
* this if we knew the INSERT trigger already fired, but there is no easy
* way to know that.)
*/
- xminDatum = slot_getsysattr(oldslot, MinTransactionIdAttributeNumber, &isnull);
- Assert(!isnull);
- xmin = DatumGetTransactionId(xminDatum);
- if (TransactionIdIsCurrentTransactionId(xmin))
+ if (slot_is_current_xact_tuple(oldslot))
return true;
/* If all old and new key values are equal, no check is needed */
diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h
index 6133dbcd0a3..c2eddda74a8 100644
--- a/src/include/executor/tuptable.h
+++ b/src/include/executor/tuptable.h
@@ -166,6 +166,12 @@ struct TupleTableSlotOps
*/
Datum (*getsysattr) (TupleTableSlot *slot, int attnum, bool *isnull);
+ /*
+ * Check if the tuple is created by the current transaction. Throws an
+ * error if the slot doesn't contain the storage tuple.
+ */
+ bool (*is_current_xact_tuple) (TupleTableSlot *slot);
+
/*
* Make the contents of the slot solely depend on the slot, and not on
* underlying resources (like another memory context, buffers, etc).
@@ -426,6 +432,21 @@ slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
return slot->tts_ops->getsysattr(slot, attnum, isnull);
}
+/*
+ * slot_is_current_xact_tuple - check if the slot's current tuple is created
+ * by the current transaction.
+ *
+ * If the slot does not contain storage tuple, this will throw an error.
+ * Hence before calling this function, callers should make sure that the
+ * slot type supports storage tuples and there is currently one inside the
+ * slot.
+ */
+static inline bool
+slot_is_current_xact_tuple(TupleTableSlot *slot)
+{
+ return slot->tts_ops->is_current_xact_tuple(slot);
+}
+
/*
* ExecClearTuple - clear the slot's contents
*/
--
2.39.3 (Apple Git-145)