From db8daebf6a46aef82a0f8de70344165d3c171fb4 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 23 Feb 2026 09:39:37 +1300 Subject: [PATCH v9 5/5] Reduce size of CompactAttribute struct to 8 bytes Previously, this was 16 bytes. With the use of some bitflags and by reducing the attcacheoff field size to a 16-bit type, we can halve the size of the struct. It's unlikely that caching the offsets for offsets larger than what will fit in a 16-bit int will help much as the tuple is very likely to have some non-fixed-width types anyway, the offsets of which we cannot cache. --- src/backend/access/common/tupdesc.c | 9 +++++++++ src/backend/executor/execTuples.c | 16 ++++++++++++---- src/include/access/tupdesc.h | 16 ++++++++-------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 028fcd53734..590dd8ec331 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -534,6 +534,15 @@ TupleDescFinalize(TupleDesc tupdesc) cattr->attcacheoff = off; + /* + * attcacheoff is an int16, so don't try and cache any offsets larger + * than will fit in that type. + */ + if (off > PG_INT16_MAX) + break; + + cattr->attcacheoff = off; + off += cattr->attlen; firstNonCachedOffsetAttr = i + 1; } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 2070c665d2f..b3699b77649 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -1013,6 +1013,7 @@ static pg_attribute_always_inline void slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int reqnatts) { + CompactAttribute *cattrs; CompactAttribute *cattr; TupleDesc tupleDesc = slot->tts_tupleDescriptor; HeapTupleHeader tup = tuple->t_data; @@ -1101,6 +1102,13 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, values = slot->tts_values; slot->tts_nvalid = reqnatts; + /* + * We store the tupleDesc's CompactAttribute array in 'cattrs' as gcc + * seems to be unwilling to optimize accessing the CompactAttribute + * element efficiently when accessing it via TupleDescCompactAttr(). + */ + cattrs = tupleDesc->compact_attrs; + /* Ensure we calculated tp correctly */ Assert(tp == (char *) tup + tup->t_hoff); @@ -1111,7 +1119,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int attlen; isnull[attnum] = false; - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; attlen = cattr->attlen; /* We don't expect any non-byval types */ @@ -1156,7 +1164,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, do { isnull[attnum] = false; - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; off = cattr->attcacheoff; values[attnum] = fetch_att_noerr(tp + off, @@ -1183,7 +1191,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, int attlen; isnull[attnum] = false; - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; attlen = cattr->attlen; /* @@ -1216,7 +1224,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, continue; } - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; attlen = cattr->attlen; /* As above, we don't expect cstrings */ diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index d4c3a749558..5e54b82c296 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -55,7 +55,7 @@ typedef struct TupleConstr * directly after the FormData_pg_attribute struct is populated or * altered in any way. * - * Currently, this struct is 16 bytes. Any code changes which enlarge this + * Currently, this struct is 8 bytes. Any code changes which enlarge this * struct should be considered very carefully. * * Code which must access a TupleDesc's attribute data should always make use @@ -67,17 +67,17 @@ typedef struct TupleConstr */ typedef struct CompactAttribute { - int32 attcacheoff; /* fixed offset into tuple, if known, or -1 */ + int16 attcacheoff; /* fixed offset into tuple, if known, or -1 */ int16 attlen; /* attr len in bytes or -1 = varlen, -2 = * cstring */ bool attbyval; /* as FormData_pg_attribute.attbyval */ - bool attispackable; /* FormData_pg_attribute.attstorage != - * TYPSTORAGE_PLAIN */ - bool atthasmissing; /* as FormData_pg_attribute.atthasmissing */ - bool attisdropped; /* as FormData_pg_attribute.attisdropped */ - bool attgenerated; /* FormData_pg_attribute.attgenerated != '\0' */ - char attnullability; /* status of not-null constraint, see below */ uint8 attalignby; /* alignment requirement in bytes */ + bool attispackable:1; /* FormData_pg_attribute.attstorage != + * TYPSTORAGE_PLAIN */ + bool atthasmissing:1; /* as FormData_pg_attribute.atthasmissing */ + bool attisdropped:1; /* as FormData_pg_attribute.attisdropped */ + bool attgenerated:1; /* FormData_pg_attribute.attgenerated != '\0' */ + char attnullability; /* status of not-null constraint, see below */ } CompactAttribute; /* Valid values for CompactAttribute->attnullability */ -- 2.51.0