LCOV - code coverage report
Current view: top level - src/backend/access/common - heaptuple.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 67.5 % 486 328
Test Date: 2026-04-07 14:16:30 Functions: 70.4 % 27 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * heaptuple.c
       4              :  *    This file contains heap tuple accessor and mutator routines, as well
       5              :  *    as various tuple utilities.
       6              :  *
       7              :  * Some notes about varlenas and this code:
       8              :  *
       9              :  * Before Postgres 8.3 varlenas always had a 4-byte length header, and
      10              :  * therefore always needed 4-byte alignment (at least).  This wasted space
      11              :  * for short varlenas, for example CHAR(1) took 5 bytes and could need up to
      12              :  * 3 additional padding bytes for alignment.
      13              :  *
      14              :  * Now, a short varlena (up to 126 data bytes) is reduced to a 1-byte header
      15              :  * and we don't align it.  To hide this from datatype-specific functions that
      16              :  * don't want to deal with it, such a datum is considered "toasted" and will
      17              :  * be expanded back to the normal 4-byte-header format by pg_detoast_datum.
      18              :  * (In performance-critical code paths we can use pg_detoast_datum_packed
      19              :  * and the appropriate access macros to avoid that overhead.)  Note that this
      20              :  * conversion is performed directly in heap_form_tuple, without invoking
      21              :  * heaptoast.c.
      22              :  *
      23              :  * This change will break any code that assumes it needn't detoast values
      24              :  * that have been put into a tuple but never sent to disk.  Hopefully there
      25              :  * are few such places.
      26              :  *
      27              :  * Varlenas still have alignment INT (or DOUBLE) in pg_type/pg_attribute, since
      28              :  * that's the normal requirement for the untoasted format.  But we ignore that
      29              :  * for the 1-byte-header format.  This means that the actual start position
      30              :  * of a varlena datum may vary depending on which format it has.  To determine
      31              :  * what is stored, we have to require that alignment padding bytes be zero.
      32              :  * (Postgres actually has always zeroed them, but now it's required!)  Since
      33              :  * the first byte of a 1-byte-header varlena can never be zero, we can examine
      34              :  * the first byte after the previous datum to tell if it's a pad byte or the
      35              :  * start of a 1-byte-header varlena.
      36              :  *
      37              :  * Note that while formerly we could rely on the first varlena column of a
      38              :  * system catalog to be at the offset suggested by the C struct for the
      39              :  * catalog, this is now risky: it's only safe if the preceding field is
      40              :  * word-aligned, so that there will never be any padding.
      41              :  *
      42              :  * We don't pack varlenas whose attstorage is PLAIN, since the data type
      43              :  * isn't expecting to have to detoast values.  This is used in particular
      44              :  * by oidvector and int2vector, which are used in the system catalogs
      45              :  * and we'd like to still refer to them via C struct offsets.
      46              :  *
      47              :  *
      48              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      49              :  * Portions Copyright (c) 1994, Regents of the University of California
      50              :  *
      51              :  *
      52              :  * IDENTIFICATION
      53              :  *    src/backend/access/common/heaptuple.c
      54              :  *
      55              :  *-------------------------------------------------------------------------
      56              :  */
      57              : 
      58              : #include "postgres.h"
      59              : 
      60              : #include "access/heaptoast.h"
      61              : #include "access/sysattr.h"
      62              : #include "access/tupdesc_details.h"
      63              : #include "common/hashfn.h"
      64              : #include "utils/datum.h"
      65              : #include "utils/expandeddatum.h"
      66              : #include "utils/hsearch.h"
      67              : #include "utils/memutils.h"
      68              : 
      69              : 
      70              : /*
      71              :  * Does att's datatype allow packing into the 1-byte-header varlena format?
      72              :  * While functions that use TupleDescAttr() and assign attstorage =
      73              :  * TYPSTORAGE_PLAIN cannot use packed varlena headers, functions that call
      74              :  * TupleDescInitEntry() use typeForm->typstorage (TYPSTORAGE_EXTENDED) and
      75              :  * can use packed varlena headers, e.g.:
      76              :  *     CREATE TABLE test(a VARCHAR(10000) STORAGE PLAIN);
      77              :  *     INSERT INTO test VALUES (repeat('A',10));
      78              :  * This can be verified with pageinspect.
      79              :  */
      80              : #define ATT_IS_PACKABLE(att) \
      81              :     ((att)->attlen == -1 && (att)->attstorage != TYPSTORAGE_PLAIN)
      82              : /* Use this if it's already known varlena */
      83              : #define VARLENA_ATT_IS_PACKABLE(att) \
      84              :     ((att)->attstorage != TYPSTORAGE_PLAIN)
      85              : 
      86              : /* FormData_pg_attribute.attstorage != TYPSTORAGE_PLAIN and an attlen of -1 */
      87              : #define COMPACT_ATTR_IS_PACKABLE(att) \
      88              :     ((att)->attlen == -1 && (att)->attispackable)
      89              : 
      90              : /*
      91              :  * Setup for caching pass-by-ref missing attributes in a way that survives
      92              :  * tupleDesc destruction.
      93              :  */
      94              : 
      95              : typedef struct
      96              : {
      97              :     int         len;
      98              :     Datum       value;
      99              : } missing_cache_key;
     100              : 
     101              : static HTAB *missing_cache = NULL;
     102              : 
     103              : static uint32
     104            0 : missing_hash(const void *key, Size keysize)
     105              : {
     106            0 :     const missing_cache_key *entry = key;
     107              : 
     108            0 :     return hash_bytes((const unsigned char *) DatumGetPointer(entry->value), entry->len);
     109              : }
     110              : 
     111              : static int
     112            0 : missing_match(const void *key1, const void *key2, Size keysize)
     113              : {
     114            0 :     const missing_cache_key *entry1 = key1;
     115            0 :     const missing_cache_key *entry2 = key2;
     116              : 
     117            0 :     if (entry1->len != entry2->len)
     118            0 :         return entry1->len > entry2->len ? 1 : -1;
     119              : 
     120            0 :     return memcmp(DatumGetPointer(entry1->value),
     121            0 :                   DatumGetPointer(entry2->value),
     122            0 :                   entry1->len);
     123              : }
     124              : 
     125              : static void
     126            0 : init_missing_cache(void)
     127              : {
     128              :     HASHCTL     hash_ctl;
     129              : 
     130            0 :     hash_ctl.keysize = sizeof(missing_cache_key);
     131            0 :     hash_ctl.entrysize = sizeof(missing_cache_key);
     132            0 :     hash_ctl.hcxt = TopMemoryContext;
     133            0 :     hash_ctl.hash = missing_hash;
     134            0 :     hash_ctl.match = missing_match;
     135            0 :     missing_cache =
     136            0 :         hash_create("Missing Values Cache",
     137              :                     32,
     138              :                     &hash_ctl,
     139              :                     HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
     140            0 : }
     141              : 
     142              : /* ----------------------------------------------------------------
     143              :  *                      misc support routines
     144              :  * ----------------------------------------------------------------
     145              :  */
     146              : 
     147              : /*
     148              :  * Return the missing value of an attribute, or NULL if there isn't one.
     149              :  */
     150              : Datum
     151          233 : getmissingattr(TupleDesc tupleDesc,
     152              :                int attnum, bool *isnull)
     153              : {
     154              :     CompactAttribute *att;
     155              : 
     156              :     Assert(attnum <= tupleDesc->natts);
     157              :     Assert(attnum > 0);
     158              : 
     159          233 :     att = TupleDescCompactAttr(tupleDesc, attnum - 1);
     160              : 
     161          233 :     if (att->atthasmissing)
     162              :     {
     163              :         AttrMissing *attrmiss;
     164              : 
     165              :         Assert(tupleDesc->constr);
     166              :         Assert(tupleDesc->constr->missing);
     167              : 
     168           36 :         attrmiss = tupleDesc->constr->missing + (attnum - 1);
     169              : 
     170           36 :         if (attrmiss->am_present)
     171              :         {
     172              :             missing_cache_key key;
     173              :             missing_cache_key *entry;
     174              :             bool        found;
     175              :             MemoryContext oldctx;
     176              : 
     177           36 :             *isnull = false;
     178              : 
     179              :             /* no  need to cache by-value attributes */
     180           36 :             if (att->attbyval)
     181           36 :                 return attrmiss->am_value;
     182              : 
     183              :             /* set up cache if required */
     184            0 :             if (missing_cache == NULL)
     185            0 :                 init_missing_cache();
     186              : 
     187              :             /* check if there's a cache entry */
     188              :             Assert(att->attlen > 0 || att->attlen == -1);
     189            0 :             if (att->attlen > 0)
     190            0 :                 key.len = att->attlen;
     191              :             else
     192            0 :                 key.len = VARSIZE_ANY(DatumGetPointer(attrmiss->am_value));
     193            0 :             key.value = attrmiss->am_value;
     194              : 
     195            0 :             entry = hash_search(missing_cache, &key, HASH_ENTER, &found);
     196              : 
     197            0 :             if (!found)
     198              :             {
     199              :                 /* cache miss, so we need a non-transient copy of the datum */
     200            0 :                 oldctx = MemoryContextSwitchTo(TopMemoryContext);
     201            0 :                 entry->value =
     202            0 :                     datumCopy(attrmiss->am_value, false, att->attlen);
     203            0 :                 MemoryContextSwitchTo(oldctx);
     204              :             }
     205              : 
     206            0 :             return entry->value;
     207              :         }
     208              :     }
     209              : 
     210          197 :     *isnull = true;
     211          197 :     return PointerGetDatum(NULL);
     212              : }
     213              : 
     214              : /*
     215              :  * heap_compute_data_size
     216              :  *      Determine size of the data area of a tuple to be constructed
     217              :  */
     218              : Size
     219     81516730 : heap_compute_data_size(TupleDesc tupleDesc,
     220              :                        const Datum *values,
     221              :                        const bool *isnull)
     222              : {
     223     81516730 :     Size        data_length = 0;
     224              :     int         i;
     225     81516730 :     int         numberOfAttributes = tupleDesc->natts;
     226              : 
     227    275624265 :     for (i = 0; i < numberOfAttributes; i++)
     228              :     {
     229              :         Datum       val;
     230              :         CompactAttribute *atti;
     231              : 
     232    194107535 :         if (isnull[i])
     233     16240779 :             continue;
     234              : 
     235    177866756 :         val = values[i];
     236    177866756 :         atti = TupleDescCompactAttr(tupleDesc, i);
     237              : 
     238    200484148 :         if (COMPACT_ATTR_IS_PACKABLE(atti) &&
     239     22617392 :             VARATT_CAN_MAKE_SHORT(DatumGetPointer(val)))
     240              :         {
     241              :             /*
     242              :              * we're anticipating converting to a short varlena header, so
     243              :              * adjust length and don't count any alignment
     244              :              */
     245     17288692 :             data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
     246              :         }
     247    167067479 :         else if (atti->attlen == -1 &&
     248      6489415 :                  VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
     249              :         {
     250              :             /*
     251              :              * we want to flatten the expanded value so that the constructed
     252              :              * tuple doesn't depend on it
     253              :              */
     254         1855 :             data_length = att_nominal_alignby(data_length, atti->attalignby);
     255         1855 :             data_length += EOH_get_flat_size(DatumGetEOHP(val));
     256              :         }
     257              :         else
     258              :         {
     259    160576209 :             data_length = att_datum_alignby(data_length, atti->attalignby,
     260              :                                             atti->attlen, val);
     261    160576209 :             data_length = att_addlength_datum(data_length, atti->attlen,
     262              :                                               val);
     263              :         }
     264              :     }
     265              : 
     266     81516730 :     return data_length;
     267              : }
     268              : 
     269              : /*
     270              :  * Per-attribute helper for heap_fill_tuple and other routines building tuples.
     271              :  *
     272              :  * Fill in either a data value or a bit in the null bitmask
     273              :  */
     274              : static inline void
     275    179661816 : fill_val(CompactAttribute *att,
     276              :          uint8 **bit,
     277              :          int *bitmask,
     278              :          char **dataP,
     279              :          uint16 *infomask,
     280              :          Datum datum,
     281              :          bool isnull)
     282              : {
     283              :     Size        data_length;
     284    179661816 :     char       *data = *dataP;
     285              : 
     286              :     /*
     287              :      * If we're building a null bitmap, set the appropriate bit for the
     288              :      * current column value here.
     289              :      */
     290    179661816 :     if (bit != NULL)
     291              :     {
     292     60816889 :         if (*bitmask != HIGHBIT)
     293     50477264 :             *bitmask <<= 1;
     294              :         else
     295              :         {
     296     10339625 :             *bit += 1;
     297     10339625 :             **bit = 0x0;
     298     10339625 :             *bitmask = 1;
     299              :         }
     300              : 
     301     60816889 :         if (isnull)
     302              :         {
     303     16095687 :             *infomask |= HEAP_HASNULL;
     304     16095687 :             return;
     305              :         }
     306              : 
     307     44721202 :         **bit |= *bitmask;
     308              :     }
     309              : 
     310              :     /*
     311              :      * XXX we use the att_nominal_alignby macro on the pointer value itself,
     312              :      * not on an offset.  This is a bit of a hack.
     313              :      */
     314    163566129 :     if (att->attbyval)
     315              :     {
     316              :         /* pass-by-value */
     317    124484271 :         data = (char *) att_nominal_alignby(data, att->attalignby);
     318    124484271 :         store_att_byval(data, datum, att->attlen);
     319    124484271 :         data_length = att->attlen;
     320              :     }
     321     39081858 :     else if (att->attlen == -1)
     322              :     {
     323              :         /* varlena */
     324     22753631 :         Pointer     val = DatumGetPointer(datum);
     325              : 
     326     22753631 :         *infomask |= HEAP_HASVARWIDTH;
     327     22753631 :         if (VARATT_IS_EXTERNAL(val))
     328              :         {
     329        15520 :             if (VARATT_IS_EXTERNAL_EXPANDED(val))
     330              :             {
     331              :                 /*
     332              :                  * we want to flatten the expanded value so that the
     333              :                  * constructed tuple doesn't depend on it
     334              :                  */
     335         1855 :                 ExpandedObjectHeader *eoh = DatumGetEOHP(datum);
     336              : 
     337         1855 :                 data = (char *) att_nominal_alignby(data, att->attalignby);
     338         1855 :                 data_length = EOH_get_flat_size(eoh);
     339         1855 :                 EOH_flatten_into(eoh, data, data_length);
     340              :             }
     341              :             else
     342              :             {
     343        13665 :                 *infomask |= HEAP_HASEXTERNAL;
     344              :                 /* no alignment, since it's short by definition */
     345        13665 :                 data_length = VARSIZE_EXTERNAL(val);
     346        13665 :                 memcpy(data, val, data_length);
     347              :             }
     348              :         }
     349     22738111 :         else if (VARATT_IS_SHORT(val))
     350              :         {
     351              :             /* no alignment for short varlenas */
     352      4244604 :             data_length = VARSIZE_SHORT(val);
     353      4244604 :             memcpy(data, val, data_length);
     354              :         }
     355     18493507 :         else if (att->attispackable && VARATT_CAN_MAKE_SHORT(val))
     356              :         {
     357              :             /* convert to short varlena -- no alignment */
     358     16672921 :             data_length = VARATT_CONVERTED_SHORT_SIZE(val);
     359     16672921 :             SET_VARSIZE_SHORT(data, data_length);
     360     16672921 :             memcpy(data + 1, VARDATA(val), data_length - 1);
     361              :         }
     362              :         else
     363              :         {
     364              :             /* full 4-byte header varlena */
     365      1820586 :             data = (char *) att_nominal_alignby(data, att->attalignby);
     366      1820586 :             data_length = VARSIZE(val);
     367      1820586 :             memcpy(data, val, data_length);
     368              :         }
     369              :     }
     370     16328227 :     else if (att->attlen == -2)
     371              :     {
     372              :         /* cstring ... never needs alignment */
     373      1551897 :         *infomask |= HEAP_HASVARWIDTH;
     374              :         Assert(att->attalignby == sizeof(char));
     375      1551897 :         data_length = strlen(DatumGetCString(datum)) + 1;
     376      1551897 :         memcpy(data, DatumGetPointer(datum), data_length);
     377              :     }
     378              :     else
     379              :     {
     380              :         /* fixed-length pass-by-reference */
     381     14776330 :         data = (char *) att_nominal_alignby(data, att->attalignby);
     382              :         Assert(att->attlen > 0);
     383     14776330 :         data_length = att->attlen;
     384     14776330 :         memcpy(data, DatumGetPointer(datum), data_length);
     385              :     }
     386              : 
     387    163566129 :     data += data_length;
     388    163566129 :     *dataP = data;
     389              : }
     390              : 
     391              : /*
     392              :  * heap_fill_tuple
     393              :  *      Load data portion of a tuple from values/isnull arrays
     394              :  *
     395              :  * We also fill the null bitmap (if any) and set the infomask bits
     396              :  * that reflect the tuple's data contents.
     397              :  *
     398              :  * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area.
     399              :  */
     400              : void
     401     68414025 : heap_fill_tuple(TupleDesc tupleDesc,
     402              :                 const Datum *values, const bool *isnull,
     403              :                 char *data, Size data_size,
     404              :                 uint16 *infomask, uint8 *bit)
     405              : {
     406              :     uint8      *bitP;
     407              :     int         bitmask;
     408              :     int         i;
     409     68414025 :     int         numberOfAttributes = tupleDesc->natts;
     410              : 
     411              : #ifdef USE_ASSERT_CHECKING
     412              :     char       *start = data;
     413              : #endif
     414              : 
     415     68414025 :     if (bit != NULL)
     416              :     {
     417      4284532 :         bitP = &bit[-1];
     418      4284532 :         bitmask = HIGHBIT;
     419              :     }
     420              :     else
     421              :     {
     422              :         /* just to keep compiler quiet */
     423     64129493 :         bitP = NULL;
     424     64129493 :         bitmask = 0;
     425              :     }
     426              : 
     427     68414025 :     *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
     428              : 
     429    248075841 :     for (i = 0; i < numberOfAttributes; i++)
     430              :     {
     431    179661816 :         CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, i);
     432              : 
     433    538985448 :         fill_val(attr,
     434    179661816 :                  bitP ? &bitP : NULL,
     435              :                  &bitmask,
     436              :                  &data,
     437              :                  infomask,
     438    179661816 :                  values ? values[i] : PointerGetDatum(NULL),
     439    179661816 :                  isnull ? isnull[i] : true);
     440              :     }
     441              : 
     442              :     Assert((data - start) == data_size);
     443     68414025 : }
     444              : 
     445              : 
     446              : /* ----------------------------------------------------------------
     447              :  *                      heap tuple interface
     448              :  * ----------------------------------------------------------------
     449              :  */
     450              : 
     451              : /* ----------------
     452              :  *      heap_attisnull  - returns true iff tuple attribute is not present
     453              :  * ----------------
     454              :  */
     455              : bool
     456      6709689 : heap_attisnull(HeapTuple tup, int attnum, TupleDesc tupleDesc)
     457              : {
     458              :     /*
     459              :      * We allow a NULL tupledesc for relations not expected to have missing
     460              :      * values, such as catalog relations and indexes.
     461              :      */
     462              :     Assert(!tupleDesc || attnum <= tupleDesc->natts);
     463      6709689 :     if (attnum > (int) HeapTupleHeaderGetNatts(tup->t_data))
     464              :     {
     465            0 :         if (tupleDesc &&
     466            0 :             TupleDescCompactAttr(tupleDesc, attnum - 1)->atthasmissing)
     467            0 :             return false;
     468              :         else
     469            0 :             return true;
     470              :     }
     471              : 
     472      6709689 :     if (attnum > 0)
     473              :     {
     474      6709689 :         if (HeapTupleNoNulls(tup))
     475         1974 :             return false;
     476      6707715 :         return att_isnull(attnum - 1, tup->t_data->t_bits);
     477              :     }
     478              : 
     479            0 :     switch (attnum)
     480              :     {
     481            0 :         case TableOidAttributeNumber:
     482              :         case SelfItemPointerAttributeNumber:
     483              :         case MinTransactionIdAttributeNumber:
     484              :         case MinCommandIdAttributeNumber:
     485              :         case MaxTransactionIdAttributeNumber:
     486              :         case MaxCommandIdAttributeNumber:
     487              :             /* these are never null */
     488            0 :             break;
     489              : 
     490            0 :         default:
     491            0 :             elog(ERROR, "invalid attnum: %d", attnum);
     492              :     }
     493              : 
     494            0 :     return false;
     495              : }
     496              : 
     497              : /* ----------------
     498              :  *      nocachegetattr
     499              :  *
     500              :  *      This only gets called from fastgetattr(), in cases where we
     501              :  *      can't use the attcacheoff and the value is not null.
     502              :  *
     503              :  *      NOTE: if you need to change this code, see also heap_deform_tuple.
     504              :  *      Also see nocache_index_getattr, which is the same code for index
     505              :  *      tuples.
     506              :  * ----------------
     507              :  */
     508              : Datum
     509    141982118 : nocachegetattr(HeapTuple tup,
     510              :                int attnum,
     511              :                TupleDesc tupleDesc)
     512              : {
     513              :     CompactAttribute *cattr;
     514    141982118 :     HeapTupleHeader td = tup->t_data;
     515              :     char       *tp;             /* ptr to data part of tuple */
     516    141982118 :     uint8      *bp = td->t_bits; /* ptr to null bitmap in tuple */
     517              :     int         off;            /* current offset within data */
     518              :     int         startAttr;
     519              :     int         firstNullAttr;
     520              :     int         i;
     521    141982118 :     bool        hasnulls = HeapTupleHasNulls(tup);
     522              : 
     523              :     /* Did someone forget to call TupleDescFinalize()? */
     524              :     Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
     525              : 
     526    141982118 :     attnum--;
     527              : 
     528              :     /*
     529              :      * To minimize the number of attributes we need to look at, start walking
     530              :      * the tuple at the attribute with the highest attcacheoff prior to attnum
     531              :      * or the first NULL attribute prior to attnum, whichever comes first.
     532              :      */
     533    141982118 :     if (hasnulls)
     534    100432657 :         firstNullAttr = first_null_attr(bp, attnum);
     535              :     else
     536     41549461 :         firstNullAttr = attnum;
     537              : 
     538    141982118 :     if (tupleDesc->firstNonCachedOffsetAttr > 0 && firstNullAttr > 0)
     539              :     {
     540              :         /*
     541              :          * Try to start with the highest attribute with an attcacheoff that's
     542              :          * prior to the one we're looking for, or with the attribute prior to
     543              :          * the first NULL attribute, if there is one.
     544              :          */
     545     48196815 :         startAttr = Min(tupleDesc->firstNonCachedOffsetAttr - 1, firstNullAttr - 1);
     546     48196815 :         off = TupleDescCompactAttr(tupleDesc, startAttr)->attcacheoff;
     547              :     }
     548              :     else
     549              :     {
     550              :         /* Otherwise, start at the beginning... */
     551     93785303 :         startAttr = 0;
     552     93785303 :         off = 0;
     553              :     }
     554              : 
     555    141982118 :     tp = (char *) td + td->t_hoff;
     556              : 
     557              :     /*
     558              :      * Calculate 'off' up to the first NULL attr.  We use two cheaper loops
     559              :      * when the tuple has no variable-width columns.  When variable-width
     560              :      * columns exists, we use att_addlength_pointer() to move the offset
     561              :      * beyond the current attribute.
     562              :      */
     563    141982118 :     if (!HeapTupleHasVarWidth(tup))
     564              :     {
     565     95401527 :         for (i = startAttr; i < firstNullAttr; i++)
     566              :         {
     567     23462270 :             cattr = TupleDescCompactAttr(tupleDesc, i);
     568              : 
     569     23462270 :             off = att_nominal_alignby(off, cattr->attalignby);
     570     23462270 :             off += cattr->attlen;
     571              :         }
     572              : 
     573     76005610 :         for (; i < attnum; i++)
     574              :         {
     575      4066353 :             if (att_isnull(i, bp))
     576      3321402 :                 continue;
     577              : 
     578       744951 :             cattr = TupleDescCompactAttr(tupleDesc, i);
     579              : 
     580       744951 :             off = att_nominal_alignby(off, cattr->attalignby);
     581       744951 :             off += cattr->attlen;
     582              :         }
     583              :     }
     584              :     else
     585              :     {
     586    177097361 :         for (i = startAttr; i < firstNullAttr; i++)
     587              :         {
     588              :             int         attlen;
     589              : 
     590    107054500 :             cattr = TupleDescCompactAttr(tupleDesc, i);
     591    107054500 :             attlen = cattr->attlen;
     592    107054500 :             off = att_pointer_alignby(off,
     593              :                                       cattr->attalignby,
     594              :                                       attlen,
     595              :                                       tp + off);
     596    107054500 :             off = att_addlength_pointer(off, attlen, tp + off);
     597              :         }
     598              : 
     599     81938655 :         for (; i < attnum; i++)
     600              :         {
     601              :             int         attlen;
     602              : 
     603     11895794 :             if (att_isnull(i, bp))
     604      8321348 :                 continue;
     605              : 
     606      3574446 :             cattr = TupleDescCompactAttr(tupleDesc, i);
     607      3574446 :             attlen = cattr->attlen;
     608      3574446 :             off = att_pointer_alignby(off, cattr->attalignby, attlen,
     609              :                                       tp + off);
     610      3574446 :             off = att_addlength_pointer(off, attlen, tp + off);
     611              :         }
     612              :     }
     613              : 
     614    141982118 :     cattr = TupleDescCompactAttr(tupleDesc, attnum);
     615    141982118 :     off = att_pointer_alignby(off,
     616              :                               cattr->attalignby,
     617              :                               cattr->attlen,
     618              :                               tp + off);
     619              : 
     620    141982118 :     return fetchatt(cattr, tp + off);
     621              : }
     622              : 
     623              : /* ----------------
     624              :  *      heap_getsysattr
     625              :  *
     626              :  *      Fetch the value of a system attribute for a tuple.
     627              :  *
     628              :  * This is a support routine for heap_getattr().  The function has already
     629              :  * determined that the attnum refers to a system attribute.
     630              :  * ----------------
     631              :  */
     632              : Datum
     633        72813 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
     634              : {
     635              :     Datum       result;
     636              : 
     637              :     Assert(tup);
     638              : 
     639              :     /* Currently, no sys attribute ever reads as NULL. */
     640        72813 :     *isnull = false;
     641              : 
     642        72813 :     switch (attnum)
     643              :     {
     644            2 :         case SelfItemPointerAttributeNumber:
     645              :             /* pass-by-reference datatype */
     646            2 :             result = PointerGetDatum(&(tup->t_self));
     647            2 :             break;
     648        72566 :         case MinTransactionIdAttributeNumber:
     649        72566 :             result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
     650        72566 :             break;
     651          119 :         case MaxTransactionIdAttributeNumber:
     652          119 :             result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
     653          119 :             break;
     654          124 :         case MinCommandIdAttributeNumber:
     655              :         case MaxCommandIdAttributeNumber:
     656              : 
     657              :             /*
     658              :              * cmin and cmax are now both aliases for the same field, which
     659              :              * can in fact also be a combo command id.  XXX perhaps we should
     660              :              * return the "real" cmin or cmax if possible, that is if we are
     661              :              * inside the originating transaction?
     662              :              */
     663          124 :             result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
     664          124 :             break;
     665            2 :         case TableOidAttributeNumber:
     666            2 :             result = ObjectIdGetDatum(tup->t_tableOid);
     667            2 :             break;
     668            0 :         default:
     669            0 :             elog(ERROR, "invalid attnum: %d", attnum);
     670              :             result = 0;         /* keep compiler quiet */
     671              :             break;
     672              :     }
     673        72813 :     return result;
     674              : }
     675              : 
     676              : /* ----------------
     677              :  *      heap_copytuple
     678              :  *
     679              :  *      returns a copy of an entire tuple
     680              :  *
     681              :  * The HeapTuple struct, tuple header, and tuple data are all allocated
     682              :  * as a single palloc() block.
     683              :  * ----------------
     684              :  */
     685              : HeapTuple
     686     10706382 : heap_copytuple(HeapTuple tuple)
     687              : {
     688              :     HeapTuple   newTuple;
     689              : 
     690     10706382 :     if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
     691            0 :         return NULL;
     692              : 
     693     10706382 :     newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
     694     10706382 :     newTuple->t_len = tuple->t_len;
     695     10706382 :     newTuple->t_self = tuple->t_self;
     696     10706382 :     newTuple->t_tableOid = tuple->t_tableOid;
     697     10706382 :     newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
     698     10706382 :     memcpy(newTuple->t_data, tuple->t_data, tuple->t_len);
     699     10706382 :     return newTuple;
     700              : }
     701              : 
     702              : /* ----------------
     703              :  *      heap_copytuple_with_tuple
     704              :  *
     705              :  *      copy a tuple into a caller-supplied HeapTuple management struct
     706              :  *
     707              :  * Note that after calling this function, the "dest" HeapTuple will not be
     708              :  * allocated as a single palloc() block (unlike with heap_copytuple()).
     709              :  * ----------------
     710              :  */
     711              : void
     712            0 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
     713              : {
     714            0 :     if (!HeapTupleIsValid(src) || src->t_data == NULL)
     715              :     {
     716            0 :         dest->t_data = NULL;
     717            0 :         return;
     718              :     }
     719              : 
     720            0 :     dest->t_len = src->t_len;
     721            0 :     dest->t_self = src->t_self;
     722            0 :     dest->t_tableOid = src->t_tableOid;
     723            0 :     dest->t_data = (HeapTupleHeader) palloc(src->t_len);
     724            0 :     memcpy(dest->t_data, src->t_data, src->t_len);
     725              : }
     726              : 
     727              : /*
     728              :  * Expand a tuple which has fewer attributes than required. For each attribute
     729              :  * not present in the sourceTuple, if there is a missing value that will be
     730              :  * used. Otherwise the attribute will be set to NULL.
     731              :  *
     732              :  * The source tuple must have fewer attributes than the required number.
     733              :  *
     734              :  * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
     735              :  * other argument must be NULL.
     736              :  */
     737              : static void
     738            0 : expand_tuple(HeapTuple *targetHeapTuple,
     739              :              MinimalTuple *targetMinimalTuple,
     740              :              HeapTuple sourceTuple,
     741              :              TupleDesc tupleDesc)
     742              : {
     743            0 :     AttrMissing *attrmiss = NULL;
     744              :     int         attnum;
     745              :     int         firstmissingnum;
     746            0 :     bool        hasNulls = HeapTupleHasNulls(sourceTuple);
     747              :     HeapTupleHeader targetTHeader;
     748            0 :     HeapTupleHeader sourceTHeader = sourceTuple->t_data;
     749            0 :     int         sourceNatts = HeapTupleHeaderGetNatts(sourceTHeader);
     750            0 :     int         natts = tupleDesc->natts;
     751              :     int         sourceNullLen;
     752              :     int         targetNullLen;
     753            0 :     Size        sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
     754              :     Size        targetDataLen;
     755              :     Size        len;
     756              :     int         hoff;
     757            0 :     uint8      *nullBits = NULL;
     758            0 :     int         bitMask = 0;
     759              :     char       *targetData;
     760              :     uint16     *infoMask;
     761              : 
     762              :     Assert((targetHeapTuple && !targetMinimalTuple)
     763              :            || (!targetHeapTuple && targetMinimalTuple));
     764              : 
     765              :     Assert(sourceNatts < natts);
     766              : 
     767            0 :     sourceNullLen = (hasNulls ? BITMAPLEN(sourceNatts) : 0);
     768              : 
     769            0 :     targetDataLen = sourceDataLen;
     770              : 
     771            0 :     if (tupleDesc->constr &&
     772            0 :         tupleDesc->constr->missing)
     773              :     {
     774              :         /*
     775              :          * If there are missing values we want to put them into the tuple.
     776              :          * Before that we have to compute the extra length for the values
     777              :          * array and the variable length data.
     778              :          */
     779            0 :         attrmiss = tupleDesc->constr->missing;
     780              : 
     781              :         /*
     782              :          * Find the first item in attrmiss for which we don't have a value in
     783              :          * the source. We can ignore all the missing entries before that.
     784              :          */
     785            0 :         for (firstmissingnum = sourceNatts;
     786            0 :              firstmissingnum < natts;
     787            0 :              firstmissingnum++)
     788              :         {
     789            0 :             if (attrmiss[firstmissingnum].am_present)
     790            0 :                 break;
     791              :             else
     792            0 :                 hasNulls = true;
     793              :         }
     794              : 
     795              :         /*
     796              :          * Now walk the missing attributes. If there is a missing value make
     797              :          * space for it. Otherwise, it's going to be NULL.
     798              :          */
     799            0 :         for (attnum = firstmissingnum;
     800            0 :              attnum < natts;
     801            0 :              attnum++)
     802              :         {
     803            0 :             if (attrmiss[attnum].am_present)
     804              :             {
     805            0 :                 CompactAttribute *att = TupleDescCompactAttr(tupleDesc, attnum);
     806              : 
     807            0 :                 targetDataLen = att_datum_alignby(targetDataLen,
     808              :                                                   att->attalignby,
     809              :                                                   att->attlen,
     810              :                                                   attrmiss[attnum].am_value);
     811              : 
     812            0 :                 targetDataLen = att_addlength_datum(targetDataLen,
     813              :                                                     att->attlen,
     814              :                                                     attrmiss[attnum].am_value);
     815              :             }
     816              :             else
     817              :             {
     818              :                 /* no missing value, so it must be null */
     819            0 :                 hasNulls = true;
     820              :             }
     821              :         }
     822              :     }                           /* end if have missing values */
     823              :     else
     824              :     {
     825              :         /*
     826              :          * If there are no missing values at all then NULLS must be allowed,
     827              :          * since some of the attributes are known to be absent.
     828              :          */
     829            0 :         hasNulls = true;
     830              :     }
     831              : 
     832            0 :     len = 0;
     833              : 
     834            0 :     if (hasNulls)
     835              :     {
     836            0 :         targetNullLen = BITMAPLEN(natts);
     837            0 :         len += targetNullLen;
     838              :     }
     839              :     else
     840            0 :         targetNullLen = 0;
     841              : 
     842              :     /*
     843              :      * Allocate and zero the space needed.  Note that the tuple body and
     844              :      * HeapTupleData management structure are allocated in one chunk.
     845              :      */
     846            0 :     if (targetHeapTuple)
     847              :     {
     848            0 :         len += offsetof(HeapTupleHeaderData, t_bits);
     849            0 :         hoff = len = MAXALIGN(len); /* align user data safely */
     850            0 :         len += targetDataLen;
     851              : 
     852            0 :         *targetHeapTuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
     853            0 :         (*targetHeapTuple)->t_data
     854            0 :             = targetTHeader
     855            0 :             = (HeapTupleHeader) ((char *) *targetHeapTuple + HEAPTUPLESIZE);
     856            0 :         (*targetHeapTuple)->t_len = len;
     857            0 :         (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
     858            0 :         (*targetHeapTuple)->t_self = sourceTuple->t_self;
     859              : 
     860            0 :         targetTHeader->t_infomask = sourceTHeader->t_infomask;
     861            0 :         targetTHeader->t_hoff = hoff;
     862            0 :         HeapTupleHeaderSetNatts(targetTHeader, natts);
     863            0 :         HeapTupleHeaderSetDatumLength(targetTHeader, len);
     864            0 :         HeapTupleHeaderSetTypeId(targetTHeader, tupleDesc->tdtypeid);
     865            0 :         HeapTupleHeaderSetTypMod(targetTHeader, tupleDesc->tdtypmod);
     866              :         /* We also make sure that t_ctid is invalid unless explicitly set */
     867            0 :         ItemPointerSetInvalid(&(targetTHeader->t_ctid));
     868            0 :         if (targetNullLen > 0)
     869            0 :             nullBits = (uint8 *) ((char *) (*targetHeapTuple)->t_data
     870              :                                   + offsetof(HeapTupleHeaderData, t_bits));
     871            0 :         targetData = (char *) (*targetHeapTuple)->t_data + hoff;
     872            0 :         infoMask = &(targetTHeader->t_infomask);
     873              :     }
     874              :     else
     875              :     {
     876            0 :         len += SizeofMinimalTupleHeader;
     877            0 :         hoff = len = MAXALIGN(len); /* align user data safely */
     878            0 :         len += targetDataLen;
     879              : 
     880            0 :         *targetMinimalTuple = (MinimalTuple) palloc0(len);
     881            0 :         (*targetMinimalTuple)->t_len = len;
     882            0 :         (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
     883            0 :         (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
     884              :         /* Same macro works for MinimalTuples */
     885            0 :         HeapTupleHeaderSetNatts(*targetMinimalTuple, natts);
     886            0 :         if (targetNullLen > 0)
     887            0 :             nullBits = (uint8 *) ((char *) *targetMinimalTuple
     888            0 :                                   + offsetof(MinimalTupleData, t_bits));
     889            0 :         targetData = (char *) *targetMinimalTuple + hoff;
     890            0 :         infoMask = &((*targetMinimalTuple)->t_infomask);
     891              :     }
     892              : 
     893            0 :     if (targetNullLen > 0)
     894              :     {
     895            0 :         if (sourceNullLen > 0)
     896              :         {
     897              :             /* if bitmap pre-existed copy in - all is set */
     898            0 :             memcpy(nullBits,
     899              :                    ((char *) sourceTHeader)
     900              :                    + offsetof(HeapTupleHeaderData, t_bits),
     901              :                    sourceNullLen);
     902            0 :             nullBits += sourceNullLen - 1;
     903              :         }
     904              :         else
     905              :         {
     906            0 :             sourceNullLen = BITMAPLEN(sourceNatts);
     907              :             /* Set NOT NULL for all existing attributes */
     908            0 :             memset(nullBits, 0xff, sourceNullLen);
     909              : 
     910            0 :             nullBits += sourceNullLen - 1;
     911              : 
     912            0 :             if (sourceNatts & 0x07)
     913              :             {
     914              :                 /* build the mask (inverted!) */
     915            0 :                 bitMask = 0xff << (sourceNatts & 0x07);
     916              :                 /* Voila */
     917            0 :                 *nullBits = ~bitMask;
     918              :             }
     919              :         }
     920              : 
     921            0 :         bitMask = (1 << ((sourceNatts - 1) & 0x07));
     922              :     }                           /* End if have null bitmap */
     923              : 
     924            0 :     memcpy(targetData,
     925            0 :            ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
     926              :            sourceDataLen);
     927              : 
     928            0 :     targetData += sourceDataLen;
     929              : 
     930              :     /* Now fill in the missing values */
     931            0 :     for (attnum = sourceNatts; attnum < natts; attnum++)
     932              :     {
     933            0 :         CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, attnum);
     934              : 
     935            0 :         if (attrmiss && attrmiss[attnum].am_present)
     936              :         {
     937            0 :             fill_val(attr,
     938            0 :                      nullBits ? &nullBits : NULL,
     939              :                      &bitMask,
     940              :                      &targetData,
     941              :                      infoMask,
     942            0 :                      attrmiss[attnum].am_value,
     943              :                      false);
     944              :         }
     945              :         else
     946              :         {
     947            0 :             fill_val(attr,
     948              :                      &nullBits,
     949              :                      &bitMask,
     950              :                      &targetData,
     951              :                      infoMask,
     952              :                      (Datum) 0,
     953              :                      true);
     954              :         }
     955              :     }                           /* end loop over missing attributes */
     956            0 : }
     957              : 
     958              : /*
     959              :  * Fill in the missing values for a minimal HeapTuple
     960              :  */
     961              : MinimalTuple
     962            0 : minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
     963              : {
     964              :     MinimalTuple minimalTuple;
     965              : 
     966            0 :     expand_tuple(NULL, &minimalTuple, sourceTuple, tupleDesc);
     967            0 :     return minimalTuple;
     968              : }
     969              : 
     970              : /*
     971              :  * Fill in the missing values for an ordinary HeapTuple
     972              :  */
     973              : HeapTuple
     974            0 : heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
     975              : {
     976              :     HeapTuple   heapTuple;
     977              : 
     978            0 :     expand_tuple(&heapTuple, NULL, sourceTuple, tupleDesc);
     979            0 :     return heapTuple;
     980              : }
     981              : 
     982              : /* ----------------
     983              :  *      heap_copy_tuple_as_datum
     984              :  *
     985              :  *      copy a tuple as a composite-type Datum
     986              :  * ----------------
     987              :  */
     988              : Datum
     989        52136 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
     990              : {
     991              :     HeapTupleHeader td;
     992              : 
     993              :     /*
     994              :      * If the tuple contains any external TOAST pointers, we have to inline
     995              :      * those fields to meet the conventions for composite-type Datums.
     996              :      */
     997        52136 :     if (HeapTupleHasExternal(tuple))
     998            0 :         return toast_flatten_tuple_to_datum(tuple->t_data,
     999              :                                             tuple->t_len,
    1000              :                                             tupleDesc);
    1001              : 
    1002              :     /*
    1003              :      * Fast path for easy case: just make a palloc'd copy and insert the
    1004              :      * correct composite-Datum header fields (since those may not be set if
    1005              :      * the given tuple came from disk, rather than from heap_form_tuple).
    1006              :      */
    1007        52136 :     td = (HeapTupleHeader) palloc(tuple->t_len);
    1008        52136 :     memcpy(td, tuple->t_data, tuple->t_len);
    1009              : 
    1010        52136 :     HeapTupleHeaderSetDatumLength(td, tuple->t_len);
    1011        52136 :     HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
    1012        52136 :     HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
    1013              : 
    1014        52136 :     return PointerGetDatum(td);
    1015              : }
    1016              : 
    1017              : /*
    1018              :  * heap_form_tuple
    1019              :  *      construct a tuple from the given values[] and isnull[] arrays,
    1020              :  *      which are of the length indicated by tupleDescriptor->natts
    1021              :  *
    1022              :  * The result is allocated in the current memory context.
    1023              :  */
    1024              : HeapTuple
    1025     18570532 : heap_form_tuple(TupleDesc tupleDescriptor,
    1026              :                 const Datum *values,
    1027              :                 const bool *isnull)
    1028              : {
    1029              :     HeapTuple   tuple;          /* return tuple */
    1030              :     HeapTupleHeader td;         /* tuple data */
    1031              :     Size        len,
    1032              :                 data_len;
    1033              :     int         hoff;
    1034     18570532 :     bool        hasnull = false;
    1035     18570532 :     int         numberOfAttributes = tupleDescriptor->natts;
    1036              :     int         i;
    1037              : 
    1038     18570532 :     if (numberOfAttributes > MaxTupleAttributeNumber)
    1039            0 :         ereport(ERROR,
    1040              :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1041              :                  errmsg("number of columns (%d) exceeds limit (%d)",
    1042              :                         numberOfAttributes, MaxTupleAttributeNumber)));
    1043              : 
    1044              :     /*
    1045              :      * Check for nulls
    1046              :      */
    1047     83342051 :     for (i = 0; i < numberOfAttributes; i++)
    1048              :     {
    1049     68459205 :         if (isnull[i])
    1050              :         {
    1051      3687686 :             hasnull = true;
    1052      3687686 :             break;
    1053              :         }
    1054              :     }
    1055              : 
    1056              :     /*
    1057              :      * Determine total space needed
    1058              :      */
    1059     18570532 :     len = offsetof(HeapTupleHeaderData, t_bits);
    1060              : 
    1061     18570532 :     if (hasnull)
    1062      3687686 :         len += BITMAPLEN(numberOfAttributes);
    1063              : 
    1064     18570532 :     hoff = len = MAXALIGN(len); /* align user data safely */
    1065              : 
    1066     18570532 :     data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
    1067              : 
    1068     18570532 :     len += data_len;
    1069              : 
    1070              :     /*
    1071              :      * Allocate and zero the space needed.  Note that the tuple body and
    1072              :      * HeapTupleData management structure are allocated in one chunk.
    1073              :      */
    1074     18570532 :     tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
    1075     18570532 :     tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
    1076              : 
    1077              :     /*
    1078              :      * And fill in the information.  Note we fill the Datum fields even though
    1079              :      * this tuple may never become a Datum.  This lets HeapTupleHeaderGetDatum
    1080              :      * identify the tuple type if needed.
    1081              :      */
    1082     18570532 :     tuple->t_len = len;
    1083     18570532 :     ItemPointerSetInvalid(&(tuple->t_self));
    1084     18570532 :     tuple->t_tableOid = InvalidOid;
    1085              : 
    1086     18570532 :     HeapTupleHeaderSetDatumLength(td, len);
    1087     18570532 :     HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
    1088     18570532 :     HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
    1089              :     /* We also make sure that t_ctid is invalid unless explicitly set */
    1090     18570532 :     ItemPointerSetInvalid(&(td->t_ctid));
    1091              : 
    1092     18570532 :     HeapTupleHeaderSetNatts(td, numberOfAttributes);
    1093     18570532 :     td->t_hoff = hoff;
    1094              : 
    1095     18570532 :     heap_fill_tuple(tupleDescriptor,
    1096              :                     values,
    1097              :                     isnull,
    1098              :                     (char *) td + hoff,
    1099              :                     data_len,
    1100              :                     &td->t_infomask,
    1101              :                     (hasnull ? td->t_bits : NULL));
    1102              : 
    1103     18570532 :     return tuple;
    1104              : }
    1105              : 
    1106              : /*
    1107              :  * heap_modify_tuple
    1108              :  *      form a new tuple from an old tuple and a set of replacement values.
    1109              :  *
    1110              :  * The replValues, replIsnull, and doReplace arrays must be of the length
    1111              :  * indicated by tupleDesc->natts.  The new tuple is constructed using the data
    1112              :  * from replValues/replIsnull at columns where doReplace is true, and using
    1113              :  * the data from the old tuple at columns where doReplace is false.
    1114              :  *
    1115              :  * The result is allocated in the current memory context.
    1116              :  */
    1117              : HeapTuple
    1118        60030 : heap_modify_tuple(HeapTuple tuple,
    1119              :                   TupleDesc tupleDesc,
    1120              :                   const Datum *replValues,
    1121              :                   const bool *replIsnull,
    1122              :                   const bool *doReplace)
    1123              : {
    1124        60030 :     int         numberOfAttributes = tupleDesc->natts;
    1125              :     int         attoff;
    1126              :     Datum      *values;
    1127              :     bool       *isnull;
    1128              :     HeapTuple   newTuple;
    1129              : 
    1130              :     /*
    1131              :      * allocate and fill values and isnull arrays from either the tuple or the
    1132              :      * repl information, as appropriate.
    1133              :      *
    1134              :      * NOTE: it's debatable whether to use heap_deform_tuple() here or just
    1135              :      * heap_getattr() only the non-replaced columns.  The latter could win if
    1136              :      * there are many replaced columns and few non-replaced ones. However,
    1137              :      * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
    1138              :      * O(N^2) if there are many non-replaced columns, so it seems better to
    1139              :      * err on the side of linear cost.
    1140              :      */
    1141        60030 :     values = palloc_array(Datum, numberOfAttributes);
    1142        60030 :     isnull = palloc_array(bool, numberOfAttributes);
    1143              : 
    1144        60030 :     heap_deform_tuple(tuple, tupleDesc, values, isnull);
    1145              : 
    1146      1819299 :     for (attoff = 0; attoff < numberOfAttributes; attoff++)
    1147              :     {
    1148      1759269 :         if (doReplace[attoff])
    1149              :         {
    1150       815923 :             values[attoff] = replValues[attoff];
    1151       815923 :             isnull[attoff] = replIsnull[attoff];
    1152              :         }
    1153              :     }
    1154              : 
    1155              :     /*
    1156              :      * create a new tuple from the values and isnull arrays
    1157              :      */
    1158        60030 :     newTuple = heap_form_tuple(tupleDesc, values, isnull);
    1159              : 
    1160        60030 :     pfree(values);
    1161        60030 :     pfree(isnull);
    1162              : 
    1163              :     /*
    1164              :      * copy the identification info of the old tuple: t_ctid, t_self
    1165              :      */
    1166        60030 :     newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
    1167        60030 :     newTuple->t_self = tuple->t_self;
    1168        60030 :     newTuple->t_tableOid = tuple->t_tableOid;
    1169              : 
    1170        60030 :     return newTuple;
    1171              : }
    1172              : 
    1173              : /*
    1174              :  * heap_modify_tuple_by_cols
    1175              :  *      form a new tuple from an old tuple and a set of replacement values.
    1176              :  *
    1177              :  * This is like heap_modify_tuple, except that instead of specifying which
    1178              :  * column(s) to replace by a boolean map, an array of target column numbers
    1179              :  * is used.  This is often more convenient when a fixed number of columns
    1180              :  * are to be replaced.  The replCols, replValues, and replIsnull arrays must
    1181              :  * be of length nCols.  Target column numbers are indexed from 1.
    1182              :  *
    1183              :  * The result is allocated in the current memory context.
    1184              :  */
    1185              : HeapTuple
    1186          719 : heap_modify_tuple_by_cols(HeapTuple tuple,
    1187              :                           TupleDesc tupleDesc,
    1188              :                           int nCols,
    1189              :                           const int *replCols,
    1190              :                           const Datum *replValues,
    1191              :                           const bool *replIsnull)
    1192              : {
    1193          719 :     int         numberOfAttributes = tupleDesc->natts;
    1194              :     Datum      *values;
    1195              :     bool       *isnull;
    1196              :     HeapTuple   newTuple;
    1197              :     int         i;
    1198              : 
    1199              :     /*
    1200              :      * allocate and fill values and isnull arrays from the tuple, then replace
    1201              :      * selected columns from the input arrays.
    1202              :      */
    1203          719 :     values = palloc_array(Datum, numberOfAttributes);
    1204          719 :     isnull = palloc_array(bool, numberOfAttributes);
    1205              : 
    1206          719 :     heap_deform_tuple(tuple, tupleDesc, values, isnull);
    1207              : 
    1208         2091 :     for (i = 0; i < nCols; i++)
    1209              :     {
    1210         1372 :         int         attnum = replCols[i];
    1211              : 
    1212         1372 :         if (attnum <= 0 || attnum > numberOfAttributes)
    1213            0 :             elog(ERROR, "invalid column number %d", attnum);
    1214         1372 :         values[attnum - 1] = replValues[i];
    1215         1372 :         isnull[attnum - 1] = replIsnull[i];
    1216              :     }
    1217              : 
    1218              :     /*
    1219              :      * create a new tuple from the values and isnull arrays
    1220              :      */
    1221          719 :     newTuple = heap_form_tuple(tupleDesc, values, isnull);
    1222              : 
    1223          719 :     pfree(values);
    1224          719 :     pfree(isnull);
    1225              : 
    1226              :     /*
    1227              :      * copy the identification info of the old tuple: t_ctid, t_self
    1228              :      */
    1229          719 :     newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
    1230          719 :     newTuple->t_self = tuple->t_self;
    1231          719 :     newTuple->t_tableOid = tuple->t_tableOid;
    1232              : 
    1233          719 :     return newTuple;
    1234              : }
    1235              : 
    1236              : /*
    1237              :  * heap_deform_tuple
    1238              :  *      Given a tuple, extract data into values/isnull arrays; this is
    1239              :  *      the inverse of heap_form_tuple.
    1240              :  *
    1241              :  *      Storage for the values/isnull arrays is provided by the caller;
    1242              :  *      it should be sized according to tupleDesc->natts not
    1243              :  *      HeapTupleHeaderGetNatts(tuple->t_data).
    1244              :  *
    1245              :  *      Note that for pass-by-reference datatypes, the pointer placed
    1246              :  *      in the Datum will point into the given tuple.
    1247              :  *
    1248              :  *      When all or most of a tuple's fields need to be extracted,
    1249              :  *      this routine will be significantly quicker than a loop around
    1250              :  *      heap_getattr; the loop will become O(N^2) as soon as any
    1251              :  *      noncacheable attribute offsets are involved.
    1252              :  */
    1253              : void
    1254      3171120 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
    1255              :                   Datum *values, bool *isnull)
    1256              : {
    1257      3171120 :     HeapTupleHeader tup = tuple->t_data;
    1258              :     CompactAttribute *cattr;
    1259      3171120 :     bool        hasnulls = HeapTupleHasNulls(tuple);
    1260      3171120 :     int         tdesc_natts = tupleDesc->natts;
    1261              :     int         natts;          /* number of atts to extract */
    1262              :     int         attnum;
    1263              :     char       *tp;             /* ptr to tuple data */
    1264              :     uint32      off;            /* offset in tuple data */
    1265      3171120 :     uint8      *bp = tup->t_bits;    /* ptr to null bitmap in tuple */
    1266              :     int         firstNonCacheOffsetAttr;
    1267              :     int         firstNullAttr;
    1268              : 
    1269      3171120 :     natts = HeapTupleHeaderGetNatts(tup);
    1270              : 
    1271              :     /* Did someone forget to call TupleDescFinalize()? */
    1272              :     Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
    1273              : 
    1274              :     /*
    1275              :      * In inheritance situations, it is possible that the given tuple actually
    1276              :      * has more fields than the caller is expecting.  Don't run off the end of
    1277              :      * the caller's arrays.
    1278              :      */
    1279      3171120 :     natts = Min(natts, tdesc_natts);
    1280      3171120 :     firstNonCacheOffsetAttr = Min(tupleDesc->firstNonCachedOffsetAttr, natts);
    1281              : 
    1282      3171120 :     if (hasnulls)
    1283              :     {
    1284       120414 :         firstNullAttr = first_null_attr(bp, natts);
    1285              : 
    1286              :         /*
    1287              :          * XXX: it'd be nice to use populate_isnull_array() here, but that
    1288              :          * requires that the isnull array's size is rounded up to the next
    1289              :          * multiple of 8.  Doing that would require adjusting many locations
    1290              :          * that allocate the array.
    1291              :          */
    1292       120414 :         firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
    1293              :     }
    1294              :     else
    1295      3050706 :         firstNullAttr = natts;
    1296              : 
    1297      3171120 :     tp = (char *) tup + tup->t_hoff;
    1298      3171120 :     attnum = 0;
    1299              : 
    1300      3171120 :     if (firstNonCacheOffsetAttr > 0)
    1301              :     {
    1302              : #ifdef USE_ASSERT_CHECKING
    1303              :         /* In Assert enabled builds, verify attcacheoff is correct */
    1304              :         int         offcheck = 0;
    1305              : #endif
    1306              :         do
    1307              :         {
    1308      4343565 :             isnull[attnum] = false;
    1309      4343565 :             cattr = TupleDescCompactAttr(tupleDesc, attnum);
    1310      4343565 :             off = cattr->attcacheoff;
    1311              : 
    1312              : #ifdef USE_ASSERT_CHECKING
    1313              :             offcheck = att_nominal_alignby(offcheck, cattr->attalignby);
    1314              :             Assert(offcheck == cattr->attcacheoff);
    1315              :             offcheck += cattr->attlen;
    1316              : #endif
    1317              : 
    1318      8687130 :             values[attnum] = fetch_att_noerr(tp + off,
    1319      4343565 :                                              cattr->attbyval,
    1320      4343565 :                                              cattr->attlen);
    1321      4343565 :         } while (++attnum < firstNonCacheOffsetAttr);
    1322      2576248 :         off += cattr->attlen;
    1323              :     }
    1324              :     else
    1325       594872 :         off = 0;
    1326              : 
    1327      4881932 :     for (; attnum < firstNullAttr; attnum++)
    1328              :     {
    1329      1710812 :         isnull[attnum] = false;
    1330      1710812 :         cattr = TupleDescCompactAttr(tupleDesc, attnum);
    1331      1710812 :         values[attnum] = align_fetch_then_add(tp,
    1332              :                                               &off,
    1333      1710812 :                                               cattr->attbyval,
    1334      1710812 :                                               cattr->attlen,
    1335      1710812 :                                               cattr->attalignby);
    1336              :     }
    1337              : 
    1338      3700037 :     for (; attnum < natts; attnum++)
    1339              :     {
    1340              :         Assert(hasnulls);
    1341              : 
    1342       528917 :         if (att_isnull(attnum, bp))
    1343              :         {
    1344       418302 :             values[attnum] = (Datum) 0;
    1345       418302 :             isnull[attnum] = true;
    1346       418302 :             continue;
    1347              :         }
    1348              : 
    1349       110615 :         isnull[attnum] = false;
    1350       110615 :         cattr = TupleDescCompactAttr(tupleDesc, attnum);
    1351              : 
    1352              :         /* align 'off', fetch the attr's value, and increment off beyond it */
    1353       110615 :         values[attnum] = align_fetch_then_add(tp,
    1354              :                                               &off,
    1355       110615 :                                               cattr->attbyval,
    1356       110615 :                                               cattr->attlen,
    1357       110615 :                                               cattr->attalignby);
    1358              :     }
    1359              : 
    1360              :     /*
    1361              :      * If tuple doesn't have all the atts indicated by tupleDesc, read the
    1362              :      * rest as nulls or missing values as appropriate.
    1363              :      */
    1364      3171132 :     for (; attnum < tdesc_natts; attnum++)
    1365           12 :         values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
    1366      3171120 : }
    1367              : 
    1368              : /*
    1369              :  * heap_freetuple
    1370              :  */
    1371              : void
    1372     15515835 : heap_freetuple(HeapTuple htup)
    1373              : {
    1374     15515835 :     pfree(htup);
    1375     15515835 : }
    1376              : 
    1377              : 
    1378              : /*
    1379              :  * heap_form_minimal_tuple
    1380              :  *      construct a MinimalTuple from the given values[] and isnull[] arrays,
    1381              :  *      which are of the length indicated by tupleDescriptor->natts
    1382              :  *
    1383              :  * This is exactly like heap_form_tuple() except that the result is a
    1384              :  * "minimal" tuple lacking a HeapTupleData header as well as room for system
    1385              :  * columns.
    1386              :  *
    1387              :  * The result is allocated in the current memory context.
    1388              :  */
    1389              : MinimalTuple
    1390     32257885 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
    1391              :                         const Datum *values,
    1392              :                         const bool *isnull,
    1393              :                         Size extra)
    1394              : {
    1395              :     MinimalTuple tuple;         /* return tuple */
    1396              :     char       *mem;
    1397              :     Size        len,
    1398              :                 data_len;
    1399              :     int         hoff;
    1400     32257885 :     bool        hasnull = false;
    1401     32257885 :     int         numberOfAttributes = tupleDescriptor->natts;
    1402              :     int         i;
    1403              : 
    1404              :     Assert(extra == MAXALIGN(extra));
    1405              : 
    1406     32257885 :     if (numberOfAttributes > MaxTupleAttributeNumber)
    1407            0 :         ereport(ERROR,
    1408              :                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1409              :                  errmsg("number of columns (%d) exceeds limit (%d)",
    1410              :                         numberOfAttributes, MaxTupleAttributeNumber)));
    1411              : 
    1412              :     /*
    1413              :      * Check for nulls
    1414              :      */
    1415     93429615 :     for (i = 0; i < numberOfAttributes; i++)
    1416              :     {
    1417     61686203 :         if (isnull[i])
    1418              :         {
    1419       514473 :             hasnull = true;
    1420       514473 :             break;
    1421              :         }
    1422              :     }
    1423              : 
    1424              :     /*
    1425              :      * Determine total space needed
    1426              :      */
    1427     32257885 :     len = SizeofMinimalTupleHeader;
    1428              : 
    1429     32257885 :     if (hasnull)
    1430       514473 :         len += BITMAPLEN(numberOfAttributes);
    1431              : 
    1432     32257885 :     hoff = len = MAXALIGN(len); /* align user data safely */
    1433              : 
    1434     32257885 :     data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
    1435              : 
    1436     32257885 :     len += data_len;
    1437              : 
    1438              :     /*
    1439              :      * Allocate and zero the space needed.
    1440              :      */
    1441     32257885 :     mem = palloc0(len + extra);
    1442     32257885 :     tuple = (MinimalTuple) (mem + extra);
    1443              : 
    1444              :     /*
    1445              :      * And fill in the information.
    1446              :      */
    1447     32257885 :     tuple->t_len = len;
    1448     32257885 :     HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
    1449     32257885 :     tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
    1450              : 
    1451     32257885 :     heap_fill_tuple(tupleDescriptor,
    1452              :                     values,
    1453              :                     isnull,
    1454              :                     (char *) tuple + hoff,
    1455              :                     data_len,
    1456              :                     &tuple->t_infomask,
    1457              :                     (hasnull ? tuple->t_bits : NULL));
    1458              : 
    1459     32257885 :     return tuple;
    1460              : }
    1461              : 
    1462              : /*
    1463              :  * heap_free_minimal_tuple
    1464              :  */
    1465              : void
    1466     22870999 : heap_free_minimal_tuple(MinimalTuple mtup)
    1467              : {
    1468     22870999 :     pfree(mtup);
    1469     22870999 : }
    1470              : 
    1471              : /*
    1472              :  * heap_copy_minimal_tuple
    1473              :  *      copy a MinimalTuple
    1474              :  *
    1475              :  * The result is allocated in the current memory context.
    1476              :  */
    1477              : MinimalTuple
    1478      3248423 : heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
    1479              : {
    1480              :     MinimalTuple result;
    1481              :     char       *mem;
    1482              : 
    1483              :     Assert(extra == MAXALIGN(extra));
    1484      3248423 :     mem = palloc(mtup->t_len + extra);
    1485      3248423 :     memset(mem, 0, extra);
    1486      3248423 :     result = (MinimalTuple) (mem + extra);
    1487      3248423 :     memcpy(result, mtup, mtup->t_len);
    1488      3248423 :     return result;
    1489              : }
    1490              : 
    1491              : /*
    1492              :  * heap_tuple_from_minimal_tuple
    1493              :  *      create a HeapTuple by copying from a MinimalTuple;
    1494              :  *      system columns are filled with zeroes
    1495              :  *
    1496              :  * The result is allocated in the current memory context.
    1497              :  * The HeapTuple struct, tuple header, and tuple data are all allocated
    1498              :  * as a single palloc() block.
    1499              :  */
    1500              : HeapTuple
    1501       491810 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
    1502              : {
    1503              :     HeapTuple   result;
    1504       491810 :     uint32      len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
    1505              : 
    1506       491810 :     result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
    1507       491810 :     result->t_len = len;
    1508       491810 :     ItemPointerSetInvalid(&(result->t_self));
    1509       491810 :     result->t_tableOid = InvalidOid;
    1510       491810 :     result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
    1511       491810 :     memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
    1512       491810 :     memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
    1513       491810 :     return result;
    1514              : }
    1515              : 
    1516              : /*
    1517              :  * minimal_tuple_from_heap_tuple
    1518              :  *      create a MinimalTuple by copying from a HeapTuple
    1519              :  *
    1520              :  * The result is allocated in the current memory context.
    1521              :  */
    1522              : MinimalTuple
    1523      2997332 : minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
    1524              : {
    1525              :     MinimalTuple result;
    1526              :     char       *mem;
    1527              :     uint32      len;
    1528              : 
    1529              :     Assert(extra == MAXALIGN(extra));
    1530              :     Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
    1531      2997332 :     len = htup->t_len - MINIMAL_TUPLE_OFFSET;
    1532      2997332 :     mem = palloc(len + extra);
    1533      2997332 :     memset(mem, 0, extra);
    1534      2997332 :     result = (MinimalTuple) (mem + extra);
    1535      2997332 :     memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
    1536              : 
    1537      2997332 :     result->t_len = len;
    1538      2997332 :     return result;
    1539              : }
    1540              : 
    1541              : /*
    1542              :  * This mainly exists so JIT can inline the definition, but it's also
    1543              :  * sometimes useful in debugging sessions.
    1544              :  */
    1545              : size_t
    1546            0 : varsize_any(void *p)
    1547              : {
    1548            0 :     return VARSIZE_ANY(p);
    1549              : }
        

Generated by: LCOV version 2.0-1