From d022fc14b5c5a67dd538e2464d55c05c4a68dddd Mon Sep 17 00:00:00 2001 From: David Rowley Date: Tue, 28 May 2024 20:10:50 +1200 Subject: [PATCH v1 3/4] Use a compact struct to deform tuples --- contrib/amcheck/verify_heapam.c | 6 +-- contrib/pageinspect/heapfuncs.c | 4 +- contrib/postgres_fdw/postgres_fdw.c | 12 ++--- src/backend/access/brin/brin_inclusion.c | 18 +++---- src/backend/access/brin/brin_tuple.c | 4 +- src/backend/access/common/attmap.c | 14 +++-- src/backend/access/common/heaptuple.c | 60 +++++++++++---------- src/backend/access/common/indextuple.c | 28 +++++----- src/backend/access/common/tupdesc.c | 58 +++++++++++++++++--- src/backend/access/gin/ginbulk.c | 6 +-- src/backend/access/gin/ginget.c | 8 +-- src/backend/access/gist/gistbuild.c | 6 ++- src/backend/access/heap/heapam.c | 10 ++-- src/backend/access/heap/heapam_handler.c | 2 +- src/backend/access/heap/heaptoast.c | 6 +-- src/backend/access/nbtree/nbtutils.c | 6 +-- src/backend/access/spgist/spgdoinsert.c | 2 +- src/backend/access/table/toast_helper.c | 2 +- src/backend/catalog/index.c | 2 + src/backend/commands/copy.c | 6 +-- src/backend/commands/tablecmds.c | 5 ++ src/backend/executor/execExpr.c | 8 +-- src/backend/executor/execExprInterp.c | 8 +-- src/backend/executor/execJunk.c | 2 +- src/backend/executor/execTuples.c | 14 ++--- src/backend/executor/functions.c | 3 +- src/backend/executor/nodeMemoize.c | 12 ++--- src/backend/executor/nodeModifyTable.c | 8 +-- src/backend/executor/nodeValuesscan.c | 4 +- src/backend/executor/tstoreReceiver.c | 8 +-- src/backend/optimizer/util/plancat.c | 8 +-- src/backend/replication/pgoutput/pgoutput.c | 2 +- src/backend/utils/adt/expandedrecord.c | 22 ++++---- src/backend/utils/adt/ri_triggers.c | 4 +- src/backend/utils/cache/relcache.c | 12 +++++ src/include/access/htup_details.h | 8 +-- src/include/access/itup.h | 11 ++-- src/include/access/tupdesc.h | 52 ++++++++++++++++-- src/include/access/tupmacs.h | 2 + 39 files changed, 290 insertions(+), 163 deletions(-) diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c index f2526ed63a..125d594826 100644 --- a/contrib/amcheck/verify_heapam.c +++ b/contrib/amcheck/verify_heapam.c @@ -1567,11 +1567,11 @@ check_tuple_attribute(HeapCheckContext *ctx) struct varlena *attr; char *tp; /* pointer to the tuple data */ uint16 infomask; - Form_pg_attribute thisatt; + TupleDescDeformAttr *thisatt; struct varatt_external toast_pointer; infomask = ctx->tuphdr->t_infomask; - thisatt = TupleDescAttr(RelationGetDescr(ctx->rel), ctx->attnum); + thisatt = TupleDescDeformAttr(RelationGetDescr(ctx->rel), ctx->attnum); tp = (char *) ctx->tuphdr + ctx->tuphdr->t_hoff; @@ -1612,7 +1612,7 @@ check_tuple_attribute(HeapCheckContext *ctx) tp + ctx->offset); /* Get the (possibly corrupt) varlena datum */ - attdatum = fetchatt(thisatt, tp + ctx->offset); + attdatum = fetchatt_fast(thisatt, tp + ctx->offset); /* * We have the datum, but we cannot decode it carelessly, as it may still diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index 3faeabc711..e610aa69c6 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -331,11 +331,11 @@ tuple_data_split_internal(Oid relid, char *tupdata, for (i = 0; i < nattrs; i++) { - Form_pg_attribute attr; + TupleDescDeformAttr *attr; bool is_null; bytea *attr_data = NULL; - attr = TupleDescAttr(tupdesc, i); + attr = TupleDescDeformAttr(tupdesc, i); /* * Tuple header can specify fewer attributes than tuple descriptor as diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 0bb9a5ae8f..10906a1363 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1804,9 +1804,9 @@ postgresPlanForeignModify(PlannerInfo *root, for (attnum = 1; attnum <= tupdesc->natts; attnum++) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, attnum - 1); - if (!attr->attisdropped) + if (!DeformAttrIsDropped(attr)) targetAttrs = lappend_int(targetAttrs, attnum); } } @@ -2177,9 +2177,9 @@ postgresBeginForeignInsert(ModifyTableState *mtstate, /* We transmit all columns that are defined in the foreign table. */ for (attnum = 1; attnum <= tupdesc->natts; attnum++) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, attnum - 1); - if (!attr->attisdropped) + if (!DeformAttrIsDropped(attr)) targetAttrs = lappend_int(targetAttrs, attnum); } @@ -4291,12 +4291,12 @@ convert_prep_stmt_params(PgFdwModifyState *fmstate, foreach(lc, fmstate->target_attrs) { int attnum = lfirst_int(lc); - Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, attnum - 1); Datum value; bool isnull; /* Ignore generated columns; they are set to DEFAULT */ - if (attr->attgenerated) + if (DeformAttrIsGenerated(attr)) continue; value = slot_getattr(slots[i], attnum, &isnull); if (isnull) diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index 750276998c..289418706d 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -146,12 +146,12 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) Datum result; bool new = false; AttrNumber attno; - Form_pg_attribute attr; + TupleDescDeformAttr *attr; Assert(!isnull); attno = column->bv_attno; - attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); + attr = TupleDescDeformAttr(bdesc->bd_tupdesc, attno - 1); /* * If the recorded value is null, copy the new value (which we know to be @@ -160,7 +160,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) if (column->bv_allnulls) { column->bv_values[INCLUSION_UNION] = - datumCopy(newval, attr->attbyval, attr->attlen); + datumCopy(newval, DeformAttrByVal(attr), attr->attlen); column->bv_values[INCLUSION_UNMERGEABLE] = BoolGetDatum(false); column->bv_values[INCLUSION_CONTAINS_EMPTY] = BoolGetDatum(false); column->bv_allnulls = false; @@ -225,13 +225,13 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) Assert(finfo != NULL); result = FunctionCall2Coll(finfo, colloid, column->bv_values[INCLUSION_UNION], newval); - if (!attr->attbyval && + if (!DeformAttrByVal(attr) && DatumGetPointer(result) != DatumGetPointer(column->bv_values[INCLUSION_UNION])) { pfree(DatumGetPointer(column->bv_values[INCLUSION_UNION])); if (result == newval) - result = datumCopy(result, attr->attbyval, attr->attlen); + result = datumCopy(result, DeformAttrByVal(attr), attr->attlen); } column->bv_values[INCLUSION_UNION] = result; @@ -479,7 +479,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS) BrinValues *col_b = (BrinValues *) PG_GETARG_POINTER(2); Oid colloid = PG_GET_COLLATION(); AttrNumber attno; - Form_pg_attribute attr; + TupleDescDeformAttr *attr; FmgrInfo *finfo; Datum result; @@ -487,7 +487,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS) Assert(!col_a->bv_allnulls && !col_b->bv_allnulls); attno = col_a->bv_attno; - attr = TupleDescAttr(bdesc->bd_tupdesc, attno - 1); + attr = TupleDescDeformAttr(bdesc->bd_tupdesc, attno - 1); /* If B includes empty elements, mark A similarly, if needed. */ if (!DatumGetBool(col_a->bv_values[INCLUSION_CONTAINS_EMPTY]) && @@ -522,13 +522,13 @@ brin_inclusion_union(PG_FUNCTION_ARGS) result = FunctionCall2Coll(finfo, colloid, col_a->bv_values[INCLUSION_UNION], col_b->bv_values[INCLUSION_UNION]); - if (!attr->attbyval && + if (!DeformAttrByVal(attr) && DatumGetPointer(result) != DatumGetPointer(col_a->bv_values[INCLUSION_UNION])) { pfree(DatumGetPointer(col_a->bv_values[INCLUSION_UNION])); if (result == col_b->bv_values[INCLUSION_UNION]) - result = datumCopy(result, attr->attbyval, attr->attlen); + result = datumCopy(result, DeformAttrByVal(attr), attr->attlen); } col_a->bv_values[INCLUSION_UNION] = result; diff --git a/src/backend/access/brin/brin_tuple.c b/src/backend/access/brin/brin_tuple.c index 997eb6d822..213b873867 100644 --- a/src/backend/access/brin/brin_tuple.c +++ b/src/backend/access/brin/brin_tuple.c @@ -699,7 +699,7 @@ brin_deconstruct_tuple(BrinDesc *brdesc, datumno < brdesc->bd_info[attnum]->oi_nstored; datumno++) { - Form_pg_attribute thisatt = TupleDescAttr(diskdsc, stored); + TupleDescDeformAttr *thisatt = TupleDescDeformAttr(diskdsc, stored); if (thisatt->attlen == -1) { @@ -712,7 +712,7 @@ brin_deconstruct_tuple(BrinDesc *brdesc, off = att_align_nominal(off, thisatt->attalign); } - values[stored++] = fetchatt(thisatt, tp + off); + values[stored++] = fetchatt_fast(thisatt, tp + off); off = att_addlength_pointer(off, thisatt->attlen, tp + off); } diff --git a/src/backend/access/common/attmap.c b/src/backend/access/common/attmap.c index b0fe27ef57..a341f0bf50 100644 --- a/src/backend/access/common/attmap.c +++ b/src/backend/access/common/attmap.c @@ -135,7 +135,9 @@ build_attrmap_by_position(TupleDesc indesc, /* Check for unused input columns */ for (; j < indesc->natts; j++) { - if (TupleDescAttr(indesc, j)->attisdropped) + TupleDescDeformAttr *attr = TupleDescDeformAttr(indesc, j); + + if (DeformAttrIsDropped(attr)) continue; nincols++; same = false; /* we'll complain below */ @@ -299,25 +301,27 @@ check_attrmap_match(TupleDesc indesc, for (i = 0; i < attrMap->maplen; i++) { - Form_pg_attribute inatt = TupleDescAttr(indesc, i); - Form_pg_attribute outatt = TupleDescAttr(outdesc, i); + TupleDescDeformAttr *inatt = TupleDescDeformAttr(indesc, i); + TupleDescDeformAttr *outatt; /* * If the input column has a missing attribute, we need a conversion. */ - if (inatt->atthasmissing) + if (DeformAttrHasMissing(inatt)) return false; if (attrMap->attnums[i] == (i + 1)) continue; + outatt = TupleDescDeformAttr(outdesc, i); + /* * If it's a dropped column and the corresponding input column is also * dropped, we don't need a conversion. However, attlen and attalign * must agree. */ if (attrMap->attnums[i] == 0 && - inatt->attisdropped && + DeformAttrIsDropped(inatt) && inatt->attlen == outatt->attlen && inatt->attalign == outatt->attalign) continue; diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 9e3407bf98..963b88c27b 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -83,6 +83,9 @@ #define VARLENA_ATT_IS_PACKABLE(att) \ ((att)->attstorage != TYPSTORAGE_PLAIN) +#define ATT_IS_PACKABLE_FAST(att) \ + ((att)->attlen == -1 && DeformAttrIsPackable(att)) + /* * Setup for caching pass-by-ref missing attributes in a way that survives * tupleDesc destruction. @@ -147,14 +150,14 @@ Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull) { - Form_pg_attribute att; + TupleDescDeformAttr *att; Assert(attnum <= tupleDesc->natts); Assert(attnum > 0); - att = TupleDescAttr(tupleDesc, attnum - 1); + att = TupleDescDeformAttr(tupleDesc, attnum - 1); - if (att->atthasmissing) + if (DeformAttrHasMissing(att)) { AttrMissing *attrmiss; @@ -173,7 +176,7 @@ getmissingattr(TupleDesc tupleDesc, *isnull = false; /* no need to cache by-value attributes */ - if (att->attbyval) + if (DeformAttrByVal(att)) return attrmiss->am_value; /* set up cache if required */ @@ -223,15 +226,15 @@ heap_compute_data_size(TupleDesc tupleDesc, for (i = 0; i < numberOfAttributes; i++) { Datum val; - Form_pg_attribute atti; + TupleDescDeformAttr *atti; if (isnull[i]) continue; val = values[i]; - atti = TupleDescAttr(tupleDesc, i); + atti = TupleDescDeformAttr(tupleDesc, i); - if (ATT_IS_PACKABLE(atti) && + if (ATT_IS_PACKABLE_FAST(atti) && VARATT_CAN_MAKE_SHORT(DatumGetPointer(val))) { /* @@ -268,7 +271,7 @@ heap_compute_data_size(TupleDesc tupleDesc, * Fill in either a data value or a bit in the null bitmask */ static inline void -fill_val(Form_pg_attribute att, +fill_val(TupleDescDeformAttr *att, bits8 **bit, int *bitmask, char **dataP, @@ -307,7 +310,7 @@ fill_val(Form_pg_attribute att, * XXX we use the att_align macros on the pointer value itself, not on an * offset. This is a bit of a hack. */ - if (att->attbyval) + if (DeformAttrByVal(att)) { /* pass-by-value */ data = (char *) att_align_nominal(data, att->attalign); @@ -349,7 +352,7 @@ fill_val(Form_pg_attribute att, data_length = VARSIZE_SHORT(val); memcpy(data, val, data_length); } - else if (VARLENA_ATT_IS_PACKABLE(att) && + else if (DeformAttrIsPackable(att) && VARATT_CAN_MAKE_SHORT(val)) { /* convert to short varlena -- no alignment */ @@ -427,7 +430,7 @@ heap_fill_tuple(TupleDesc tupleDesc, for (i = 0; i < numberOfAttributes; i++) { - Form_pg_attribute attr = TupleDescAttr(tupleDesc, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupleDesc, i); fill_val(attr, bitP ? &bitP : NULL, @@ -461,7 +464,8 @@ heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc) Assert(!tupleDesc || attnum <= tupleDesc->natts); if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data)) { - if (tupleDesc && TupleDescAttr(tupleDesc, attnum - 1)->atthasmissing) + if (tupleDesc && + DeformAttrHasMissing(TupleDescDeformAttr(tupleDesc, attnum - 1))) return false; else return true; @@ -570,15 +574,15 @@ nocachegetattr(HeapTuple tup, if (!slow) { - Form_pg_attribute att; + TupleDescDeformAttr *att; /* * If we get here, there are no nulls up to and including the target * attribute. If we have a cached offset, we can use it. */ - att = TupleDescAttr(tupleDesc, attnum); + att = TupleDescDeformAttr(tupleDesc, attnum); if (att->attcacheoff >= 0) - return fetchatt(att, tp + att->attcacheoff); + return fetchatt_fast(att, tp + att->attcacheoff); /* * Otherwise, check for non-fixed-length attrs up to and including @@ -591,7 +595,7 @@ nocachegetattr(HeapTuple tup, for (j = 0; j <= attnum; j++) { - if (TupleDescAttr(tupleDesc, j)->attlen <= 0) + if (TupleDescDeformAttr(tupleDesc, j)->attlen <= 0) { slow = true; break; @@ -614,18 +618,18 @@ nocachegetattr(HeapTuple tup, * fixed-width columns, in hope of avoiding future visits to this * routine. */ - TupleDescAttr(tupleDesc, 0)->attcacheoff = 0; + TupleDescDeformAttr(tupleDesc, 0)->attcacheoff = 0; /* we might have set some offsets in the slow path previously */ - while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0) + while (j < natts && TupleDescDeformAttr(tupleDesc, j)->attcacheoff > 0) j++; - off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff + - TupleDescAttr(tupleDesc, j - 1)->attlen; + off = TupleDescDeformAttr(tupleDesc, j - 1)->attcacheoff + + TupleDescDeformAttr(tupleDesc, j - 1)->attlen; for (; j < natts; j++) { - Form_pg_attribute att = TupleDescAttr(tupleDesc, j); + TupleDescDeformAttr *att = TupleDescDeformAttr(tupleDesc, j); if (att->attlen <= 0) break; @@ -639,7 +643,7 @@ nocachegetattr(HeapTuple tup, Assert(j > attnum); - off = TupleDescAttr(tupleDesc, attnum)->attcacheoff; + off = TupleDescDeformAttr(tupleDesc, attnum)->attcacheoff; } else { @@ -659,7 +663,7 @@ nocachegetattr(HeapTuple tup, off = 0; for (i = 0;; i++) /* loop exit is at "break" */ { - Form_pg_attribute att = TupleDescAttr(tupleDesc, i); + TupleDescDeformAttr *att = TupleDescDeformAttr(tupleDesc, i); if (HeapTupleHasNulls(tup) && att_isnull(i, bp)) { @@ -707,7 +711,7 @@ nocachegetattr(HeapTuple tup, } } - return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off); + return fetchatt_fast(TupleDescDeformAttr(tupleDesc, attnum), tp + off); } /* ---------------- @@ -892,7 +896,7 @@ expand_tuple(HeapTuple *targetHeapTuple, { if (attrmiss[attnum].am_present) { - Form_pg_attribute att = TupleDescAttr(tupleDesc, attnum); + TupleDescDeformAttr *att = TupleDescDeformAttr(tupleDesc, attnum); targetDataLen = att_align_datum(targetDataLen, att->attalign, @@ -1021,7 +1025,7 @@ expand_tuple(HeapTuple *targetHeapTuple, for (attnum = sourceNatts; attnum < natts; attnum++) { - Form_pg_attribute attr = TupleDescAttr(tupleDesc, attnum); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupleDesc, attnum); if (attrmiss && attrmiss[attnum].am_present) { @@ -1370,7 +1374,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, for (attnum = 0; attnum < natts; attnum++) { - Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum); + TupleDescDeformAttr *thisatt = TupleDescDeformAttr(tupleDesc, attnum); if (hasnulls && att_isnull(attnum, bp)) { @@ -1411,7 +1415,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, thisatt->attcacheoff = off; } - values[attnum] = fetchatt(thisatt, tp + off); + values[attnum] = fetchatt_fast(thisatt, tp + off); off = att_addlength_pointer(off, thisatt->attlen, tp + off); diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c index 79ae29989d..aac4214cc7 100644 --- a/src/backend/access/common/indextuple.c +++ b/src/backend/access/common/indextuple.c @@ -303,15 +303,15 @@ nocache_index_getattr(IndexTuple tup, if (!slow) { - Form_pg_attribute att; + TupleDescDeformAttr *att; /* * If we get here, there are no nulls up to and including the target * attribute. If we have a cached offset, we can use it. */ - att = TupleDescAttr(tupleDesc, attnum); + att = TupleDescDeformAttr(tupleDesc, attnum); if (att->attcacheoff >= 0) - return fetchatt(att, tp + att->attcacheoff); + return fetchatt_fast(att, tp + att->attcacheoff); /* * Otherwise, check for non-fixed-length attrs up to and including @@ -324,7 +324,7 @@ nocache_index_getattr(IndexTuple tup, for (j = 0; j <= attnum; j++) { - if (TupleDescAttr(tupleDesc, j)->attlen <= 0) + if (TupleDescDeformAttr(tupleDesc, j)->attlen <= 0) { slow = true; break; @@ -347,18 +347,18 @@ nocache_index_getattr(IndexTuple tup, * fixed-width columns, in hope of avoiding future visits to this * routine. */ - TupleDescAttr(tupleDesc, 0)->attcacheoff = 0; + TupleDescDeformAttr(tupleDesc, 0)->attcacheoff = 0; /* we might have set some offsets in the slow path previously */ - while (j < natts && TupleDescAttr(tupleDesc, j)->attcacheoff > 0) + while (j < natts && TupleDescDeformAttr(tupleDesc, j)->attcacheoff > 0) j++; - off = TupleDescAttr(tupleDesc, j - 1)->attcacheoff + - TupleDescAttr(tupleDesc, j - 1)->attlen; + off = TupleDescDeformAttr(tupleDesc, j - 1)->attcacheoff + + TupleDescDeformAttr(tupleDesc, j - 1)->attlen; for (; j < natts; j++) { - Form_pg_attribute att = TupleDescAttr(tupleDesc, j); + TupleDescDeformAttr *att = TupleDescDeformAttr(tupleDesc, j); if (att->attlen <= 0) break; @@ -372,7 +372,7 @@ nocache_index_getattr(IndexTuple tup, Assert(j > attnum); - off = TupleDescAttr(tupleDesc, attnum)->attcacheoff; + off = TupleDescDeformAttr(tupleDesc, attnum)->attcacheoff; } else { @@ -392,7 +392,7 @@ nocache_index_getattr(IndexTuple tup, off = 0; for (i = 0;; i++) /* loop exit is at "break" */ { - Form_pg_attribute att = TupleDescAttr(tupleDesc, i); + TupleDescDeformAttr *att = TupleDescDeformAttr(tupleDesc, i); if (IndexTupleHasNulls(tup) && att_isnull(i, bp)) { @@ -440,7 +440,7 @@ nocache_index_getattr(IndexTuple tup, } } - return fetchatt(TupleDescAttr(tupleDesc, attnum), tp + off); + return fetchatt_fast(TupleDescDeformAttr(tupleDesc, attnum), tp + off); } /* @@ -490,7 +490,7 @@ index_deform_tuple_internal(TupleDesc tupleDescriptor, for (attnum = 0; attnum < natts; attnum++) { - Form_pg_attribute thisatt = TupleDescAttr(tupleDescriptor, attnum); + TupleDescDeformAttr *thisatt = TupleDescDeformAttr(tupleDescriptor, attnum); if (hasnulls && att_isnull(attnum, bp)) { @@ -531,7 +531,7 @@ index_deform_tuple_internal(TupleDesc tupleDescriptor, thisatt->attcacheoff = off; } - values[attnum] = fetchatt(thisatt, tp + off); + values[attnum] = fetchatt_fast(thisatt, tp + off); off = att_addlength_pointer(off, thisatt->attlen, tp + off); diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index fba0026520..ee996f465a 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -56,6 +56,30 @@ ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc) ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc); } +void +populate_TupleDescAttr(TupleDescDeformAttr *dst, Form_pg_attribute src) +{ + dst->attcacheoff = -1; + dst->attlen = src->attlen; + + dst->attflags = 0; + + if (src->attbyval) + dst->attflags |= DEFORM_ATTR_FLAG_BYVAL; + if (src->attstorage != TYPSTORAGE_PLAIN) + dst->attflags |= DEFORM_ATTR_FLAG_IS_PACKABLE; + if (src->atthasmissing) + dst->attflags |= DEFORM_ATTR_FLAG_HAS_MISSING; + if (src->attisdropped) + dst->attflags |= DEFORM_ATTR_FLAG_IS_DROPPED; + if (src->attgenerated) + dst->attflags |= DEFORM_ATTR_FLAG_IS_GENERATED; + if (src->attnotnull) + dst->attflags |= DEFORM_ATTR_FLAG_IS_NOTNULL; + + dst->attalign = src->attalign; +} + /* * CreateTemplateTupleDesc * This function allocates an empty tuple descriptor structure. @@ -85,7 +109,8 @@ CreateTemplateTupleDesc(int natts) * could be less due to trailing padding, although with the current * definition of pg_attribute there probably isn't any padding. */ - desc = (TupleDesc) palloc(MAXALIGN(sizeof(TupleDescData)) + + desc = (TupleDesc) palloc(offsetof(struct TupleDescData, deform_attrs) + + natts * sizeof(TupleDescDeformAttr) + natts * sizeof(FormData_pg_attribute)); /* @@ -118,8 +143,11 @@ CreateTupleDesc(int natts, Form_pg_attribute *attrs) desc = CreateTemplateTupleDesc(natts); for (i = 0; i < natts; ++i) + { memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE); - + populate_TupleDescAttr(TupleDescDeformAttr(desc, i), + TupleDescAttr(desc, i)); + } return desc; } @@ -156,6 +184,9 @@ CreateTupleDescCopy(TupleDesc tupdesc) att->atthasmissing = false; att->attidentity = '\0'; att->attgenerated = '\0'; + + populate_TupleDescAttr(TupleDescDeformAttr(desc, i), + TupleDescAttr(desc, i)); } /* We can copy the tuple type identification, too */ @@ -184,6 +215,10 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) TupleDescAttr(tupdesc, 0), desc->natts * sizeof(FormData_pg_attribute)); + for (i = 0; i < desc->natts; i++) + populate_TupleDescAttr(TupleDescDeformAttr(desc, i), + TupleDescAttr(desc, i)); + /* Copy the TupleConstr data structure, if any */ if (constr) { @@ -208,10 +243,10 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) { if (constr->missing[i].am_present) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, i); cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value, - attr->attbyval, + DeformAttrByVal(attr), attr->attlen); } } @@ -275,6 +310,9 @@ TupleDescCopy(TupleDesc dst, TupleDesc src) att->atthasmissing = false; att->attidentity = '\0'; att->attgenerated = '\0'; + + populate_TupleDescAttr(TupleDescDeformAttr(dst, i), + TupleDescAttr(dst, i)); } dst->constr = NULL; @@ -329,6 +367,8 @@ TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, dstAtt->atthasmissing = false; dstAtt->attidentity = '\0'; dstAtt->attgenerated = '\0'; + + populate_TupleDescAttr(TupleDescDeformAttr(dst, dstAttno - 1), dstAtt); } /* @@ -528,10 +568,10 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) return false; if (missval1->am_present) { - Form_pg_attribute missatt1 = TupleDescAttr(tupdesc1, i); + TupleDescDeformAttr *missatt1 = TupleDescDeformAttr(tupdesc1, i); if (!datumIsEqual(missval1->am_value, missval2->am_value, - missatt1->attbyval, missatt1->attlen)) + DeformAttrByVal(missatt1), missatt1->attlen)) return false; } } @@ -721,6 +761,9 @@ TupleDescInitEntry(TupleDesc desc, att->attcompression = InvalidCompressionMethod; att->attcollation = typeForm->typcollation; + populate_TupleDescAttr(TupleDescDeformAttr(desc, attributeNumber - 1), + att); + ReleaseSysCache(tuple); } @@ -828,6 +871,9 @@ TupleDescInitBuiltinEntry(TupleDesc desc, default: elog(ERROR, "unsupported type %u", oidtypeid); } + + populate_TupleDescAttr(TupleDescDeformAttr(desc, attributeNumber - 1), + att); } /* diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c index 7f89cd5e82..c2c03261fa 100644 --- a/src/backend/access/gin/ginbulk.c +++ b/src/backend/access/gin/ginbulk.c @@ -127,11 +127,11 @@ ginInitBA(BuildAccumulator *accum) static Datum getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value) { - Form_pg_attribute att; + TupleDescDeformAttr *att; Datum res; - att = TupleDescAttr(accum->ginstate->origTupdesc, attnum - 1); - if (att->attbyval) + att = TupleDescDeformAttr(accum->ginstate->origTupdesc, attnum - 1); + if (DeformAttrByVal(att)) res = value; else { diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 0b4f2ebadb..d869cf2d77 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -122,7 +122,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack, GinScanEntry scanEntry, Snapshot snapshot) { OffsetNumber attnum; - Form_pg_attribute attr; + TupleDescDeformAttr *attr; /* Initialize empty bitmap result */ scanEntry->matchBitmap = tbm_create(work_mem * 1024L, NULL); @@ -134,7 +134,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack, /* Locate tupdesc entry for key column (for attbyval/attlen data) */ attnum = scanEntry->attnum; - attr = TupleDescAttr(btree->ginstate->origTupdesc, attnum - 1); + attr = TupleDescDeformAttr(btree->ginstate->origTupdesc, attnum - 1); /* * Predicate lock entry leaf page, following pages will be locked by @@ -232,7 +232,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack, * tuple after re-locking */ if (icategory == GIN_CAT_NORM_KEY) - idatum = datumCopy(idatum, attr->attbyval, attr->attlen); + idatum = datumCopy(idatum, DeformAttrByVal(attr), attr->attlen); LockBuffer(stack->buffer, GIN_UNLOCK); @@ -291,7 +291,7 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack, stack->off++; } - if (icategory == GIN_CAT_NORM_KEY && !attr->attbyval) + if (icategory == GIN_CAT_NORM_KEY && !DeformAttrByVal(attr)) pfree(DatumGetPointer(idatum)); } else diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index ba06df30fa..0779948dbd 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -657,10 +657,12 @@ gistInitBuffering(GISTBuildState *buildstate) itupMinSize = (Size) MAXALIGN(sizeof(IndexTupleData)); for (i = 0; i < index->rd_att->natts; i++) { - if (TupleDescAttr(index->rd_att, i)->attlen < 0) + TupleDescDeformAttr *attr = TupleDescDeformAttr(index->rd_att, i); + + if (attr->attlen < 0) itupMinSize += VARHDRSZ; else - itupMinSize += TupleDescAttr(index->rd_att, i)->attlen; + itupMinSize += attr->attlen; } /* Calculate average and maximal number of index tuples which fit to page */ diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 91b20147a0..205e601642 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -4080,8 +4080,6 @@ static bool heap_attr_equals(TupleDesc tupdesc, int attrnum, Datum value1, Datum value2, bool isnull1, bool isnull2) { - Form_pg_attribute att; - /* * If one value is NULL and other is not, then they are certainly not * equal @@ -4111,9 +4109,11 @@ heap_attr_equals(TupleDesc tupdesc, int attrnum, Datum value1, Datum value2, } else { + TupleDescDeformAttr *att; + Assert(attrnum <= tupdesc->natts); - att = TupleDescAttr(tupdesc, attrnum - 1); - return datumIsEqual(value1, value2, att->attbyval, att->attlen); + att = TupleDescDeformAttr(tupdesc, attrnum - 1); + return datumIsEqual(value1, value2, DeformAttrByVal(att), att->attlen); } } @@ -4194,7 +4194,7 @@ HeapDetermineColumnsInfo(Relation relation, * that system attributes can't be stored externally. */ if (attrnum < 0 || isnull1 || - TupleDescAttr(tupdesc, attrnum - 1)->attlen != -1) + TupleDescDeformAttr(tupdesc, attrnum - 1)->attlen != -1) continue; /* diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 6f8b1b7929..16d6a62ee1 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2524,7 +2524,7 @@ reform_and_rewrite_tuple(HeapTuple tuple, /* Be sure to null out any dropped columns */ for (i = 0; i < newTupDesc->natts; i++) { - if (TupleDescAttr(newTupDesc, i)->attisdropped) + if (DeformAttrIsDropped(TupleDescDeformAttr(newTupDesc, i))) isnull[i] = true; } diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index a420e16530..ffc8d15d31 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -369,7 +369,7 @@ toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc) /* * Look at non-null varlena attributes */ - if (!toast_isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1) + if (!toast_isnull[i] && TupleDescDeformAttr(tupleDesc, i)->attlen == -1) { struct varlena *new_value; @@ -483,7 +483,7 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup, */ if (toast_isnull[i]) has_nulls = true; - else if (TupleDescAttr(tupleDesc, i)->attlen == -1) + else if (TupleDescDeformAttr(tupleDesc, i)->attlen == -1) { struct varlena *new_value; @@ -584,7 +584,7 @@ toast_build_flattened_tuple(TupleDesc tupleDesc, /* * Look at non-null varlena attributes */ - if (!isnull[i] && TupleDescAttr(tupleDesc, i)->attlen == -1) + if (!isnull[i] && TupleDescDeformAttr(tupleDesc, i)->attlen == -1) { struct varlena *new_value; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index d6de2072d4..bfc9daff41 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -4874,17 +4874,17 @@ _bt_keep_natts_fast(Relation rel, IndexTuple lastleft, IndexTuple firstright) datum2; bool isNull1, isNull2; - Form_pg_attribute att; + TupleDescDeformAttr *att; datum1 = index_getattr(lastleft, attnum, itupdesc, &isNull1); datum2 = index_getattr(firstright, attnum, itupdesc, &isNull2); - att = TupleDescAttr(itupdesc, attnum - 1); + att = TupleDescDeformAttr(itupdesc, attnum - 1); if (isNull1 != isNull2) break; if (!isNull1 && - !datum_image_eq(datum1, datum2, att->attbyval, att->attlen)) + !datum_image_eq(datum1, datum2, DeformAttrByVal(att), att->attlen)) break; keepnatts++; diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c index a4995c168b..1cac593ec4 100644 --- a/src/backend/access/spgist/spgdoinsert.c +++ b/src/backend/access/spgist/spgdoinsert.c @@ -1974,7 +1974,7 @@ spgdoinsert(Relation index, SpGistState *state, { if (!isnulls[i]) { - if (TupleDescAttr(leafDescriptor, i)->attlen == -1) + if (TupleDescDeformAttr(leafDescriptor, i)->attlen == -1) leafDatums[i] = PointerGetDatum(PG_DETOAST_DATUM(datums[i])); else leafDatums[i] = datums[i]; diff --git a/src/backend/access/table/toast_helper.c b/src/backend/access/table/toast_helper.c index 53224932f0..361f0cbd88 100644 --- a/src/backend/access/table/toast_helper.c +++ b/src/backend/access/table/toast_helper.c @@ -324,7 +324,7 @@ toast_delete_external(Relation rel, const Datum *values, const bool *isnull, for (i = 0; i < numAttrs; i++) { - if (TupleDescAttr(tupleDesc, i)->attlen == -1) + if (TupleDescDeformAttr(tupleDesc, i)->attlen == -1) { Datum value = values[i]; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index a819b4197c..b59ba2b45c 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -477,6 +477,8 @@ ConstructTupleDescriptor(Relation heapRelation, ReleaseSysCache(tuple); } + + populate_TupleDescAttr(TupleDescDeformAttr(indexTupDesc, i), to); } pfree(amroutine); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index df7a4a21c9..ecd2044a15 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -867,9 +867,9 @@ CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) for (i = 0; i < attr_count; i++) { - if (TupleDescAttr(tupDesc, i)->attisdropped) - continue; - if (TupleDescAttr(tupDesc, i)->attgenerated) + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupDesc, i); + + if (DeformAttrIsDropped(attr) || DeformAttrIsGenerated(attr)) continue; attnums = lappend_int(attnums, i + 1); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 8fcb188323..96034cdefc 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -944,6 +944,9 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, cookedDefaults = lappend(cookedDefaults, cooked); attr->atthasdef = true; } + + populate_TupleDescAttr(TupleDescDeformAttr(descriptor, attnum - 1), + attr); } /* @@ -1350,6 +1353,8 @@ BuildDescForRelation(const List *columns) att->attstorage = entry->storage; else if (entry->storage_name) att->attstorage = GetAttributeStorage(att->atttypid, entry->storage_name); + + populate_TupleDescAttr(TupleDescDeformAttr(desc, attnum - 1), att); } if (has_not_null) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index ccd4863778..4d87186ce9 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -594,9 +594,9 @@ ExecBuildUpdateProjection(List *targetList, */ for (int attnum = relDesc->natts; attnum > 0; attnum--) { - Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(relDesc, attnum - 1); - if (attr->attisdropped) + if (DeformAttrIsDropped(attr)) continue; if (bms_is_member(attnum, assignedCols)) continue; @@ -690,9 +690,9 @@ ExecBuildUpdateProjection(List *targetList, */ for (int attnum = 1; attnum <= relDesc->natts; attnum++) { - Form_pg_attribute attr = TupleDescAttr(relDesc, attnum - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(relDesc, attnum - 1); - if (attr->attisdropped) + if (DeformAttrIsDropped(attr)) { /* Put a null into the ExprState's resvalue/resnull ... */ scratch.opcode = EEOP_CONST; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index d8735286c4..22440cd10b 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -2798,7 +2798,7 @@ ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op, for (int att = 1; att <= tupDesc->natts; att++) { /* ignore dropped columns */ - if (TupleDescAttr(tupDesc, att - 1)->attisdropped) + if (DeformAttrIsDropped(TupleDescDeformAttr(tupDesc, att - 1))) continue; if (heap_attisnull(&tmptup, att, tupDesc)) { @@ -4838,10 +4838,10 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) for (int i = 0; i < var_tupdesc->natts; i++) { - Form_pg_attribute vattr = TupleDescAttr(var_tupdesc, i); - Form_pg_attribute sattr = TupleDescAttr(tupleDesc, i); + TupleDescDeformAttr *vattr = TupleDescDeformAttr(var_tupdesc, i); + TupleDescDeformAttr *sattr = TupleDescDeformAttr(tupleDesc, i); - if (!vattr->attisdropped) + if (!DeformAttrIsDropped(vattr)) continue; /* already checked non-dropped cols */ if (slot->tts_isnull[i]) continue; /* null is always okay */ diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index b962c31383..bff4213a6c 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -169,7 +169,7 @@ ExecInitJunkFilterConversion(List *targetList, t = list_head(targetList); for (i = 0; i < cleanLength; i++) { - if (TupleDescAttr(cleanTupType, i)->attisdropped) + if (DeformAttrIsDropped(TupleDescDeformAttr(cleanTupType, i))) continue; /* map entry is already zero */ for (;;) { diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 00dc339615..e651934918 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -187,10 +187,10 @@ tts_virtual_materialize(TupleTableSlot *slot) /* compute size of memory required */ for (int natt = 0; natt < desc->natts; natt++) { - Form_pg_attribute att = TupleDescAttr(desc, natt); + TupleDescDeformAttr *att = TupleDescDeformAttr(desc, natt); Datum val; - if (att->attbyval || slot->tts_isnull[natt]) + if (DeformAttrByVal(att) || slot->tts_isnull[natt]) continue; val = slot->tts_values[natt]; @@ -223,10 +223,10 @@ tts_virtual_materialize(TupleTableSlot *slot) /* and copy all attributes into the pre-allocated space */ for (int natt = 0; natt < desc->natts; natt++) { - Form_pg_attribute att = TupleDescAttr(desc, natt); + TupleDescDeformAttr *att = TupleDescDeformAttr(desc, natt); Datum val; - if (att->attbyval || slot->tts_isnull[natt]) + if (DeformAttrByVal(att) || slot->tts_isnull[natt]) continue; val = slot->tts_values[natt]; @@ -1044,7 +1044,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, for (; attnum < natts; attnum++) { - Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum); + TupleDescDeformAttr *thisatt = TupleDescDeformAttr(tupleDesc, attnum); if (hasnulls && att_isnull(attnum, bp)) { @@ -1085,7 +1085,7 @@ slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp, thisatt->attcacheoff = off; } - values[attnum] = fetchatt(thisatt, tp + off); + values[attnum] = fetchatt_fast(thisatt, tp + off); off = att_addlength_pointer(off, thisatt->attlen, tp + off); @@ -2237,7 +2237,7 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values) */ for (i = 0; i < natts; i++) { - if (!TupleDescAttr(tupdesc, i)->attisdropped) + if (!DeformAttrIsDropped(TupleDescDeformAttr(tupdesc, i))) { /* Non-dropped attributes */ dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i], diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 539cd0a999..7cd37fde34 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -1885,7 +1885,8 @@ check_sql_fn_retval(List *queryTreeLists, /* remaining columns in rettupdesc had better all be dropped */ for (colindex++; colindex <= tupnatts; colindex++) { - if (!TupleDescAttr(rettupdesc, colindex - 1)->attisdropped) + if (!DeformAttrIsDropped(TupleDescDeformAttr(rettupdesc, + colindex - 1))) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("return type mismatch in function declared to return %s", diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c index df8e3fff08..d73a4bb0c2 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -175,12 +175,12 @@ MemoizeHash_hash(struct memoize_hash *tb, const MemoizeKey *key) if (!pslot->tts_isnull[i]) /* treat nulls as having hash key 0 */ { - Form_pg_attribute attr; + TupleDescDeformAttr *attr; uint32 hkey; - attr = TupleDescAttr(pslot->tts_tupleDescriptor, i); + attr = TupleDescDeformAttr(pslot->tts_tupleDescriptor, i); - hkey = datum_image_hash(pslot->tts_values[i], attr->attbyval, attr->attlen); + hkey = datum_image_hash(pslot->tts_values[i], DeformAttrByVal(attr), attr->attlen); hashkey ^= hkey; } @@ -242,7 +242,7 @@ MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1, for (int i = 0; i < numkeys; i++) { - Form_pg_attribute attr; + TupleDescDeformAttr *attr; if (tslot->tts_isnull[i] != pslot->tts_isnull[i]) { @@ -255,9 +255,9 @@ MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1, continue; /* perform binary comparison on the two datums */ - attr = TupleDescAttr(tslot->tts_tupleDescriptor, i); + attr = TupleDescDeformAttr(tslot->tts_tupleDescriptor, i); if (!datum_image_eq(tslot->tts_values[i], pslot->tts_values[i], - attr->attbyval, attr->attlen)) + DeformAttrByVal(attr), attr->attlen)) { match = false; break; diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index a2442b7b0d..bf8d1e9702 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -495,14 +495,14 @@ ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, for (int i = 0; i < natts; i++) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, i); if (ri_GeneratedExprs[i]) { Datum val; bool isnull; - Assert(attr->attgenerated == ATTRIBUTE_GENERATED_STORED); + Assert(TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED); econtext->ecxt_scantuple = slot; @@ -513,7 +513,7 @@ ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, * memory for a pass-by-reference Datum is located. */ if (!isnull) - val = datumCopy(val, attr->attbyval, attr->attlen); + val = datumCopy(val, DeformAttrByVal(attr), attr->attlen); values[i] = val; nulls[i] = isnull; @@ -521,7 +521,7 @@ ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo, else { if (!nulls[i]) - values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen); + values[i] = datumCopy(slot->tts_values[i], DeformAttrByVal(attr), attr->attlen); } } diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index 92948917a0..2ab8c52ead 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -142,8 +142,8 @@ ValuesNext(ValuesScanState *node) foreach(lc, exprstatelist) { ExprState *estate = (ExprState *) lfirst(lc); - Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor, - resind); + TupleDescDeformAttr *attr = TupleDescDeformAttr(slot->tts_tupleDescriptor, + resind); values[resind] = ExecEvalExpr(estate, econtext, diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index de4646b5c2..616530b5b6 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -65,9 +65,9 @@ tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo) { for (i = 0; i < natts; i++) { - Form_pg_attribute attr = TupleDescAttr(typeinfo, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(typeinfo, i); - if (attr->attisdropped) + if (DeformAttrIsDropped(attr)) continue; if (attr->attlen == -1) { @@ -154,9 +154,9 @@ tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self) for (i = 0; i < natts; i++) { Datum val = slot->tts_values[i]; - Form_pg_attribute attr = TupleDescAttr(typeinfo, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(typeinfo, i); - if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i]) + if (!DeformAttrIsDropped(attr) && attr->attlen == -1 && !slot->tts_isnull[i]) { if (VARATT_IS_EXTERNAL(DatumGetPointer(val))) { diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 9efdd844aa..5e1c452753 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -174,19 +174,19 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, { for (int i = 0; i < relation->rd_att->natts; i++) { - Form_pg_attribute attr = TupleDescAttr(relation->rd_att, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(relation->rd_att, i); - if (attr->attnotnull) + if (DeformAttrIsNotNull(attr)) { rel->notnullattnums = bms_add_member(rel->notnullattnums, - attr->attnum); + i + 1); /* * Per RemoveAttributeById(), dropped columns will have their * attnotnull unset, so we needn't check for dropped columns * in the above condition. */ - Assert(!attr->attisdropped); + Assert(!DeformAttrIsDropped(attr)); } } } diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c index abef4eaf68..02d0211911 100644 --- a/src/backend/replication/pgoutput/pgoutput.c +++ b/src/backend/replication/pgoutput/pgoutput.c @@ -1305,7 +1305,7 @@ pgoutput_row_filter(Relation relation, TupleTableSlot *old_slot, */ for (i = 0; i < desc->natts; i++) { - Form_pg_attribute att = TupleDescAttr(desc, i); + TupleDescDeformAttr *att = TupleDescDeformAttr(desc, i); /* * if the column in the new tuple or old tuple is null, nothing to do diff --git a/src/backend/utils/adt/expandedrecord.c b/src/backend/utils/adt/expandedrecord.c index 7e85ae3825..d0b28d48fb 100644 --- a/src/backend/utils/adt/expandedrecord.c +++ b/src/backend/utils/adt/expandedrecord.c @@ -699,10 +699,10 @@ ER_get_flat_size(ExpandedObjectHeader *eohptr) { for (i = 0; i < erh->nfields; i++) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, i); if (!erh->dnulls[i] && - !attr->attbyval && attr->attlen == -1 && + !DeformAttrByVal(attr) && attr->attlen == -1 && VARATT_IS_EXTERNAL(DatumGetPointer(erh->dvalues[i]))) { /* @@ -1115,7 +1115,7 @@ expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, bool check_constraints) { TupleDesc tupdesc; - Form_pg_attribute attr; + TupleDescDeformAttr *attr; Datum *dvalues; bool *dnulls; char *oldValue; @@ -1146,8 +1146,8 @@ expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, * Copy new field value into record's context, and deal with detoasting, * if needed. */ - attr = TupleDescAttr(tupdesc, fnumber - 1); - if (!isnull && !attr->attbyval) + attr = TupleDescDeformAttr(tupdesc, fnumber - 1); + if (!isnull && !DeformAttrByVal(attr)) { MemoryContext oldcxt; @@ -1201,7 +1201,7 @@ expanded_record_set_field_internal(ExpandedRecordHeader *erh, int fnumber, erh->flat_size = 0; /* Grab old field value for pfree'ing, if needed. */ - if (!attr->attbyval && !dnulls[fnumber - 1]) + if (!DeformAttrByVal(attr) && !dnulls[fnumber - 1]) oldValue = (char *) DatumGetPointer(dvalues[fnumber - 1]); else oldValue = NULL; @@ -1279,18 +1279,18 @@ expanded_record_set_fields(ExpandedRecordHeader *erh, for (fnumber = 0; fnumber < erh->nfields; fnumber++) { - Form_pg_attribute attr = TupleDescAttr(tupdesc, fnumber); + TupleDescDeformAttr *attr = TupleDescDeformAttr(tupdesc, fnumber); Datum newValue; bool isnull; /* Ignore dropped columns */ - if (attr->attisdropped) + if (DeformAttrIsDropped(attr)) continue; newValue = newValues[fnumber]; isnull = isnulls[fnumber]; - if (!attr->attbyval) + if (!DeformAttrByVal(attr)) { /* * Copy new field value into record's context, and deal with @@ -1541,9 +1541,9 @@ check_domain_for_new_field(ExpandedRecordHeader *erh, int fnumber, */ if (!isnull) { - Form_pg_attribute attr = TupleDescAttr(erh->er_tupdesc, fnumber - 1); + TupleDescDeformAttr *attr = TupleDescDeformAttr(erh->er_tupdesc, fnumber - 1); - if (!attr->attbyval && attr->attlen == -1 && + if (!DeformAttrByVal(attr) && attr->attlen == -1 && VARATT_IS_EXTERNAL(DatumGetPointer(newValue))) dummy_erh->flags |= ER_FLAG_HAVE_EXTERNAL; } diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 62601a6d80..f4637e466a 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -2833,9 +2833,9 @@ ri_KeysEqual(Relation rel, TupleTableSlot *oldslot, TupleTableSlot *newslot, * difference for ON UPDATE CASCADE, but for consistency we treat * all changes to the PK the same. */ - Form_pg_attribute att = TupleDescAttr(oldslot->tts_tupleDescriptor, attnums[i] - 1); + TupleDescDeformAttr *att = TupleDescDeformAttr(oldslot->tts_tupleDescriptor, attnums[i] - 1); - if (!datum_image_eq(oldvalue, newvalue, att->attbyval, att->attlen)) + if (!datum_image_eq(oldvalue, newvalue, DeformAttrByVal(att), att->attlen)) return false; } else diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 930cc03ee2..0b9a97d174 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -586,6 +586,10 @@ RelationBuildTupleDesc(Relation relation) attp, ATTRIBUTE_FIXED_PART_SIZE); + populate_TupleDescAttr(TupleDescDeformAttr(relation->rd_att, + attnum - 1), + attp); + /* Update constraint/default info */ if (attp->attnotnull) constr->has_not_null = true; @@ -1967,6 +1971,9 @@ formrdesc(const char *relationName, Oid relationReltype, has_not_null |= attrs[i].attnotnull; /* make sure attcacheoff is valid */ TupleDescAttr(relation->rd_att, i)->attcacheoff = -1; + + populate_TupleDescAttr(TupleDescDeformAttr(relation->rd_att, i), + TupleDescAttr(relation->rd_att, i)); } /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ @@ -4436,6 +4443,9 @@ BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs) memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE); /* make sure attcacheoff is valid */ TupleDescAttr(result, i)->attcacheoff = -1; + + populate_TupleDescAttr(TupleDescDeformAttr(result, i), + TupleDescAttr(result, i)); } /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ @@ -6174,6 +6184,8 @@ load_relcache_init_file(bool shared) goto read_failed; has_not_null |= attr->attnotnull; + + populate_TupleDescAttr(TupleDescDeformAttr(rel->rd_att, i), attr); } /* next read the access method specific field */ diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 5e38ef8696..92f5882b27 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -758,12 +758,12 @@ fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) *isnull = false; if (HeapTupleNoNulls(tup)) { - Form_pg_attribute att; + TupleDescDeformAttr *att; - att = TupleDescAttr(tupleDesc, attnum - 1); + att = TupleDescDeformAttr(tupleDesc, attnum - 1); if (att->attcacheoff >= 0) - return fetchatt(att, (char *) tup->t_data + tup->t_data->t_hoff + - att->attcacheoff); + return fetchatt_fast(att, (char *) tup->t_data + tup->t_data->t_hoff + + att->attcacheoff); else return nocachegetattr(tup, attnum, tupleDesc); } diff --git a/src/include/access/itup.h b/src/include/access/itup.h index 94885751e5..f9d33e3bb1 100644 --- a/src/include/access/itup.h +++ b/src/include/access/itup.h @@ -117,18 +117,21 @@ IndexInfoFindDataOffset(unsigned short t_info) static inline Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull) { + TupleDescDeformAttr *attr; + Assert(PointerIsValid(isnull)); Assert(attnum > 0); *isnull = false; + attr = TupleDescDeformAttr(tupleDesc, attnum - 1); if (!IndexTupleHasNulls(tup)) { - if (TupleDescAttr(tupleDesc, attnum - 1)->attcacheoff >= 0) + if (attr->attcacheoff >= 0) { - return fetchatt(TupleDescAttr(tupleDesc, attnum - 1), - (char *) tup + IndexInfoFindDataOffset(tup->t_info) - + TupleDescAttr(tupleDesc, attnum - 1)->attcacheoff); + return fetchatt_fast(attr, + (char *) tup + IndexInfoFindDataOffset(tup->t_info) + + attr->attcacheoff); } else return nocache_index_getattr(tup, attnum, tupleDesc); diff --git a/src/include/access/tupdesc.h b/src/include/access/tupdesc.h index 2c435cdcb2..908c32254e 100644 --- a/src/include/access/tupdesc.h +++ b/src/include/access/tupdesc.h @@ -45,6 +45,43 @@ typedef struct TupleConstr bool has_generated_stored; } TupleConstr; +/* + * Cut-down version of FormData_pg_attribute for faster access for tuple + * deformation. + */ +typedef struct TupleDescDeformAttr +{ + int32 attcacheoff; + int16 attlen; + uint8 attflags; + char attalign; +} TupleDescDeformAttr; + +#define DEFORM_ATTR_FLAG_BYVAL (1 << 0) +#define DEFORM_ATTR_FLAG_IS_PACKABLE (1 << 1) +#define DEFORM_ATTR_FLAG_HAS_MISSING (1 << 2) +#define DEFORM_ATTR_FLAG_IS_DROPPED (1 << 3) +#define DEFORM_ATTR_FLAG_IS_GENERATED (1 << 4) +#define DEFORM_ATTR_FLAG_IS_NOTNULL (1 << 5) + +#define DeformAttrByVal(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_BYVAL) != 0) + +#define DeformAttrIsPackable(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_IS_PACKABLE) != 0) + +#define DeformAttrHasMissing(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_HAS_MISSING) != 0) + +#define DeformAttrIsDropped(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_IS_DROPPED) != 0) + +#define DeformAttrIsGenerated(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_IS_GENERATED) != 0) + +#define DeformAttrIsNotNull(att) \ + (((att)->attflags & DEFORM_ATTR_FLAG_IS_NOTNULL) != 0) + /* * This struct is passed around within the backend to describe the structure * of tuples. For tuples coming from on-disk relations, the information is @@ -85,12 +122,19 @@ typedef struct TupleDescData TupleConstr *constr; /* constraints, or NULL if none */ /* attrs[N] is the description of Attribute Number N+1 */ FormData_pg_attribute *attrs; + TupleDescDeformAttr deform_attrs[FLEXIBLE_ARRAY_MEMBER]; } TupleDescData; typedef struct TupleDescData *TupleDesc; /* Accessor for the i'th attribute of tupdesc. */ #define TupleDescAttr(tupdesc, i) (&(tupdesc)->attrs[(i)]) +/* Accessor for the i'th TupleDescAttr of tupdesc */ +#define TupleDescDeformAttr(tupdesc, i) (&(tupdesc)->deform_attrs[(i)]) + +extern void populate_TupleDescAttr(TupleDescDeformAttr *dst, + Form_pg_attribute src); + extern TupleDesc CreateTemplateTupleDesc(int natts); extern TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs); @@ -99,13 +143,15 @@ extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); -#define TupleDescSize(src) MAXALIGN(sizeof(TupleDescData)) +#define TupleDescSize(src) \ + (offsetof(struct TupleDescData, deform_attrs) + \ + (src)->natts * sizeof(TupleDescDeformAttr)) #define TupleDescFullSize(src) \ - (MAXALIGN(sizeof(TupleDescData)) + sizeof(FormData_pg_attribute) * (src)->natts) + (TupleDescSize(src) + sizeof(FormData_pg_attribute) * (src)->natts) #define TupleDescAttrAddress(desc) \ - (Form_pg_attribute) ((char *) (desc) + MAXALIGN(sizeof(TupleDescData))) + (Form_pg_attribute) ((char *) (desc) + TupleDescSize(desc)) extern void TupleDescCopy(TupleDesc dst, TupleDesc src); diff --git a/src/include/access/tupmacs.h b/src/include/access/tupmacs.h index 58b3a58cfd..f96820f64a 100644 --- a/src/include/access/tupmacs.h +++ b/src/include/access/tupmacs.h @@ -45,6 +45,8 @@ att_isnull(int ATT, const bits8 *BITS) */ #define fetchatt(A,T) fetch_att(T, (A)->attbyval, (A)->attlen) +#define fetchatt_fast(A, T) fetch_att(T, DeformAttrByVal(A), (A)->attlen) + /* * Same, but work from byval/len parameters rather than Form_pg_attribute. */ -- 2.34.1