LCOV - code coverage report
Current view: top level - src/backend/access/common - heaptuple.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 69.8 % 659 460
Test Date: 2026-01-26 10:56:24 Functions: 70.4 % 27 19
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 61.0 % 341 208

             Branch data     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                 :           0 : }
     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                 :           0 : }
     124                 :             : 
     125                 :             : static void
     126                 :           0 : init_missing_cache(void)
     127                 :             : {
     128                 :           0 :         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                 :          57 : getmissingattr(TupleDesc tupleDesc,
     152                 :             :                            int attnum, bool *isnull)
     153                 :             : {
     154                 :          57 :         CompactAttribute *att;
     155                 :             : 
     156         [ +  - ]:          57 :         Assert(attnum <= tupleDesc->natts);
     157         [ +  - ]:          57 :         Assert(attnum > 0);
     158                 :             : 
     159                 :          57 :         att = TupleDescCompactAttr(tupleDesc, attnum - 1);
     160                 :             : 
     161         [ +  + ]:          57 :         if (att->atthasmissing)
     162                 :             :         {
     163                 :           9 :                 AttrMissing *attrmiss;
     164                 :             : 
     165         [ +  - ]:           9 :                 Assert(tupleDesc->constr);
     166         [ +  - ]:           9 :                 Assert(tupleDesc->constr->missing);
     167                 :             : 
     168                 :           9 :                 attrmiss = tupleDesc->constr->missing + (attnum - 1);
     169                 :             : 
     170         [ +  - ]:           9 :                 if (attrmiss->am_present)
     171                 :             :                 {
     172                 :           9 :                         missing_cache_key key;
     173                 :           9 :                         missing_cache_key *entry;
     174                 :           9 :                         bool            found;
     175                 :           9 :                         MemoryContext oldctx;
     176                 :             : 
     177                 :           9 :                         *isnull = false;
     178                 :             : 
     179                 :             :                         /* no  need to cache by-value attributes */
     180         [ +  - ]:           9 :                         if (att->attbyval)
     181                 :           9 :                                 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   [ #  #  #  # ]:           0 :                         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                 :           0 :                         }
     205                 :             : 
     206                 :           0 :                         return entry->value;
     207                 :           9 :                 }
     208         [ +  - ]:           9 :         }
     209                 :             : 
     210                 :          48 :         *isnull = true;
     211                 :          48 :         return PointerGetDatum(NULL);
     212                 :          57 : }
     213                 :             : 
     214                 :             : /*
     215                 :             :  * heap_compute_data_size
     216                 :             :  *              Determine size of the data area of a tuple to be constructed
     217                 :             :  */
     218                 :             : Size
     219                 :    14417874 : heap_compute_data_size(TupleDesc tupleDesc,
     220                 :             :                                            const Datum *values,
     221                 :             :                                            const bool *isnull)
     222                 :             : {
     223                 :    14417874 :         Size            data_length = 0;
     224                 :    14417874 :         int                     i;
     225                 :    14417874 :         int                     numberOfAttributes = tupleDesc->natts;
     226                 :             : 
     227         [ +  + ]:    43103757 :         for (i = 0; i < numberOfAttributes; i++)
     228                 :             :         {
     229                 :    28685883 :                 Datum           val;
     230                 :    28685883 :                 CompactAttribute *atti;
     231                 :             : 
     232         [ +  + ]:    28685883 :                 if (isnull[i])
     233                 :     1013824 :                         continue;
     234                 :             : 
     235                 :    27672059 :                 val = values[i];
     236                 :    27672059 :                 atti = TupleDescCompactAttr(tupleDesc, i);
     237                 :             : 
     238   [ +  +  +  +  :    27672059 :                 if (COMPACT_ATTR_IS_PACKABLE(atti) &&
                   +  + ]
     239                 :     2903069 :                         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                 :     1941292 :                         data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val));
     246                 :     1941292 :                 }
     247   [ +  +  +  + ]:    25730767 :                 else if (atti->attlen == -1 &&
     248                 :     1074179 :                                  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                 :         462 :                         data_length = att_nominal_alignby(data_length, atti->attalignby);
     255                 :         462 :                         data_length += EOH_get_flat_size(DatumGetEOHP(val));
     256                 :         462 :                 }
     257                 :             :                 else
     258                 :             :                 {
     259   [ +  +  +  + ]:    25730305 :                         data_length = att_datum_alignby(data_length, atti->attalignby,
     260                 :             :                                                                                         atti->attlen, val);
     261   [ +  +  +  +  :    25730305 :                         data_length = att_addlength_datum(data_length, atti->attlen,
                   +  - ]
     262                 :             :                                                                                           val);
     263                 :             :                 }
     264      [ -  +  + ]:    28685883 :         }
     265                 :             : 
     266                 :    28835748 :         return data_length;
     267                 :    14417874 : }
     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                 :    25328381 : fill_val(CompactAttribute *att,
     276                 :             :                  bits8 **bit,
     277                 :             :                  int *bitmask,
     278                 :             :                  char **dataP,
     279                 :             :                  uint16 *infomask,
     280                 :             :                  Datum datum,
     281                 :             :                  bool isnull)
     282                 :             : {
     283                 :    25328381 :         Size            data_length;
     284                 :    25328381 :         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         [ +  + ]:    25328381 :         if (bit != NULL)
     291                 :             :         {
     292         [ +  + ]:     4090525 :                 if (*bitmask != HIGHBIT)
     293                 :     3458887 :                         *bitmask <<= 1;
     294                 :             :                 else
     295                 :             :                 {
     296                 :      631638 :                         *bit += 1;
     297                 :      631638 :                         **bit = 0x0;
     298                 :      631638 :                         *bitmask = 1;
     299                 :             :                 }
     300                 :             : 
     301         [ +  + ]:     4090525 :                 if (isnull)
     302                 :             :                 {
     303                 :     1009101 :                         *infomask |= HEAP_HASNULL;
     304                 :     1009101 :                         return;
     305                 :             :                 }
     306                 :             : 
     307                 :     3081424 :                 **bit |= *bitmask;
     308                 :     3081424 :         }
     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         [ +  + ]:    24319280 :         if (att->attbyval)
     315                 :             :         {
     316                 :             :                 /* pass-by-value */
     317                 :    18054175 :                 data = (char *) att_nominal_alignby(data, att->attalignby);
     318                 :    18054175 :                 store_att_byval(data, datum, att->attlen);
     319                 :    18054175 :                 data_length = att->attlen;
     320                 :    18054175 :         }
     321         [ +  + ]:     6265105 :         else if (att->attlen == -1)
     322                 :             :         {
     323                 :             :                 /* varlena */
     324                 :     2815023 :                 Pointer         val = DatumGetPointer(datum);
     325                 :             : 
     326                 :     2815023 :                 *infomask |= HEAP_HASVARWIDTH;
     327         [ +  + ]:     2815023 :                 if (VARATT_IS_EXTERNAL(val))
     328                 :             :                 {
     329         [ +  + ]:         921 :                         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                 :         462 :                                 ExpandedObjectHeader *eoh = DatumGetEOHP(datum);
     336                 :             : 
     337                 :         462 :                                 data = (char *) att_nominal_alignby(data, att->attalignby);
     338                 :         462 :                                 data_length = EOH_get_flat_size(eoh);
     339                 :         462 :                                 EOH_flatten_into(eoh, data, data_length);
     340                 :         462 :                         }
     341                 :             :                         else
     342                 :             :                         {
     343                 :         459 :                                 *infomask |= HEAP_HASEXTERNAL;
     344                 :             :                                 /* no alignment, since it's short by definition */
     345                 :         459 :                                 data_length = VARSIZE_EXTERNAL(val);
     346                 :         459 :                                 memcpy(data, val, data_length);
     347                 :             :                         }
     348                 :         921 :                 }
     349         [ +  + ]:     2814102 :                 else if (VARATT_IS_SHORT(val))
     350                 :             :                 {
     351                 :             :                         /* no alignment for short varlenas */
     352                 :      537786 :                         data_length = VARSIZE_SHORT(val);
     353                 :      537786 :                         memcpy(data, val, data_length);
     354                 :      537786 :                 }
     355   [ +  +  +  + ]:     2276316 :                 else if (att->attispackable && VARATT_CAN_MAKE_SHORT(val))
     356                 :             :                 {
     357                 :             :                         /* convert to short varlena -- no alignment */
     358                 :     1792358 :                         data_length = VARATT_CONVERTED_SHORT_SIZE(val);
     359                 :     1792358 :                         SET_VARSIZE_SHORT(data, data_length);
     360                 :     1792358 :                         memcpy(data + 1, VARDATA(val), data_length - 1);
     361                 :     1792358 :                 }
     362                 :             :                 else
     363                 :             :                 {
     364                 :             :                         /* full 4-byte header varlena */
     365                 :      483958 :                         data = (char *) att_nominal_alignby(data, att->attalignby);
     366                 :      483958 :                         data_length = VARSIZE(val);
     367                 :      483958 :                         memcpy(data, val, data_length);
     368                 :             :                 }
     369                 :     2815023 :         }
     370         [ +  + ]:     3450082 :         else if (att->attlen == -2)
     371                 :             :         {
     372                 :             :                 /* cstring ... never needs alignment */
     373                 :      128210 :                 *infomask |= HEAP_HASVARWIDTH;
     374         [ +  - ]:      128210 :                 Assert(att->attalignby == sizeof(char));
     375                 :      128210 :                 data_length = strlen(DatumGetCString(datum)) + 1;
     376                 :      128210 :                 memcpy(data, DatumGetPointer(datum), data_length);
     377                 :      128210 :         }
     378                 :             :         else
     379                 :             :         {
     380                 :             :                 /* fixed-length pass-by-reference */
     381                 :     3321872 :                 data = (char *) att_nominal_alignby(data, att->attalignby);
     382         [ +  - ]:     3321872 :                 Assert(att->attlen > 0);
     383                 :     3321872 :                 data_length = att->attlen;
     384                 :     3321872 :                 memcpy(data, DatumGetPointer(datum), data_length);
     385                 :             :         }
     386                 :             : 
     387                 :    24319280 :         data += data_length;
     388                 :    24319280 :         *dataP = data;
     389         [ -  + ]:    25328381 : }
     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                 :    11168343 : heap_fill_tuple(TupleDesc tupleDesc,
     402                 :             :                                 const Datum *values, const bool *isnull,
     403                 :             :                                 char *data, Size data_size,
     404                 :             :                                 uint16 *infomask, bits8 *bit)
     405                 :             : {
     406                 :    11168343 :         bits8      *bitP;
     407                 :    11168343 :         int                     bitmask;
     408                 :    11168343 :         int                     i;
     409                 :    11168343 :         int                     numberOfAttributes = tupleDesc->natts;
     410                 :             : 
     411                 :             : #ifdef USE_ASSERT_CHECKING
     412                 :    11168343 :         char       *start = data;
     413                 :             : #endif
     414                 :             : 
     415         [ +  + ]:    11168343 :         if (bit != NULL)
     416                 :             :         {
     417                 :      255598 :                 bitP = &bit[-1];
     418                 :      255598 :                 bitmask = HIGHBIT;
     419                 :      255598 :         }
     420                 :             :         else
     421                 :             :         {
     422                 :             :                 /* just to keep compiler quiet */
     423                 :    10912745 :                 bitP = NULL;
     424                 :    10912745 :                 bitmask = 0;
     425                 :             :         }
     426                 :             : 
     427                 :    11168343 :         *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL);
     428                 :             : 
     429         [ +  + ]:    36496724 :         for (i = 0; i < numberOfAttributes; i++)
     430                 :             :         {
     431                 :    25328381 :                 CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, i);
     432                 :             : 
     433                 :    50656762 :                 fill_val(attr,
     434         [ +  + ]:    25328381 :                                  bitP ? &bitP : NULL,
     435                 :             :                                  &bitmask,
     436                 :             :                                  &data,
     437                 :    25328381 :                                  infomask,
     438         [ +  + ]:    25328381 :                                  values ? values[i] : PointerGetDatum(NULL),
     439         [ +  - ]:    25328381 :                                  isnull ? isnull[i] : true);
     440                 :    25328381 :         }
     441                 :             : 
     442         [ +  - ]:    11168343 :         Assert((data - start) == data_size);
     443                 :    11168343 : }
     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                 :      746081 : 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   [ +  +  +  - ]:      746081 :         Assert(!tupleDesc || attnum <= tupleDesc->natts);
     463         [ -  + ]:      746081 :         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         [ +  - ]:      746081 :         if (attnum > 0)
     473                 :             :         {
     474         [ +  + ]:      746081 :                 if (HeapTupleNoNulls(tup))
     475                 :         393 :                         return false;
     476                 :      745688 :                 return att_isnull(attnum - 1, tup->t_data->t_bits);
     477                 :             :         }
     478                 :             : 
     479         [ #  # ]:           0 :         switch (attnum)
     480                 :             :         {
     481                 :             :                 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                 :             :                 default:
     491   [ #  #  #  # ]:           0 :                         elog(ERROR, "invalid attnum: %d", attnum);
     492                 :           0 :         }
     493                 :             : 
     494                 :           0 :         return false;
     495                 :      746081 : }
     496                 :             : 
     497                 :             : /* ----------------
     498                 :             :  *              nocachegetattr
     499                 :             :  *
     500                 :             :  *              This only gets called from fastgetattr(), in cases where we
     501                 :             :  *              can't use a cacheoffset and the value is not null.
     502                 :             :  *
     503                 :             :  *              This caches attribute offsets in the attribute descriptor.
     504                 :             :  *
     505                 :             :  *              An alternative way to speed things up would be to cache offsets
     506                 :             :  *              with the tuple, but that seems more difficult unless you take
     507                 :             :  *              the storage hit of actually putting those offsets into the
     508                 :             :  *              tuple you send to disk.  Yuck.
     509                 :             :  *
     510                 :             :  *              This scheme will be slightly slower than that, but should
     511                 :             :  *              perform well for queries which hit large #'s of tuples.  After
     512                 :             :  *              you cache the offsets once, examining all the other tuples using
     513                 :             :  *              the same attribute descriptor will go much quicker. -cim 5/4/91
     514                 :             :  *
     515                 :             :  *              NOTE: if you need to change this code, see also heap_deform_tuple.
     516                 :             :  *              Also see nocache_index_getattr, which is the same code for index
     517                 :             :  *              tuples.
     518                 :             :  * ----------------
     519                 :             :  */
     520                 :             : Datum
     521                 :     5107391 : nocachegetattr(HeapTuple tup,
     522                 :             :                            int attnum,
     523                 :             :                            TupleDesc tupleDesc)
     524                 :             : {
     525                 :     5107391 :         HeapTupleHeader td = tup->t_data;
     526                 :     5107391 :         char       *tp;                         /* ptr to data part of tuple */
     527                 :     5107391 :         bits8      *bp = td->t_bits; /* ptr to null bitmap in tuple */
     528                 :     5107391 :         bool            slow = false;   /* do we have to walk attrs? */
     529                 :     5107391 :         int                     off;                    /* current offset within data */
     530                 :             : 
     531                 :             :         /* ----------------
     532                 :             :          *       Three cases:
     533                 :             :          *
     534                 :             :          *       1: No nulls and no variable-width attributes.
     535                 :             :          *       2: Has a null or a var-width AFTER att.
     536                 :             :          *       3: Has nulls or var-widths BEFORE att.
     537                 :             :          * ----------------
     538                 :             :          */
     539                 :             : 
     540                 :     5107391 :         attnum--;
     541                 :             : 
     542         [ +  + ]:     5107391 :         if (!HeapTupleNoNulls(tup))
     543                 :             :         {
     544                 :             :                 /*
     545                 :             :                  * there's a null somewhere in the tuple
     546                 :             :                  *
     547                 :             :                  * check to see if any preceding bits are null...
     548                 :             :                  */
     549                 :     4483839 :                 int                     byte = attnum >> 3;
     550                 :     4483839 :                 int                     finalbit = attnum & 0x07;
     551                 :             : 
     552                 :             :                 /* check for nulls "before" final bit of last byte */
     553         [ +  + ]:     4483839 :                 if ((~bp[byte]) & ((1 << finalbit) - 1))
     554                 :      598808 :                         slow = true;
     555                 :             :                 else
     556                 :             :                 {
     557                 :             :                         /* check for nulls in any "earlier" bytes */
     558                 :     3885031 :                         int                     i;
     559                 :             : 
     560         [ +  + ]:     5462670 :                         for (i = 0; i < byte; i++)
     561                 :             :                         {
     562         [ +  + ]:     1674321 :                                 if (bp[i] != 0xFF)
     563                 :             :                                 {
     564                 :       96682 :                                         slow = true;
     565                 :       96682 :                                         break;
     566                 :             :                                 }
     567                 :     1577639 :                         }
     568                 :     3885031 :                 }
     569                 :     4483839 :         }
     570                 :             : 
     571                 :     5107391 :         tp = (char *) td + td->t_hoff;
     572                 :             : 
     573         [ +  + ]:     5107391 :         if (!slow)
     574                 :             :         {
     575                 :     4411901 :                 CompactAttribute *att;
     576                 :             : 
     577                 :             :                 /*
     578                 :             :                  * If we get here, there are no nulls up to and including the target
     579                 :             :                  * attribute.  If we have a cached offset, we can use it.
     580                 :             :                  */
     581                 :     4411901 :                 att = TupleDescCompactAttr(tupleDesc, attnum);
     582         [ +  + ]:     4411901 :                 if (att->attcacheoff >= 0)
     583                 :     3651031 :                         return fetchatt(att, tp + att->attcacheoff);
     584                 :             : 
     585                 :             :                 /*
     586                 :             :                  * Otherwise, check for non-fixed-length attrs up to and including
     587                 :             :                  * target.  If there aren't any, it's safe to cheaply initialize the
     588                 :             :                  * cached offsets for these attrs.
     589                 :             :                  */
     590         [ +  + ]:      760870 :                 if (HeapTupleHasVarWidth(tup))
     591                 :             :                 {
     592                 :      746552 :                         int                     j;
     593                 :             : 
     594         [ +  + ]:     2924374 :                         for (j = 0; j <= attnum; j++)
     595                 :             :                         {
     596         [ +  + ]:     2917274 :                                 if (TupleDescCompactAttr(tupleDesc, j)->attlen <= 0)
     597                 :             :                                 {
     598                 :      739452 :                                         slow = true;
     599                 :      739452 :                                         break;
     600                 :             :                                 }
     601                 :     2177822 :                         }
     602                 :      746552 :                 }
     603         [ +  + ]:     4411901 :         }
     604                 :             : 
     605         [ +  + ]:     1456360 :         if (!slow)
     606                 :             :         {
     607                 :       21418 :                 int                     natts = tupleDesc->natts;
     608                 :       21418 :                 int                     j = 1;
     609                 :             : 
     610                 :             :                 /*
     611                 :             :                  * If we get here, we have a tuple with no nulls or var-widths up to
     612                 :             :                  * and including the target attribute, so we can use the cached offset
     613                 :             :                  * ... only we don't have it yet, or we'd not have got here.  Since
     614                 :             :                  * it's cheap to compute offsets for fixed-width columns, we take the
     615                 :             :                  * opportunity to initialize the cached offsets for *all* the leading
     616                 :             :                  * fixed-width columns, in hope of avoiding future visits to this
     617                 :             :                  * routine.
     618                 :             :                  */
     619                 :       21418 :                 TupleDescCompactAttr(tupleDesc, 0)->attcacheoff = 0;
     620                 :             : 
     621                 :             :                 /* we might have set some offsets in the slow path previously */
     622   [ +  +  +  + ]:       21643 :                 while (j < natts && TupleDescCompactAttr(tupleDesc, j)->attcacheoff > 0)
     623                 :         225 :                         j++;
     624                 :             : 
     625                 :       42836 :                 off = TupleDescCompactAttr(tupleDesc, j - 1)->attcacheoff +
     626                 :       21418 :                         TupleDescCompactAttr(tupleDesc, j - 1)->attlen;
     627                 :             : 
     628         [ +  + ]:      222558 :                 for (; j < natts; j++)
     629                 :             :                 {
     630                 :      213547 :                         CompactAttribute *att = TupleDescCompactAttr(tupleDesc, j);
     631                 :             : 
     632         [ +  + ]:      213547 :                         if (att->attlen <= 0)
     633                 :       12407 :                                 break;
     634                 :             : 
     635                 :      201140 :                         off = att_nominal_alignby(off, att->attalignby);
     636                 :             : 
     637                 :      201140 :                         att->attcacheoff = off;
     638                 :             : 
     639                 :      201140 :                         off += att->attlen;
     640         [ +  + ]:      213547 :                 }
     641                 :             : 
     642         [ +  - ]:       21418 :                 Assert(j > attnum);
     643                 :             : 
     644                 :       21418 :                 off = TupleDescCompactAttr(tupleDesc, attnum)->attcacheoff;
     645                 :       21418 :         }
     646                 :             :         else
     647                 :             :         {
     648                 :     1434942 :                 bool            usecache = true;
     649                 :     1434942 :                 int                     i;
     650                 :             : 
     651                 :             :                 /*
     652                 :             :                  * Now we know that we have to walk the tuple CAREFULLY.  But we still
     653                 :             :                  * might be able to cache some offsets for next time.
     654                 :             :                  *
     655                 :             :                  * Note - This loop is a little tricky.  For each non-null attribute,
     656                 :             :                  * we have to first account for alignment padding before the attr,
     657                 :             :                  * then advance over the attr based on its length.  Nulls have no
     658                 :             :                  * storage and no alignment padding either.  We can use/set
     659                 :             :                  * attcacheoff until we reach either a null or a var-width attribute.
     660                 :             :                  */
     661                 :     1434942 :                 off = 0;
     662                 :    11332977 :                 for (i = 0;; i++)               /* loop exit is at "break" */
     663                 :             :                 {
     664                 :    11332977 :                         CompactAttribute *att = TupleDescCompactAttr(tupleDesc, i);
     665                 :             : 
     666   [ +  +  +  + ]:    11332977 :                         if (HeapTupleHasNulls(tup) && att_isnull(i, bp))
     667                 :             :                         {
     668                 :     1880416 :                                 usecache = false;
     669                 :     1880416 :                                 continue;               /* this cannot be the target att */
     670                 :             :                         }
     671                 :             : 
     672                 :             :                         /* If we know the next offset, we can skip the rest */
     673   [ +  +  +  + ]:     9452561 :                         if (usecache && att->attcacheoff >= 0)
     674                 :     6399350 :                                 off = att->attcacheoff;
     675         [ +  + ]:     3053211 :                         else if (att->attlen == -1)
     676                 :             :                         {
     677                 :             :                                 /*
     678                 :             :                                  * We can only cache the offset for a varlena attribute if the
     679                 :             :                                  * offset is already suitably aligned, so that there would be
     680                 :             :                                  * no pad bytes in any case: then the offset will be valid for
     681                 :             :                                  * either an aligned or unaligned value.
     682                 :             :                                  */
     683   [ +  +  +  + ]:     1655877 :                                 if (usecache &&
     684                 :       87530 :                                         off == att_nominal_alignby(off, att->attalignby))
     685                 :        4859 :                                         att->attcacheoff = off;
     686                 :             :                                 else
     687                 :             :                                 {
     688         [ +  + ]:     1651018 :                                         off = att_pointer_alignby(off, att->attalignby, -1,
     689                 :             :                                                                                           tp + off);
     690                 :     1651018 :                                         usecache = false;
     691                 :             :                                 }
     692                 :     1655877 :                         }
     693                 :             :                         else
     694                 :             :                         {
     695                 :             :                                 /* not varlena, so safe to use att_nominal_alignby */
     696                 :     1397334 :                                 off = att_nominal_alignby(off, att->attalignby);
     697                 :             : 
     698         [ +  + ]:     1397334 :                                 if (usecache)
     699                 :       25865 :                                         att->attcacheoff = off;
     700                 :             :                         }
     701                 :             : 
     702         [ +  + ]:     9452561 :                         if (i == attnum)
     703                 :     1434942 :                                 break;
     704                 :             : 
     705   [ +  +  -  +  :     8017619 :                         off = att_addlength_pointer(off, att->attlen, tp + off);
                   #  # ]
     706                 :             : 
     707   [ +  +  +  + ]:     8017619 :                         if (usecache && att->attlen <= 0)
     708                 :     1110862 :                                 usecache = false;
     709      [ +  +  + ]:    11332977 :                 }
     710                 :     1434942 :         }
     711                 :             : 
     712                 :     1456360 :         return fetchatt(TupleDescCompactAttr(tupleDesc, attnum), tp + off);
     713                 :     5107391 : }
     714                 :             : 
     715                 :             : /* ----------------
     716                 :             :  *              heap_getsysattr
     717                 :             :  *
     718                 :             :  *              Fetch the value of a system attribute for a tuple.
     719                 :             :  *
     720                 :             :  * This is a support routine for heap_getattr().  The function has already
     721                 :             :  * determined that the attnum refers to a system attribute.
     722                 :             :  * ----------------
     723                 :             :  */
     724                 :             : Datum
     725                 :          52 : heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
     726                 :             : {
     727                 :          52 :         Datum           result;
     728                 :             : 
     729         [ +  - ]:          52 :         Assert(tup);
     730                 :             : 
     731                 :             :         /* Currently, no sys attribute ever reads as NULL. */
     732                 :          52 :         *isnull = false;
     733                 :             : 
     734   [ -  +  +  +  :          52 :         switch (attnum)
                   -  - ]
     735                 :             :         {
     736                 :             :                 case SelfItemPointerAttributeNumber:
     737                 :             :                         /* pass-by-reference datatype */
     738                 :           0 :                         result = PointerGetDatum(&(tup->t_self));
     739                 :           0 :                         break;
     740                 :             :                 case MinTransactionIdAttributeNumber:
     741                 :          17 :                         result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmin(tup->t_data));
     742                 :          17 :                         break;
     743                 :             :                 case MaxTransactionIdAttributeNumber:
     744                 :           4 :                         result = TransactionIdGetDatum(HeapTupleHeaderGetRawXmax(tup->t_data));
     745                 :           4 :                         break;
     746                 :             :                 case MinCommandIdAttributeNumber:
     747                 :             :                 case MaxCommandIdAttributeNumber:
     748                 :             : 
     749                 :             :                         /*
     750                 :             :                          * cmin and cmax are now both aliases for the same field, which
     751                 :             :                          * can in fact also be a combo command id.  XXX perhaps we should
     752                 :             :                          * return the "real" cmin or cmax if possible, that is if we are
     753                 :             :                          * inside the originating transaction?
     754                 :             :                          */
     755                 :          31 :                         result = CommandIdGetDatum(HeapTupleHeaderGetRawCommandId(tup->t_data));
     756                 :          31 :                         break;
     757                 :             :                 case TableOidAttributeNumber:
     758                 :           0 :                         result = ObjectIdGetDatum(tup->t_tableOid);
     759                 :           0 :                         break;
     760                 :             :                 default:
     761   [ #  #  #  # ]:           0 :                         elog(ERROR, "invalid attnum: %d", attnum);
     762                 :           0 :                         result = 0;                     /* keep compiler quiet */
     763                 :           0 :                         break;
     764                 :             :         }
     765                 :         104 :         return result;
     766                 :          52 : }
     767                 :             : 
     768                 :             : /* ----------------
     769                 :             :  *              heap_copytuple
     770                 :             :  *
     771                 :             :  *              returns a copy of an entire tuple
     772                 :             :  *
     773                 :             :  * The HeapTuple struct, tuple header, and tuple data are all allocated
     774                 :             :  * as a single palloc() block.
     775                 :             :  * ----------------
     776                 :             :  */
     777                 :             : HeapTuple
     778                 :     1545931 : heap_copytuple(HeapTuple tuple)
     779                 :             : {
     780                 :     1545931 :         HeapTuple       newTuple;
     781                 :             : 
     782   [ +  -  -  + ]:     1545931 :         if (!HeapTupleIsValid(tuple) || tuple->t_data == NULL)
     783                 :           0 :                 return NULL;
     784                 :             : 
     785                 :     1545931 :         newTuple = (HeapTuple) palloc(HEAPTUPLESIZE + tuple->t_len);
     786                 :     1545931 :         newTuple->t_len = tuple->t_len;
     787                 :     1545931 :         newTuple->t_self = tuple->t_self;
     788                 :     1545931 :         newTuple->t_tableOid = tuple->t_tableOid;
     789                 :     1545931 :         newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
     790                 :     1545931 :         memcpy(newTuple->t_data, tuple->t_data, tuple->t_len);
     791                 :     1545931 :         return newTuple;
     792                 :     1545931 : }
     793                 :             : 
     794                 :             : /* ----------------
     795                 :             :  *              heap_copytuple_with_tuple
     796                 :             :  *
     797                 :             :  *              copy a tuple into a caller-supplied HeapTuple management struct
     798                 :             :  *
     799                 :             :  * Note that after calling this function, the "dest" HeapTuple will not be
     800                 :             :  * allocated as a single palloc() block (unlike with heap_copytuple()).
     801                 :             :  * ----------------
     802                 :             :  */
     803                 :             : void
     804                 :           0 : heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest)
     805                 :             : {
     806   [ #  #  #  # ]:           0 :         if (!HeapTupleIsValid(src) || src->t_data == NULL)
     807                 :             :         {
     808                 :           0 :                 dest->t_data = NULL;
     809                 :           0 :                 return;
     810                 :             :         }
     811                 :             : 
     812                 :           0 :         dest->t_len = src->t_len;
     813                 :           0 :         dest->t_self = src->t_self;
     814                 :           0 :         dest->t_tableOid = src->t_tableOid;
     815                 :           0 :         dest->t_data = (HeapTupleHeader) palloc(src->t_len);
     816                 :           0 :         memcpy(dest->t_data, src->t_data, src->t_len);
     817                 :           0 : }
     818                 :             : 
     819                 :             : /*
     820                 :             :  * Expand a tuple which has fewer attributes than required. For each attribute
     821                 :             :  * not present in the sourceTuple, if there is a missing value that will be
     822                 :             :  * used. Otherwise the attribute will be set to NULL.
     823                 :             :  *
     824                 :             :  * The source tuple must have fewer attributes than the required number.
     825                 :             :  *
     826                 :             :  * Only one of targetHeapTuple and targetMinimalTuple may be supplied. The
     827                 :             :  * other argument must be NULL.
     828                 :             :  */
     829                 :             : static void
     830                 :           0 : expand_tuple(HeapTuple *targetHeapTuple,
     831                 :             :                          MinimalTuple *targetMinimalTuple,
     832                 :             :                          HeapTuple sourceTuple,
     833                 :             :                          TupleDesc tupleDesc)
     834                 :             : {
     835                 :           0 :         AttrMissing *attrmiss = NULL;
     836                 :           0 :         int                     attnum;
     837                 :           0 :         int                     firstmissingnum;
     838                 :           0 :         bool            hasNulls = HeapTupleHasNulls(sourceTuple);
     839                 :           0 :         HeapTupleHeader targetTHeader;
     840                 :           0 :         HeapTupleHeader sourceTHeader = sourceTuple->t_data;
     841                 :           0 :         int                     sourceNatts = HeapTupleHeaderGetNatts(sourceTHeader);
     842                 :           0 :         int                     natts = tupleDesc->natts;
     843                 :           0 :         int                     sourceNullLen;
     844                 :           0 :         int                     targetNullLen;
     845                 :           0 :         Size            sourceDataLen = sourceTuple->t_len - sourceTHeader->t_hoff;
     846                 :           0 :         Size            targetDataLen;
     847                 :           0 :         Size            len;
     848                 :           0 :         int                     hoff;
     849                 :           0 :         bits8      *nullBits = NULL;
     850                 :           0 :         int                     bitMask = 0;
     851                 :           0 :         char       *targetData;
     852                 :           0 :         uint16     *infoMask;
     853                 :             : 
     854   [ #  #  #  #  :           0 :         Assert((targetHeapTuple && !targetMinimalTuple)
                   #  # ]
     855                 :             :                    || (!targetHeapTuple && targetMinimalTuple));
     856                 :             : 
     857         [ #  # ]:           0 :         Assert(sourceNatts < natts);
     858                 :             : 
     859         [ #  # ]:           0 :         sourceNullLen = (hasNulls ? BITMAPLEN(sourceNatts) : 0);
     860                 :             : 
     861                 :           0 :         targetDataLen = sourceDataLen;
     862                 :             : 
     863   [ #  #  #  # ]:           0 :         if (tupleDesc->constr &&
     864                 :           0 :                 tupleDesc->constr->missing)
     865                 :             :         {
     866                 :             :                 /*
     867                 :             :                  * If there are missing values we want to put them into the tuple.
     868                 :             :                  * Before that we have to compute the extra length for the values
     869                 :             :                  * array and the variable length data.
     870                 :             :                  */
     871                 :           0 :                 attrmiss = tupleDesc->constr->missing;
     872                 :             : 
     873                 :             :                 /*
     874                 :             :                  * Find the first item in attrmiss for which we don't have a value in
     875                 :             :                  * the source. We can ignore all the missing entries before that.
     876                 :             :                  */
     877         [ #  # ]:           0 :                 for (firstmissingnum = sourceNatts;
     878                 :           0 :                          firstmissingnum < natts;
     879                 :           0 :                          firstmissingnum++)
     880                 :             :                 {
     881         [ #  # ]:           0 :                         if (attrmiss[firstmissingnum].am_present)
     882                 :           0 :                                 break;
     883                 :             :                         else
     884                 :           0 :                                 hasNulls = true;
     885                 :           0 :                 }
     886                 :             : 
     887                 :             :                 /*
     888                 :             :                  * Now walk the missing attributes. If there is a missing value make
     889                 :             :                  * space for it. Otherwise, it's going to be NULL.
     890                 :             :                  */
     891         [ #  # ]:           0 :                 for (attnum = firstmissingnum;
     892                 :           0 :                          attnum < natts;
     893                 :           0 :                          attnum++)
     894                 :             :                 {
     895         [ #  # ]:           0 :                         if (attrmiss[attnum].am_present)
     896                 :             :                         {
     897                 :           0 :                                 CompactAttribute *att = TupleDescCompactAttr(tupleDesc, attnum);
     898                 :             : 
     899   [ #  #  #  # ]:           0 :                                 targetDataLen = att_datum_alignby(targetDataLen,
     900                 :             :                                                                                                   att->attalignby,
     901                 :             :                                                                                                   att->attlen,
     902                 :             :                                                                                                   attrmiss[attnum].am_value);
     903                 :             : 
     904   [ #  #  #  #  :           0 :                                 targetDataLen = att_addlength_datum(targetDataLen,
                   #  # ]
     905                 :             :                                                                                                         att->attlen,
     906                 :             :                                                                                                         attrmiss[attnum].am_value);
     907                 :           0 :                         }
     908                 :             :                         else
     909                 :             :                         {
     910                 :             :                                 /* no missing value, so it must be null */
     911                 :           0 :                                 hasNulls = true;
     912                 :             :                         }
     913                 :           0 :                 }
     914                 :           0 :         }                                                       /* end if have missing values */
     915                 :             :         else
     916                 :             :         {
     917                 :             :                 /*
     918                 :             :                  * If there are no missing values at all then NULLS must be allowed,
     919                 :             :                  * since some of the attributes are known to be absent.
     920                 :             :                  */
     921                 :           0 :                 hasNulls = true;
     922                 :             :         }
     923                 :             : 
     924                 :           0 :         len = 0;
     925                 :             : 
     926         [ #  # ]:           0 :         if (hasNulls)
     927                 :             :         {
     928                 :           0 :                 targetNullLen = BITMAPLEN(natts);
     929                 :           0 :                 len += targetNullLen;
     930                 :           0 :         }
     931                 :             :         else
     932                 :           0 :                 targetNullLen = 0;
     933                 :             : 
     934                 :             :         /*
     935                 :             :          * Allocate and zero the space needed.  Note that the tuple body and
     936                 :             :          * HeapTupleData management structure are allocated in one chunk.
     937                 :             :          */
     938         [ #  # ]:           0 :         if (targetHeapTuple)
     939                 :             :         {
     940                 :           0 :                 len += offsetof(HeapTupleHeaderData, t_bits);
     941                 :           0 :                 hoff = len = MAXALIGN(len); /* align user data safely */
     942                 :           0 :                 len += targetDataLen;
     943                 :             : 
     944                 :           0 :                 *targetHeapTuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
     945                 :           0 :                 (*targetHeapTuple)->t_data
     946                 :           0 :                         = targetTHeader
     947                 :           0 :                         = (HeapTupleHeader) ((char *) *targetHeapTuple + HEAPTUPLESIZE);
     948                 :           0 :                 (*targetHeapTuple)->t_len = len;
     949                 :           0 :                 (*targetHeapTuple)->t_tableOid = sourceTuple->t_tableOid;
     950                 :           0 :                 (*targetHeapTuple)->t_self = sourceTuple->t_self;
     951                 :             : 
     952                 :           0 :                 targetTHeader->t_infomask = sourceTHeader->t_infomask;
     953                 :           0 :                 targetTHeader->t_hoff = hoff;
     954                 :           0 :                 HeapTupleHeaderSetNatts(targetTHeader, natts);
     955                 :           0 :                 HeapTupleHeaderSetDatumLength(targetTHeader, len);
     956                 :           0 :                 HeapTupleHeaderSetTypeId(targetTHeader, tupleDesc->tdtypeid);
     957                 :           0 :                 HeapTupleHeaderSetTypMod(targetTHeader, tupleDesc->tdtypmod);
     958                 :             :                 /* We also make sure that t_ctid is invalid unless explicitly set */
     959                 :           0 :                 ItemPointerSetInvalid(&(targetTHeader->t_ctid));
     960         [ #  # ]:           0 :                 if (targetNullLen > 0)
     961                 :           0 :                         nullBits = (bits8 *) ((char *) (*targetHeapTuple)->t_data
     962                 :           0 :                                                                   + offsetof(HeapTupleHeaderData, t_bits));
     963                 :           0 :                 targetData = (char *) (*targetHeapTuple)->t_data + hoff;
     964                 :           0 :                 infoMask = &(targetTHeader->t_infomask);
     965                 :           0 :         }
     966                 :             :         else
     967                 :             :         {
     968                 :           0 :                 len += SizeofMinimalTupleHeader;
     969                 :           0 :                 hoff = len = MAXALIGN(len); /* align user data safely */
     970                 :           0 :                 len += targetDataLen;
     971                 :             : 
     972                 :           0 :                 *targetMinimalTuple = (MinimalTuple) palloc0(len);
     973                 :           0 :                 (*targetMinimalTuple)->t_len = len;
     974                 :           0 :                 (*targetMinimalTuple)->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
     975                 :           0 :                 (*targetMinimalTuple)->t_infomask = sourceTHeader->t_infomask;
     976                 :             :                 /* Same macro works for MinimalTuples */
     977                 :           0 :                 HeapTupleHeaderSetNatts(*targetMinimalTuple, natts);
     978         [ #  # ]:           0 :                 if (targetNullLen > 0)
     979                 :           0 :                         nullBits = (bits8 *) ((char *) *targetMinimalTuple
     980                 :           0 :                                                                   + offsetof(MinimalTupleData, t_bits));
     981                 :           0 :                 targetData = (char *) *targetMinimalTuple + hoff;
     982                 :           0 :                 infoMask = &((*targetMinimalTuple)->t_infomask);
     983                 :             :         }
     984                 :             : 
     985         [ #  # ]:           0 :         if (targetNullLen > 0)
     986                 :             :         {
     987         [ #  # ]:           0 :                 if (sourceNullLen > 0)
     988                 :             :                 {
     989                 :             :                         /* if bitmap pre-existed copy in - all is set */
     990                 :           0 :                         memcpy(nullBits,
     991                 :             :                                    ((char *) sourceTHeader)
     992                 :             :                                    + offsetof(HeapTupleHeaderData, t_bits),
     993                 :             :                                    sourceNullLen);
     994                 :           0 :                         nullBits += sourceNullLen - 1;
     995                 :           0 :                 }
     996                 :             :                 else
     997                 :             :                 {
     998                 :           0 :                         sourceNullLen = BITMAPLEN(sourceNatts);
     999                 :             :                         /* Set NOT NULL for all existing attributes */
    1000                 :           0 :                         memset(nullBits, 0xff, sourceNullLen);
    1001                 :             : 
    1002                 :           0 :                         nullBits += sourceNullLen - 1;
    1003                 :             : 
    1004         [ #  # ]:           0 :                         if (sourceNatts & 0x07)
    1005                 :             :                         {
    1006                 :             :                                 /* build the mask (inverted!) */
    1007                 :           0 :                                 bitMask = 0xff << (sourceNatts & 0x07);
    1008                 :             :                                 /* Voila */
    1009                 :           0 :                                 *nullBits = ~bitMask;
    1010                 :           0 :                         }
    1011                 :             :                 }
    1012                 :             : 
    1013                 :           0 :                 bitMask = (1 << ((sourceNatts - 1) & 0x07));
    1014                 :           0 :         }                                                       /* End if have null bitmap */
    1015                 :             : 
    1016                 :           0 :         memcpy(targetData,
    1017                 :             :                    ((char *) sourceTuple->t_data) + sourceTHeader->t_hoff,
    1018                 :             :                    sourceDataLen);
    1019                 :             : 
    1020                 :           0 :         targetData += sourceDataLen;
    1021                 :             : 
    1022                 :             :         /* Now fill in the missing values */
    1023         [ #  # ]:           0 :         for (attnum = sourceNatts; attnum < natts; attnum++)
    1024                 :             :         {
    1025                 :           0 :                 CompactAttribute *attr = TupleDescCompactAttr(tupleDesc, attnum);
    1026                 :             : 
    1027   [ #  #  #  # ]:           0 :                 if (attrmiss && attrmiss[attnum].am_present)
    1028                 :             :                 {
    1029                 :           0 :                         fill_val(attr,
    1030         [ #  # ]:           0 :                                          nullBits ? &nullBits : NULL,
    1031                 :             :                                          &bitMask,
    1032                 :             :                                          &targetData,
    1033                 :           0 :                                          infoMask,
    1034                 :           0 :                                          attrmiss[attnum].am_value,
    1035                 :             :                                          false);
    1036                 :           0 :                 }
    1037                 :             :                 else
    1038                 :             :                 {
    1039                 :           0 :                         fill_val(attr,
    1040                 :             :                                          &nullBits,
    1041                 :             :                                          &bitMask,
    1042                 :             :                                          &targetData,
    1043                 :           0 :                                          infoMask,
    1044                 :             :                                          (Datum) 0,
    1045                 :             :                                          true);
    1046                 :             :                 }
    1047                 :           0 :         }                                                       /* end loop over missing attributes */
    1048                 :           0 : }
    1049                 :             : 
    1050                 :             : /*
    1051                 :             :  * Fill in the missing values for a minimal HeapTuple
    1052                 :             :  */
    1053                 :             : MinimalTuple
    1054                 :           0 : minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
    1055                 :             : {
    1056                 :           0 :         MinimalTuple minimalTuple;
    1057                 :             : 
    1058                 :           0 :         expand_tuple(NULL, &minimalTuple, sourceTuple, tupleDesc);
    1059                 :           0 :         return minimalTuple;
    1060                 :           0 : }
    1061                 :             : 
    1062                 :             : /*
    1063                 :             :  * Fill in the missing values for an ordinary HeapTuple
    1064                 :             :  */
    1065                 :             : HeapTuple
    1066                 :           0 : heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc)
    1067                 :             : {
    1068                 :           0 :         HeapTuple       heapTuple;
    1069                 :             : 
    1070                 :           0 :         expand_tuple(&heapTuple, NULL, sourceTuple, tupleDesc);
    1071                 :           0 :         return heapTuple;
    1072                 :           0 : }
    1073                 :             : 
    1074                 :             : /* ----------------
    1075                 :             :  *              heap_copy_tuple_as_datum
    1076                 :             :  *
    1077                 :             :  *              copy a tuple as a composite-type Datum
    1078                 :             :  * ----------------
    1079                 :             :  */
    1080                 :             : Datum
    1081                 :       12440 : heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
    1082                 :             : {
    1083                 :       12440 :         HeapTupleHeader td;
    1084                 :             : 
    1085                 :             :         /*
    1086                 :             :          * If the tuple contains any external TOAST pointers, we have to inline
    1087                 :             :          * those fields to meet the conventions for composite-type Datums.
    1088                 :             :          */
    1089         [ -  + ]:       12440 :         if (HeapTupleHasExternal(tuple))
    1090                 :           0 :                 return toast_flatten_tuple_to_datum(tuple->t_data,
    1091                 :           0 :                                                                                         tuple->t_len,
    1092                 :           0 :                                                                                         tupleDesc);
    1093                 :             : 
    1094                 :             :         /*
    1095                 :             :          * Fast path for easy case: just make a palloc'd copy and insert the
    1096                 :             :          * correct composite-Datum header fields (since those may not be set if
    1097                 :             :          * the given tuple came from disk, rather than from heap_form_tuple).
    1098                 :             :          */
    1099                 :       12440 :         td = (HeapTupleHeader) palloc(tuple->t_len);
    1100                 :       12440 :         memcpy(td, tuple->t_data, tuple->t_len);
    1101                 :             : 
    1102                 :       12440 :         HeapTupleHeaderSetDatumLength(td, tuple->t_len);
    1103                 :       12440 :         HeapTupleHeaderSetTypeId(td, tupleDesc->tdtypeid);
    1104                 :       12440 :         HeapTupleHeaderSetTypMod(td, tupleDesc->tdtypmod);
    1105                 :             : 
    1106                 :       12440 :         return PointerGetDatum(td);
    1107                 :       12440 : }
    1108                 :             : 
    1109                 :             : /*
    1110                 :             :  * heap_form_tuple
    1111                 :             :  *              construct a tuple from the given values[] and isnull[] arrays,
    1112                 :             :  *              which are of the length indicated by tupleDescriptor->natts
    1113                 :             :  *
    1114                 :             :  * The result is allocated in the current memory context.
    1115                 :             :  */
    1116                 :             : HeapTuple
    1117                 :     2747000 : heap_form_tuple(TupleDesc tupleDescriptor,
    1118                 :             :                                 const Datum *values,
    1119                 :             :                                 const bool *isnull)
    1120                 :             : {
    1121                 :     2747000 :         HeapTuple       tuple;                  /* return tuple */
    1122                 :     2747000 :         HeapTupleHeader td;                     /* tuple data */
    1123                 :     2747000 :         Size            len,
    1124                 :             :                                 data_len;
    1125                 :     2747000 :         int                     hoff;
    1126                 :     2747000 :         bool            hasnull = false;
    1127                 :     2747000 :         int                     numberOfAttributes = tupleDescriptor->natts;
    1128                 :     2747000 :         int                     i;
    1129                 :             : 
    1130         [ +  - ]:     2747000 :         if (numberOfAttributes > MaxTupleAttributeNumber)
    1131   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1132                 :             :                                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1133                 :             :                                  errmsg("number of columns (%d) exceeds limit (%d)",
    1134                 :             :                                                 numberOfAttributes, MaxTupleAttributeNumber)));
    1135                 :             : 
    1136                 :             :         /*
    1137                 :             :          * Check for nulls
    1138                 :             :          */
    1139         [ +  + ]:    11386169 :         for (i = 0; i < numberOfAttributes; i++)
    1140                 :             :         {
    1141         [ +  + ]:     8850334 :                 if (isnull[i])
    1142                 :             :                 {
    1143                 :      211165 :                         hasnull = true;
    1144                 :      211165 :                         break;
    1145                 :             :                 }
    1146                 :     8639169 :         }
    1147                 :             : 
    1148                 :             :         /*
    1149                 :             :          * Determine total space needed
    1150                 :             :          */
    1151                 :     2747000 :         len = offsetof(HeapTupleHeaderData, t_bits);
    1152                 :             : 
    1153         [ +  + ]:     2747000 :         if (hasnull)
    1154                 :      211165 :                 len += BITMAPLEN(numberOfAttributes);
    1155                 :             : 
    1156                 :     2747000 :         hoff = len = MAXALIGN(len); /* align user data safely */
    1157                 :             : 
    1158                 :     2747000 :         data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
    1159                 :             : 
    1160                 :     2747000 :         len += data_len;
    1161                 :             : 
    1162                 :             :         /*
    1163                 :             :          * Allocate and zero the space needed.  Note that the tuple body and
    1164                 :             :          * HeapTupleData management structure are allocated in one chunk.
    1165                 :             :          */
    1166                 :     2747000 :         tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len);
    1167                 :     2747000 :         tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
    1168                 :             : 
    1169                 :             :         /*
    1170                 :             :          * And fill in the information.  Note we fill the Datum fields even though
    1171                 :             :          * this tuple may never become a Datum.  This lets HeapTupleHeaderGetDatum
    1172                 :             :          * identify the tuple type if needed.
    1173                 :             :          */
    1174                 :     2747000 :         tuple->t_len = len;
    1175                 :     2747000 :         ItemPointerSetInvalid(&(tuple->t_self));
    1176                 :     2747000 :         tuple->t_tableOid = InvalidOid;
    1177                 :             : 
    1178                 :     2747000 :         HeapTupleHeaderSetDatumLength(td, len);
    1179                 :     2747000 :         HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid);
    1180                 :     2747000 :         HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod);
    1181                 :             :         /* We also make sure that t_ctid is invalid unless explicitly set */
    1182                 :     2747000 :         ItemPointerSetInvalid(&(td->t_ctid));
    1183                 :             : 
    1184                 :     2747000 :         HeapTupleHeaderSetNatts(td, numberOfAttributes);
    1185                 :     2747000 :         td->t_hoff = hoff;
    1186                 :             : 
    1187                 :     5494000 :         heap_fill_tuple(tupleDescriptor,
    1188                 :     2747000 :                                         values,
    1189                 :     2747000 :                                         isnull,
    1190                 :     2747000 :                                         (char *) td + hoff,
    1191                 :     2747000 :                                         data_len,
    1192                 :     2747000 :                                         &td->t_infomask,
    1193         [ +  + ]:     2747000 :                                         (hasnull ? td->t_bits : NULL));
    1194                 :             : 
    1195                 :     5494000 :         return tuple;
    1196                 :     2747000 : }
    1197                 :             : 
    1198                 :             : /*
    1199                 :             :  * heap_modify_tuple
    1200                 :             :  *              form a new tuple from an old tuple and a set of replacement values.
    1201                 :             :  *
    1202                 :             :  * The replValues, replIsnull, and doReplace arrays must be of the length
    1203                 :             :  * indicated by tupleDesc->natts.  The new tuple is constructed using the data
    1204                 :             :  * from replValues/replIsnull at columns where doReplace is true, and using
    1205                 :             :  * the data from the old tuple at columns where doReplace is false.
    1206                 :             :  *
    1207                 :             :  * The result is allocated in the current memory context.
    1208                 :             :  */
    1209                 :             : HeapTuple
    1210                 :        5121 : heap_modify_tuple(HeapTuple tuple,
    1211                 :             :                                   TupleDesc tupleDesc,
    1212                 :             :                                   const Datum *replValues,
    1213                 :             :                                   const bool *replIsnull,
    1214                 :             :                                   const bool *doReplace)
    1215                 :             : {
    1216                 :        5121 :         int                     numberOfAttributes = tupleDesc->natts;
    1217                 :        5121 :         int                     attoff;
    1218                 :        5121 :         Datum      *values;
    1219                 :        5121 :         bool       *isnull;
    1220                 :        5121 :         HeapTuple       newTuple;
    1221                 :             : 
    1222                 :             :         /*
    1223                 :             :          * allocate and fill values and isnull arrays from either the tuple or the
    1224                 :             :          * repl information, as appropriate.
    1225                 :             :          *
    1226                 :             :          * NOTE: it's debatable whether to use heap_deform_tuple() here or just
    1227                 :             :          * heap_getattr() only the non-replaced columns.  The latter could win if
    1228                 :             :          * there are many replaced columns and few non-replaced ones. However,
    1229                 :             :          * heap_deform_tuple costs only O(N) while the heap_getattr way would cost
    1230                 :             :          * O(N^2) if there are many non-replaced columns, so it seems better to
    1231                 :             :          * err on the side of linear cost.
    1232                 :             :          */
    1233                 :        5121 :         values = palloc_array(Datum, numberOfAttributes);
    1234                 :        5121 :         isnull = palloc_array(bool, numberOfAttributes);
    1235                 :             : 
    1236                 :        5121 :         heap_deform_tuple(tuple, tupleDesc, values, isnull);
    1237                 :             : 
    1238         [ +  + ]:      153006 :         for (attoff = 0; attoff < numberOfAttributes; attoff++)
    1239                 :             :         {
    1240         [ +  + ]:      147885 :                 if (doReplace[attoff])
    1241                 :             :                 {
    1242                 :       34625 :                         values[attoff] = replValues[attoff];
    1243                 :       34625 :                         isnull[attoff] = replIsnull[attoff];
    1244                 :       34625 :                 }
    1245                 :      147885 :         }
    1246                 :             : 
    1247                 :             :         /*
    1248                 :             :          * create a new tuple from the values and isnull arrays
    1249                 :             :          */
    1250                 :        5121 :         newTuple = heap_form_tuple(tupleDesc, values, isnull);
    1251                 :             : 
    1252                 :        5121 :         pfree(values);
    1253                 :        5121 :         pfree(isnull);
    1254                 :             : 
    1255                 :             :         /*
    1256                 :             :          * copy the identification info of the old tuple: t_ctid, t_self
    1257                 :             :          */
    1258                 :        5121 :         newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
    1259                 :        5121 :         newTuple->t_self = tuple->t_self;
    1260                 :        5121 :         newTuple->t_tableOid = tuple->t_tableOid;
    1261                 :             : 
    1262                 :       10242 :         return newTuple;
    1263                 :        5121 : }
    1264                 :             : 
    1265                 :             : /*
    1266                 :             :  * heap_modify_tuple_by_cols
    1267                 :             :  *              form a new tuple from an old tuple and a set of replacement values.
    1268                 :             :  *
    1269                 :             :  * This is like heap_modify_tuple, except that instead of specifying which
    1270                 :             :  * column(s) to replace by a boolean map, an array of target column numbers
    1271                 :             :  * is used.  This is often more convenient when a fixed number of columns
    1272                 :             :  * are to be replaced.  The replCols, replValues, and replIsnull arrays must
    1273                 :             :  * be of length nCols.  Target column numbers are indexed from 1.
    1274                 :             :  *
    1275                 :             :  * The result is allocated in the current memory context.
    1276                 :             :  */
    1277                 :             : HeapTuple
    1278                 :          18 : heap_modify_tuple_by_cols(HeapTuple tuple,
    1279                 :             :                                                   TupleDesc tupleDesc,
    1280                 :             :                                                   int nCols,
    1281                 :             :                                                   const int *replCols,
    1282                 :             :                                                   const Datum *replValues,
    1283                 :             :                                                   const bool *replIsnull)
    1284                 :             : {
    1285                 :          18 :         int                     numberOfAttributes = tupleDesc->natts;
    1286                 :          18 :         Datum      *values;
    1287                 :          18 :         bool       *isnull;
    1288                 :          18 :         HeapTuple       newTuple;
    1289                 :          18 :         int                     i;
    1290                 :             : 
    1291                 :             :         /*
    1292                 :             :          * allocate and fill values and isnull arrays from the tuple, then replace
    1293                 :             :          * selected columns from the input arrays.
    1294                 :             :          */
    1295                 :          18 :         values = palloc_array(Datum, numberOfAttributes);
    1296                 :          18 :         isnull = palloc_array(bool, numberOfAttributes);
    1297                 :             : 
    1298                 :          18 :         heap_deform_tuple(tuple, tupleDesc, values, isnull);
    1299                 :             : 
    1300         [ +  + ]:          52 :         for (i = 0; i < nCols; i++)
    1301                 :             :         {
    1302                 :          34 :                 int                     attnum = replCols[i];
    1303                 :             : 
    1304         [ +  - ]:          34 :                 if (attnum <= 0 || attnum > numberOfAttributes)
    1305   [ #  #  #  # ]:           0 :                         elog(ERROR, "invalid column number %d", attnum);
    1306                 :          34 :                 values[attnum - 1] = replValues[i];
    1307                 :          34 :                 isnull[attnum - 1] = replIsnull[i];
    1308                 :          34 :         }
    1309                 :             : 
    1310                 :             :         /*
    1311                 :             :          * create a new tuple from the values and isnull arrays
    1312                 :             :          */
    1313                 :          18 :         newTuple = heap_form_tuple(tupleDesc, values, isnull);
    1314                 :             : 
    1315                 :          18 :         pfree(values);
    1316                 :          18 :         pfree(isnull);
    1317                 :             : 
    1318                 :             :         /*
    1319                 :             :          * copy the identification info of the old tuple: t_ctid, t_self
    1320                 :             :          */
    1321                 :          18 :         newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
    1322                 :          18 :         newTuple->t_self = tuple->t_self;
    1323                 :          18 :         newTuple->t_tableOid = tuple->t_tableOid;
    1324                 :             : 
    1325                 :          36 :         return newTuple;
    1326                 :          18 : }
    1327                 :             : 
    1328                 :             : /*
    1329                 :             :  * heap_deform_tuple
    1330                 :             :  *              Given a tuple, extract data into values/isnull arrays; this is
    1331                 :             :  *              the inverse of heap_form_tuple.
    1332                 :             :  *
    1333                 :             :  *              Storage for the values/isnull arrays is provided by the caller;
    1334                 :             :  *              it should be sized according to tupleDesc->natts not
    1335                 :             :  *              HeapTupleHeaderGetNatts(tuple->t_data).
    1336                 :             :  *
    1337                 :             :  *              Note that for pass-by-reference datatypes, the pointer placed
    1338                 :             :  *              in the Datum will point into the given tuple.
    1339                 :             :  *
    1340                 :             :  *              When all or most of a tuple's fields need to be extracted,
    1341                 :             :  *              this routine will be significantly quicker than a loop around
    1342                 :             :  *              heap_getattr; the loop will become O(N^2) as soon as any
    1343                 :             :  *              noncacheable attribute offsets are involved.
    1344                 :             :  */
    1345                 :             : void
    1346                 :      853356 : heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
    1347                 :             :                                   Datum *values, bool *isnull)
    1348                 :             : {
    1349                 :      853356 :         HeapTupleHeader tup = tuple->t_data;
    1350                 :      853356 :         bool            hasnulls = HeapTupleHasNulls(tuple);
    1351                 :      853356 :         int                     tdesc_natts = tupleDesc->natts;
    1352                 :      853356 :         int                     natts;                  /* number of atts to extract */
    1353                 :      853356 :         int                     attnum;
    1354                 :      853356 :         char       *tp;                         /* ptr to tuple data */
    1355                 :      853356 :         uint32          off;                    /* offset in tuple data */
    1356                 :      853356 :         bits8      *bp = tup->t_bits;        /* ptr to null bitmap in tuple */
    1357                 :      853356 :         bool            slow = false;   /* can we use/set attcacheoff? */
    1358                 :             : 
    1359                 :      853356 :         natts = HeapTupleHeaderGetNatts(tup);
    1360                 :             : 
    1361                 :             :         /*
    1362                 :             :          * In inheritance situations, it is possible that the given tuple actually
    1363                 :             :          * has more fields than the caller is expecting.  Don't run off the end of
    1364                 :             :          * the caller's arrays.
    1365                 :             :          */
    1366         [ +  + ]:      853356 :         natts = Min(natts, tdesc_natts);
    1367                 :             : 
    1368                 :      853356 :         tp = (char *) tup + tup->t_hoff;
    1369                 :             : 
    1370                 :      853356 :         off = 0;
    1371                 :             : 
    1372         [ +  + ]:     2666122 :         for (attnum = 0; attnum < natts; attnum++)
    1373                 :             :         {
    1374                 :     1812766 :                 CompactAttribute *thisatt = TupleDescCompactAttr(tupleDesc, attnum);
    1375                 :             : 
    1376   [ +  +  +  + ]:     1812766 :                 if (hasnulls && att_isnull(attnum, bp))
    1377                 :             :                 {
    1378                 :       39260 :                         values[attnum] = (Datum) 0;
    1379                 :       39260 :                         isnull[attnum] = true;
    1380                 :       39260 :                         slow = true;            /* can't use attcacheoff anymore */
    1381                 :       39260 :                         continue;
    1382                 :             :                 }
    1383                 :             : 
    1384                 :     1773506 :                 isnull[attnum] = false;
    1385                 :             : 
    1386   [ +  +  +  + ]:     1773506 :                 if (!slow && thisatt->attcacheoff >= 0)
    1387                 :     1697296 :                         off = thisatt->attcacheoff;
    1388         [ +  + ]:       76210 :                 else if (thisatt->attlen == -1)
    1389                 :             :                 {
    1390                 :             :                         /*
    1391                 :             :                          * We can only cache the offset for a varlena attribute if the
    1392                 :             :                          * offset is already suitably aligned, so that there would be no
    1393                 :             :                          * pad bytes in any case: then the offset will be valid for either
    1394                 :             :                          * an aligned or unaligned value.
    1395                 :             :                          */
    1396   [ +  +  +  + ]:       23517 :                         if (!slow &&
    1397                 :        8683 :                                 off == att_nominal_alignby(off, thisatt->attalignby))
    1398                 :        7646 :                                 thisatt->attcacheoff = off;
    1399                 :             :                         else
    1400                 :             :                         {
    1401         [ +  + ]:       15871 :                                 off = att_pointer_alignby(off, thisatt->attalignby, -1,
    1402                 :             :                                                                                   tp + off);
    1403                 :       15871 :                                 slow = true;
    1404                 :             :                         }
    1405                 :       23517 :                 }
    1406                 :             :                 else
    1407                 :             :                 {
    1408                 :             :                         /* not varlena, so safe to use att_nominal_alignby */
    1409                 :       52693 :                         off = att_nominal_alignby(off, thisatt->attalignby);
    1410                 :             : 
    1411         [ +  + ]:       52693 :                         if (!slow)
    1412                 :        8027 :                                 thisatt->attcacheoff = off;
    1413                 :             :                 }
    1414                 :             : 
    1415                 :     1773506 :                 values[attnum] = fetchatt(thisatt, tp + off);
    1416                 :             : 
    1417   [ +  +  +  +  :     1773506 :                 off = att_addlength_pointer(off, thisatt->attlen, tp + off);
                   -  + ]
    1418                 :             : 
    1419         [ +  + ]:     1773506 :                 if (thisatt->attlen <= 0)
    1420                 :      348354 :                         slow = true;            /* can't use attcacheoff anymore */
    1421      [ -  +  + ]:     1812766 :         }
    1422                 :             : 
    1423                 :             :         /*
    1424                 :             :          * If tuple doesn't have all the atts indicated by tupleDesc, read the
    1425                 :             :          * rest as nulls or missing values as appropriate.
    1426                 :             :          */
    1427         [ +  + ]:      853358 :         for (; attnum < tdesc_natts; attnum++)
    1428                 :           2 :                 values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
    1429                 :      853356 : }
    1430                 :             : 
    1431                 :             : /*
    1432                 :             :  * heap_freetuple
    1433                 :             :  */
    1434                 :             : void
    1435                 :     2059329 : heap_freetuple(HeapTuple htup)
    1436                 :             : {
    1437                 :     2059329 :         pfree(htup);
    1438                 :     2059329 : }
    1439                 :             : 
    1440                 :             : 
    1441                 :             : /*
    1442                 :             :  * heap_form_minimal_tuple
    1443                 :             :  *              construct a MinimalTuple from the given values[] and isnull[] arrays,
    1444                 :             :  *              which are of the length indicated by tupleDescriptor->natts
    1445                 :             :  *
    1446                 :             :  * This is exactly like heap_form_tuple() except that the result is a
    1447                 :             :  * "minimal" tuple lacking a HeapTupleData header as well as room for system
    1448                 :             :  * columns.
    1449                 :             :  *
    1450                 :             :  * The result is allocated in the current memory context.
    1451                 :             :  */
    1452                 :             : MinimalTuple
    1453                 :     5542803 : heap_form_minimal_tuple(TupleDesc tupleDescriptor,
    1454                 :             :                                                 const Datum *values,
    1455                 :             :                                                 const bool *isnull,
    1456                 :             :                                                 Size extra)
    1457                 :             : {
    1458                 :     5542803 :         MinimalTuple tuple;                     /* return tuple */
    1459                 :     5542803 :         char       *mem;
    1460                 :     5542803 :         Size            len,
    1461                 :             :                                 data_len;
    1462                 :     5542803 :         int                     hoff;
    1463                 :     5542803 :         bool            hasnull = false;
    1464                 :     5542803 :         int                     numberOfAttributes = tupleDescriptor->natts;
    1465                 :     5542803 :         int                     i;
    1466                 :             : 
    1467         [ +  - ]:     5542803 :         Assert(extra == MAXALIGN(extra));
    1468                 :             : 
    1469         [ +  - ]:     5542803 :         if (numberOfAttributes > MaxTupleAttributeNumber)
    1470   [ #  #  #  # ]:           0 :                 ereport(ERROR,
    1471                 :             :                                 (errcode(ERRCODE_TOO_MANY_COLUMNS),
    1472                 :             :                                  errmsg("number of columns (%d) exceeds limit (%d)",
    1473                 :             :                                                 numberOfAttributes, MaxTupleAttributeNumber)));
    1474                 :             : 
    1475                 :             :         /*
    1476                 :             :          * Check for nulls
    1477                 :             :          */
    1478         [ +  + ]:    16825619 :         for (i = 0; i < numberOfAttributes; i++)
    1479                 :             :         {
    1480         [ +  + ]:    11322805 :                 if (isnull[i])
    1481                 :             :                 {
    1482                 :       39989 :                         hasnull = true;
    1483                 :       39989 :                         break;
    1484                 :             :                 }
    1485                 :    11282816 :         }
    1486                 :             : 
    1487                 :             :         /*
    1488                 :             :          * Determine total space needed
    1489                 :             :          */
    1490                 :     5542803 :         len = SizeofMinimalTupleHeader;
    1491                 :             : 
    1492         [ +  + ]:     5542803 :         if (hasnull)
    1493                 :       39989 :                 len += BITMAPLEN(numberOfAttributes);
    1494                 :             : 
    1495                 :     5542803 :         hoff = len = MAXALIGN(len); /* align user data safely */
    1496                 :             : 
    1497                 :     5542803 :         data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
    1498                 :             : 
    1499                 :     5542803 :         len += data_len;
    1500                 :             : 
    1501                 :             :         /*
    1502                 :             :          * Allocate and zero the space needed.
    1503                 :             :          */
    1504                 :     5542803 :         mem = palloc0(len + extra);
    1505                 :     5542803 :         tuple = (MinimalTuple) (mem + extra);
    1506                 :             : 
    1507                 :             :         /*
    1508                 :             :          * And fill in the information.
    1509                 :             :          */
    1510                 :     5542803 :         tuple->t_len = len;
    1511                 :     5542803 :         HeapTupleHeaderSetNatts(tuple, numberOfAttributes);
    1512                 :     5542803 :         tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET;
    1513                 :             : 
    1514                 :    11085606 :         heap_fill_tuple(tupleDescriptor,
    1515                 :     5542803 :                                         values,
    1516                 :     5542803 :                                         isnull,
    1517                 :     5542803 :                                         (char *) tuple + hoff,
    1518                 :     5542803 :                                         data_len,
    1519                 :     5542803 :                                         &tuple->t_infomask,
    1520         [ +  + ]:     5542803 :                                         (hasnull ? tuple->t_bits : NULL));
    1521                 :             : 
    1522                 :    11085606 :         return tuple;
    1523                 :     5542803 : }
    1524                 :             : 
    1525                 :             : /*
    1526                 :             :  * heap_free_minimal_tuple
    1527                 :             :  */
    1528                 :             : void
    1529                 :     6020538 : heap_free_minimal_tuple(MinimalTuple mtup)
    1530                 :             : {
    1531                 :     6020538 :         pfree(mtup);
    1532                 :     6020538 : }
    1533                 :             : 
    1534                 :             : /*
    1535                 :             :  * heap_copy_minimal_tuple
    1536                 :             :  *              copy a MinimalTuple
    1537                 :             :  *
    1538                 :             :  * The result is allocated in the current memory context.
    1539                 :             :  */
    1540                 :             : MinimalTuple
    1541                 :      728263 : heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
    1542                 :             : {
    1543                 :      728263 :         MinimalTuple result;
    1544                 :      728263 :         char       *mem;
    1545                 :             : 
    1546         [ +  - ]:      728263 :         Assert(extra == MAXALIGN(extra));
    1547                 :      728263 :         mem = palloc(mtup->t_len + extra);
    1548                 :      728263 :         memset(mem, 0, extra);
    1549                 :      728263 :         result = (MinimalTuple) (mem + extra);
    1550                 :      728263 :         memcpy(result, mtup, mtup->t_len);
    1551                 :     1456526 :         return result;
    1552                 :      728263 : }
    1553                 :             : 
    1554                 :             : /*
    1555                 :             :  * heap_tuple_from_minimal_tuple
    1556                 :             :  *              create a HeapTuple by copying from a MinimalTuple;
    1557                 :             :  *              system columns are filled with zeroes
    1558                 :             :  *
    1559                 :             :  * The result is allocated in the current memory context.
    1560                 :             :  * The HeapTuple struct, tuple header, and tuple data are all allocated
    1561                 :             :  * as a single palloc() block.
    1562                 :             :  */
    1563                 :             : HeapTuple
    1564                 :       94681 : heap_tuple_from_minimal_tuple(MinimalTuple mtup)
    1565                 :             : {
    1566                 :       94681 :         HeapTuple       result;
    1567                 :       94681 :         uint32          len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
    1568                 :             : 
    1569                 :       94681 :         result = (HeapTuple) palloc(HEAPTUPLESIZE + len);
    1570                 :       94681 :         result->t_len = len;
    1571                 :       94681 :         ItemPointerSetInvalid(&(result->t_self));
    1572                 :       94681 :         result->t_tableOid = InvalidOid;
    1573                 :       94681 :         result->t_data = (HeapTupleHeader) ((char *) result + HEAPTUPLESIZE);
    1574                 :       94681 :         memcpy((char *) result->t_data + MINIMAL_TUPLE_OFFSET, mtup, mtup->t_len);
    1575                 :       94681 :         memset(result->t_data, 0, offsetof(HeapTupleHeaderData, t_infomask2));
    1576                 :      189362 :         return result;
    1577                 :       94681 : }
    1578                 :             : 
    1579                 :             : /*
    1580                 :             :  * minimal_tuple_from_heap_tuple
    1581                 :             :  *              create a MinimalTuple by copying from a HeapTuple
    1582                 :             :  *
    1583                 :             :  * The result is allocated in the current memory context.
    1584                 :             :  */
    1585                 :             : MinimalTuple
    1586                 :      464158 : minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
    1587                 :             : {
    1588                 :      464158 :         MinimalTuple result;
    1589                 :      464158 :         char       *mem;
    1590                 :      464158 :         uint32          len;
    1591                 :             : 
    1592         [ +  - ]:      464158 :         Assert(extra == MAXALIGN(extra));
    1593         [ +  - ]:      464158 :         Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
    1594                 :      464158 :         len = htup->t_len - MINIMAL_TUPLE_OFFSET;
    1595                 :      464158 :         mem = palloc(len + extra);
    1596                 :      464158 :         memset(mem, 0, extra);
    1597                 :      464158 :         result = (MinimalTuple) (mem + extra);
    1598                 :      464158 :         memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
    1599                 :             : 
    1600                 :      464158 :         result->t_len = len;
    1601                 :      928316 :         return result;
    1602                 :      464158 : }
    1603                 :             : 
    1604                 :             : /*
    1605                 :             :  * This mainly exists so JIT can inline the definition, but it's also
    1606                 :             :  * sometimes useful in debugging sessions.
    1607                 :             :  */
    1608                 :             : size_t
    1609                 :           0 : varsize_any(void *p)
    1610                 :             : {
    1611                 :           0 :         return VARSIZE_ANY(p);
    1612                 :             : }
        

Generated by: LCOV version 2.3.2-1