From 8e1a945f172e3c6e9cc0092e5c2168151ed8c6d1 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Mon, 23 Feb 2026 09:39:37 +1300 Subject: [PATCH v12 5/6] 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 | 10 ++++++++++ src/backend/executor/execTuples.c | 17 ++++++++++++----- src/include/access/tupdesc.h | 16 ++++++++-------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index c68561337d7..71461ba6096 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -530,6 +530,16 @@ TupleDescFinalize(TupleDesc tupdesc) off = att_nominal_alignby(off, cattr->attalignby); + /* + * attcacheoff is an int16, so don't try to cache any offsets larger + * than will fit in that type. Any attributes which are offset more + * than 2^15 are likely due to variable-length attributes. Since we + * don't cache offsets for or beyond variable-length attributes, using + * an int16 rather than an int32 here is unlikely to cost us anything. + */ + if (off > PG_INT16_MAX) + break; + cattr->attcacheoff = off; off += cattr->attlen; diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 14b2a9f0af6..1b5e1ebd334 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; @@ -1099,6 +1100,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); @@ -1109,7 +1117,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, for (; attnum < firstNonGuaranteedAttr; attnum++) { isnull[attnum] = false; - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; attlen = cattr->attlen; /* We don't expect any non-byval types */ @@ -1149,9 +1157,8 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, for (; attnum < firstNonCacheOffsetAttr; attnum++) { isnull[attnum] = false; - cattr = TupleDescCompactAttr(tupleDesc, attnum); + cattr = &cattrs[attnum]; attlen = cattr->attlen; - off = cattr->attcacheoff; values[attnum] = fetch_att_noerr(tp + off, cattr->attbyval, @@ -1177,7 +1184,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; /* @@ -1210,7 +1217,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 ad7bc013812..e98036b58bf 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