v3-0001-Refactor-some-TOAST-value-ID-code-to-use-uint64-i.patch
text/x-diff
Filename: v3-0001-Refactor-some-TOAST-value-ID-code-to-use-uint64-i.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v3-0001
Subject: Refactor some TOAST value ID code to use uint64 instead of Oid
| File | + | − |
|---|---|---|
| contrib/amcheck/verify_heapam.c | 41 | 28 |
| src/backend/access/common/toast_internals.c | 4 | 4 |
| src/backend/access/heap/heaptoast.c | 6 | 6 |
| src/backend/replication/logical/reorderbuffer.c | 8 | 6 |
| src/include/access/heaptoast.h | 1 | 1 |
| src/include/access/tableam.h | 2 | 2 |
From d3821ee322e2e4f40a78f5788da9d394ab9ba7c6 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Thu, 19 Jun 2025 09:57:19 +0900
Subject: [PATCH v3 01/14] Refactor some TOAST value ID code to use uint64
instead of Oid
This change is a mechanical switch to change most of the code paths that
assume TOAST value IDs to be Oids to become uint64, easing an upcoming
change to allow 8-byte TOAST values.
The areas touched are related to table AM, amcheck and logical
decoding's reorder buffer. A good chunk of the changes involve
switching printf() markers from %u to PRIu64.
---
src/include/access/heaptoast.h | 2 +-
src/include/access/tableam.h | 4 +-
src/backend/access/common/toast_internals.c | 8 +--
src/backend/access/heap/heaptoast.c | 12 ++--
.../replication/logical/reorderbuffer.c | 14 ++--
contrib/amcheck/verify_heapam.c | 69 +++++++++++--------
6 files changed, 62 insertions(+), 47 deletions(-)
diff --git a/src/include/access/heaptoast.h b/src/include/access/heaptoast.h
index 6385a27caf83..6e3558cbd6d2 100644
--- a/src/include/access/heaptoast.h
+++ b/src/include/access/heaptoast.h
@@ -142,7 +142,7 @@ extern HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc,
* Fetch a slice from a toast value stored in a heap table.
* ----------
*/
-extern void heap_fetch_toast_slice(Relation toastrel, Oid valueid,
+extern void heap_fetch_toast_slice(Relation toastrel, uint64 valueid,
int32 attrsize, int32 sliceoffset,
int32 slicelength, struct varlena *result);
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 1c9e802a6b12..b640047d2fdc 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -740,7 +740,7 @@ typedef struct TableAmRoutine
* table implemented by this AM. See table_relation_fetch_toast_slice()
* for more details.
*/
- void (*relation_fetch_toast_slice) (Relation toastrel, Oid valueid,
+ void (*relation_fetch_toast_slice) (Relation toastrel, uint64 valueid,
int32 attrsize,
int32 sliceoffset,
int32 slicelength,
@@ -1873,7 +1873,7 @@ table_relation_toast_am(Relation rel)
* stored.
*/
static inline void
-table_relation_fetch_toast_slice(Relation toastrel, Oid valueid,
+table_relation_fetch_toast_slice(Relation toastrel, uint64 valueid,
int32 attrsize, int32 sliceoffset,
int32 slicelength, struct varlena *result)
{
diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 7d8be8346ce5..4a1342da6e1b 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -26,8 +26,8 @@
#include "utils/rel.h"
#include "utils/snapmgr.h"
-static bool toastrel_valueid_exists(Relation toastrel, Oid valueid);
-static bool toastid_valueid_exists(Oid toastrelid, Oid valueid);
+static bool toastrel_valueid_exists(Relation toastrel, uint64 valueid);
+static bool toastid_valueid_exists(Oid toastrelid, uint64 valueid);
/* ----------
* toast_compress_datum -
@@ -456,7 +456,7 @@ toast_delete_datum(Relation rel, Datum value, bool is_speculative)
* ----------
*/
static bool
-toastrel_valueid_exists(Relation toastrel, Oid valueid)
+toastrel_valueid_exists(Relation toastrel, uint64 valueid)
{
bool result = false;
ScanKeyData toastkey;
@@ -504,7 +504,7 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
* ----------
*/
static bool
-toastid_valueid_exists(Oid toastrelid, Oid valueid)
+toastid_valueid_exists(Oid toastrelid, uint64 valueid)
{
bool result;
Relation toastrel;
diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c
index cb1e57030f64..76936b2f4944 100644
--- a/src/backend/access/heap/heaptoast.c
+++ b/src/backend/access/heap/heaptoast.c
@@ -623,7 +623,7 @@ toast_build_flattened_tuple(TupleDesc tupleDesc,
* result is the varlena into which the results should be written.
*/
void
-heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize,
+heap_fetch_toast_slice(Relation toastrel, uint64 valueid, int32 attrsize,
int32 sliceoffset, int32 slicelength,
struct varlena *result)
{
@@ -725,7 +725,7 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize,
else
{
/* should never happen */
- elog(ERROR, "found toasted toast chunk for toast value %u in %s",
+ elog(ERROR, "found toasted toast chunk for toast value %" PRIu64 " in %s",
valueid, RelationGetRelationName(toastrel));
chunksize = 0; /* keep compiler quiet */
chunkdata = NULL;
@@ -737,13 +737,13 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize,
if (curchunk != expectedchunk)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg_internal("unexpected chunk number %d (expected %d) for toast value %u in %s",
+ errmsg_internal("unexpected chunk number %d (expected %d) for toast value %" PRIu64 " in %s",
curchunk, expectedchunk, valueid,
RelationGetRelationName(toastrel))));
if (curchunk > endchunk)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %u in %s",
+ errmsg_internal("unexpected chunk number %d (out of range %d..%d) for toast value %" PRIu64 " in %s",
curchunk,
startchunk, endchunk, valueid,
RelationGetRelationName(toastrel))));
@@ -752,7 +752,7 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize,
if (chunksize != expected_size)
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u in %s",
+ errmsg_internal("unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %" PRIu64 " in %s",
chunksize, expected_size,
curchunk, totalchunks, valueid,
RelationGetRelationName(toastrel))));
@@ -781,7 +781,7 @@ heap_fetch_toast_slice(Relation toastrel, Oid valueid, int32 attrsize,
if (expectedchunk != (endchunk + 1))
ereport(ERROR,
(errcode(ERRCODE_DATA_CORRUPTED),
- errmsg_internal("missing chunk number %d for toast value %u in %s",
+ errmsg_internal("missing chunk number %d for toast value %" PRIu64 " in %s",
expectedchunk, valueid,
RelationGetRelationName(toastrel))));
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 5febd154b6ba..3a2c6649dbd4 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -176,7 +176,7 @@ typedef struct ReorderBufferIterTXNState
/* toast datastructures */
typedef struct ReorderBufferToastEnt
{
- Oid chunk_id; /* toast_table.chunk_id */
+ uint64 chunk_id; /* toast_table.chunk_id */
int32 last_chunk_seq; /* toast_table.chunk_seq of the last chunk we
* have seen */
Size num_chunks; /* number of chunks we've already seen */
@@ -4944,7 +4944,7 @@ ReorderBufferToastInitHash(ReorderBuffer *rb, ReorderBufferTXN *txn)
Assert(txn->toast_hash == NULL);
- hash_ctl.keysize = sizeof(Oid);
+ hash_ctl.keysize = sizeof(uint64);
hash_ctl.entrysize = sizeof(ReorderBufferToastEnt);
hash_ctl.hcxt = rb->context;
txn->toast_hash = hash_create("ReorderBufferToastHash", 5, &hash_ctl,
@@ -4968,7 +4968,7 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
bool isnull;
Pointer chunk;
TupleDesc desc = RelationGetDescr(relation);
- Oid chunk_id;
+ uint64 chunk_id;
int32 chunk_seq;
if (txn->toast_hash == NULL)
@@ -4995,11 +4995,11 @@ ReorderBufferToastAppendChunk(ReorderBuffer *rb, ReorderBufferTXN *txn,
dlist_init(&ent->chunks);
if (chunk_seq != 0)
- elog(ERROR, "got sequence entry %d for toast chunk %u instead of seq 0",
+ elog(ERROR, "got sequence entry %d for toast chunk %" PRIu64 " instead of seq 0",
chunk_seq, chunk_id);
}
else if (found && chunk_seq != ent->last_chunk_seq + 1)
- elog(ERROR, "got sequence entry %d for toast chunk %u instead of seq %d",
+ elog(ERROR, "got sequence entry %d for toast chunk %" PRIu64 " instead of seq %d",
chunk_seq, chunk_id, ent->last_chunk_seq + 1);
chunk = DatumGetPointer(fastgetattr(newtup, 3, desc, &isnull));
@@ -5108,6 +5108,7 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
struct varlena *reconstructed;
dlist_iter it;
Size data_done = 0;
+ uint64 toast_valueid;
/* system columns aren't toasted */
if (attr->attnum < 0)
@@ -5132,13 +5133,14 @@ ReorderBufferToastReplace(ReorderBuffer *rb, ReorderBufferTXN *txn,
continue;
VARATT_EXTERNAL_GET_POINTER(toast_pointer, varlena);
+ toast_valueid = toast_pointer.va_valueid;
/*
* Check whether the toast tuple changed, replace if so.
*/
ent = (ReorderBufferToastEnt *)
hash_search(txn->toast_hash,
- &toast_pointer.va_valueid,
+ &toast_valueid,
HASH_FIND,
NULL);
if (ent == NULL)
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 4963e9245cb5..3b2bdced4cdc 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -1556,11 +1556,18 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
uint32 extsize)
{
int32 chunk_seq;
- int32 last_chunk_seq = (extsize - 1) / TOAST_MAX_CHUNK_SIZE;
+ int32 last_chunk_seq;
Pointer chunk;
bool isnull;
int32 chunksize;
int32 expected_size;
+ uint64 toast_valueid;
+ int32 max_chunk_size;
+
+ toast_valueid = ta->toast_pointer.va_valueid;
+
+ max_chunk_size = TOAST_MAX_CHUNK_SIZE;
+ last_chunk_seq = (extsize - 1) / max_chunk_size;
/* Sanity-check the sequence number. */
chunk_seq = DatumGetInt32(fastgetattr(toasttup, 2,
@@ -1568,16 +1575,16 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
if (isnull)
{
report_toast_corruption(ctx, ta,
- psprintf("toast value %u has toast chunk with null sequence number",
- ta->toast_pointer.va_valueid));
+ psprintf("toast value %" PRIu64 " has toast chunk with null sequence number",
+ toast_valueid));
return;
}
if (chunk_seq != *expected_chunk_seq)
{
/* Either the TOAST index is corrupt, or we don't have all chunks. */
report_toast_corruption(ctx, ta,
- psprintf("toast value %u index scan returned chunk %d when expecting chunk %d",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " index scan returned chunk %d when expecting chunk %d",
+ toast_valueid,
chunk_seq, *expected_chunk_seq));
}
*expected_chunk_seq = chunk_seq + 1;
@@ -1588,8 +1595,8 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
if (isnull)
{
report_toast_corruption(ctx, ta,
- psprintf("toast value %u chunk %d has null data",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " chunk %d has null data",
+ toast_valueid,
chunk_seq));
return;
}
@@ -1608,8 +1615,8 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
uint32 header = ((varattrib_4b *) chunk)->va_4byte.va_header;
report_toast_corruption(ctx, ta,
- psprintf("toast value %u chunk %d has invalid varlena header %0x",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " chunk %d has invalid varlena header %0x",
+ toast_valueid,
chunk_seq, header));
return;
}
@@ -1620,19 +1627,19 @@ check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx,
if (chunk_seq > last_chunk_seq)
{
report_toast_corruption(ctx, ta,
- psprintf("toast value %u chunk %d follows last expected chunk %d",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " chunk %d follows last expected chunk %d",
+ toast_valueid,
chunk_seq, last_chunk_seq));
return;
}
- expected_size = chunk_seq < last_chunk_seq ? TOAST_MAX_CHUNK_SIZE
- : extsize - (last_chunk_seq * TOAST_MAX_CHUNK_SIZE);
+ expected_size = chunk_seq < last_chunk_seq ? max_chunk_size
+ : extsize - (last_chunk_seq * max_chunk_size);
if (chunksize != expected_size)
report_toast_corruption(ctx, ta,
- psprintf("toast value %u chunk %d has size %u, but expected size %u",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " chunk %d has size %u, but expected size %u",
+ toast_valueid,
chunk_seq, chunksize, expected_size));
}
@@ -1663,6 +1670,7 @@ check_tuple_attribute(HeapCheckContext *ctx)
struct varlena *attr;
char *tp; /* pointer to the tuple data */
uint16 infomask;
+ uint64 toast_pointer_valueid;
CompactAttribute *thisatt;
struct varatt_external toast_pointer;
@@ -1766,6 +1774,7 @@ check_tuple_attribute(HeapCheckContext *ctx)
return true;
/* It is external, and we're looking at a page on disk */
+ toast_pointer_valueid = toast_pointer.va_valueid;
/*
* Must copy attr into toast_pointer for alignment considerations
@@ -1775,8 +1784,8 @@ check_tuple_attribute(HeapCheckContext *ctx)
/* Toasted attributes too large to be untoasted should never be stored */
if (toast_pointer.va_rawsize > VARLENA_SIZE_LIMIT)
report_corruption(ctx,
- psprintf("toast value %u rawsize %d exceeds limit %d",
- toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " rawsize %d exceeds limit %d",
+ toast_pointer_valueid,
toast_pointer.va_rawsize,
VARLENA_SIZE_LIMIT));
@@ -1803,16 +1812,16 @@ check_tuple_attribute(HeapCheckContext *ctx)
}
if (!valid)
report_corruption(ctx,
- psprintf("toast value %u has invalid compression method id %d",
- toast_pointer.va_valueid, cmid));
+ psprintf("toast value %" PRIu64 " has invalid compression method id %d",
+ toast_pointer_valueid, cmid));
}
/* The tuple header better claim to contain toasted values */
if (!(infomask & HEAP_HASEXTERNAL))
{
report_corruption(ctx,
- psprintf("toast value %u is external but tuple header flag HEAP_HASEXTERNAL not set",
- toast_pointer.va_valueid));
+ psprintf("toast value %" PRIu64 " is external but tuple header flag HEAP_HASEXTERNAL not set",
+ toast_pointer_valueid));
return true;
}
@@ -1820,8 +1829,8 @@ check_tuple_attribute(HeapCheckContext *ctx)
if (!ctx->rel->rd_rel->reltoastrelid)
{
report_corruption(ctx,
- psprintf("toast value %u is external but relation has no toast relation",
- toast_pointer.va_valueid));
+ psprintf("toast value %" PRIu64 " is external but relation has no toast relation",
+ toast_pointer_valueid));
return true;
}
@@ -1866,9 +1875,11 @@ check_toasted_attribute(HeapCheckContext *ctx, ToastedAttribute *ta)
uint32 extsize;
int32 expected_chunk_seq = 0;
int32 last_chunk_seq;
+ uint64 toast_valueid;
+ int32 max_chunk_size = TOAST_MAX_CHUNK_SIZE;
extsize = VARATT_EXTERNAL_GET_EXTSIZE(ta->toast_pointer);
- last_chunk_seq = (extsize - 1) / TOAST_MAX_CHUNK_SIZE;
+ last_chunk_seq = (extsize - 1) / max_chunk_size;
/*
* Setup a scan key to find chunks in toast table with matching va_valueid
@@ -1896,14 +1907,16 @@ check_toasted_attribute(HeapCheckContext *ctx, ToastedAttribute *ta)
}
systable_endscan_ordered(toastscan);
+ toast_valueid = ta->toast_pointer.va_valueid;
+
if (!found_toasttup)
report_toast_corruption(ctx, ta,
- psprintf("toast value %u not found in toast table",
- ta->toast_pointer.va_valueid));
+ psprintf("toast value %" PRIu64 " not found in toast table",
+ toast_valueid));
else if (expected_chunk_seq <= last_chunk_seq)
report_toast_corruption(ctx, ta,
- psprintf("toast value %u was expected to end at chunk %d, but ended while expecting chunk %d",
- ta->toast_pointer.va_valueid,
+ psprintf("toast value %" PRIu64 " was expected to end at chunk %d, but ended while expecting chunk %d",
+ toast_valueid,
last_chunk_seq, expected_chunk_seq));
}
--
2.50.0